// SPDX-License-Identifier: LGPL-3.0-or-later import type { InMemoryStore, StoreFS } from '@zenfs/core'; import { InMemory, Port, attachFS, configure, configureSingle, fs, resolveMountConfig, waitOnline } from '@zenfs/core'; import assert from 'node:assert/strict'; import { after, suite, test } from 'node:test'; import { MessageChannel, Worker } from 'node:worker_threads'; import { setupLogs } from '../logs.js'; setupLogs(); // Tests a mis-configured `Port` using a MessageChannel const timeoutChannel = new MessageChannel(); timeoutChannel.port2.unref(); await suite('Timeout', () => { test('Misconfiguration', async () => { const configured = configure({ mounts: { '/tmp-timeout': { backend: InMemory, label: 'tmp' }, '/port': { backend: Port, port: timeoutChannel.port1, timeout: 100 }, }, }); await assert.rejects(configured, { code: 'ETIMEDOUT' }); }); test('Remote not attached', async () => { const configured = configureSingle({ backend: Port, port: timeoutChannel.port1, timeout: 100 }); await assert.rejects(configured, { code: 'ETIMEDOUT' }); }); after(() => { timeoutChannel.port1.unref(); }); }); // Test configuration const configPort = new Worker(import.meta.dirname + '/config.worker.js'); await waitOnline(configPort); suite('Remote FS with resolveRemoteMount', () => { const content = 'FS is in a port'; test('Configuration', async () => { await configureSingle({ backend: Port, port: configPort, timeout: 500 }); }); test('Write', async () => { await fs.promises.writeFile('/test', content); }); test('Read', async () => { assert.equal(await fs.promises.readFile('/test', 'utf8'), content); }); after(async () => { await configPort.terminate(); configPort.unref(); }); }); // Test using a message channel const channel = new MessageChannel(), content = 'FS is in a port'; let tmpfs: StoreFS; await suite('FS with MessageChannel', () => { test('configuration', async () => { tmpfs = await resolveMountConfig({ backend: InMemory, label: 'tmp' }); attachFS(channel.port2, tmpfs); await configureSingle({ backend: Port, port: channel.port1, disableAsyncCache: true, timeout: 500 }); }); test('write', async () => { await fs.promises.writeFile('/test', content); }); test('remote content', () => { fs.mount('/tmp', tmpfs); assert.equal(fs.readFileSync('/tmp/test', 'utf8'), content); fs.umount('/tmp'); }); test('read', async () => { assert.equal(await fs.promises.readFile('/test', 'utf8'), content); }); test('readFileSync should throw', () => { assert.throws(() => fs.readFileSync('/test', 'utf8'), { code: 'ENOTSUP' }); }); after(() => { channel.port1.close(); channel.port2.close(); channel.port1.unref(); channel.port2.unref(); }); }); // Test using a worker const remotePort = new Worker(import.meta.dirname + '/remote.worker.js'); await suite('Remote FS', () => { const content = 'FS is in a port'; test('Configuration', async () => { await configureSingle({ backend: Port, port: remotePort, timeout: 500 }); }); test('Write', async () => { await fs.promises.writeFile('/test', content); }); test('Read', async () => { assert.equal(await fs.promises.readFile('/test', 'utf8'), content); }); after(async () => { await remotePort.terminate(); remotePort.unref(); }); });