UNPKG

@hybrid-compute/remote

Version:

Remote compute backend using fetch or WebSocket transport for distributed task execution.

140 lines 5.26 kB
import test, { describe } from 'node:test'; import assert from 'node:assert/strict'; import { createRemoteCompute, RemoteCompute } from '..'; globalThis.fetch = async (input, init) => { const body = JSON.parse(init?.body ?? '{}'); const isError = body.task === 'fail'; return { ok: !isError, status: isError ? 400 : 200, headers: new Headers(), redirected: false, statusText: isError ? 'Bad Request' : 'OK', type: 'basic', url: String(input), clone: function () { return this; }, body: null, bodyUsed: true, arrayBuffer: async () => new ArrayBuffer(0), blob: async () => new Blob(), formData: async () => new FormData(), text: async () => JSON.stringify(isError ? { error: 'Task failed' } : { result: `Result for ${body.task}` }), json: async () => isError ? { error: 'Task failed' } : { result: `Result for ${body.task}` } }; }; describe('RemoteCompute', () => { test('fetch transport returns result from remote', async () => { const compute = new RemoteCompute({ transport: 'fetch', endpoint: 'https://api.example.com/compute' }); const result = await compute.runTask('echo', { message: 'hi' }); assert.equal(result, 'Result for echo'); }); test('fetch transport throws on error response', async () => { const compute = new RemoteCompute({ transport: 'fetch', endpoint: 'https://api.example.com/compute' }); await assert.rejects(() => compute.runTask('fail', {}), /Task failed/); }); test('canRun returns true if task is allowed', () => { const compute = new RemoteCompute({ transport: 'fetch', endpoint: '/compute', canRunTasks: ['foo', 'bar'] }); assert.equal(compute.canRun('foo'), true); assert.equal(compute.canRun('baz'), false); }); test('canRun returns true if canRunTasks is undefined', () => { const compute = new RemoteCompute({ transport: 'fetch', endpoint: '/compute' }); assert.equal(compute.canRun('anything'), true); }); test('WebSocket transport sends and resolves a message', { timeout: 200 }, async () => { const OriginalWebSocket = globalThis.WebSocket; let sentData = ''; class MockWebSocket { constructor(url) { this.url = url; this.readyState = WebSocket.OPEN; this.onmessage = null; } send(data) { sentData = data; const { id } = JSON.parse(data); const fakeResponse = { id, result: 'websocket-result' }; setTimeout(() => { this.onmessage?.({ data: JSON.stringify(fakeResponse) }); }, 10); } } // @ts-expect-error override native WebSocket globalThis.WebSocket = MockWebSocket; try { const compute = new RemoteCompute({ transport: 'websocket', endpoint: 'wss://example.com/ws' }); // Wait a tick before calling runTask (mimics real socket delay) await new Promise((resolve) => setTimeout(resolve, 0)); const result = await compute.runTask('test', { foo: 1 }); assert.equal(result, 'websocket-result'); } finally { globalThis.WebSocket = OriginalWebSocket; } }); test('WebSocket rejects if not connected', async () => { const OriginalWebSocket = globalThis.WebSocket; class MockWebSocket { constructor(url) { this.url = url; this.readyState = 3; // WebSocket.CLOSED this.onmessage = null; console.log('[MOCK] MockWebSocket constructor called'); } send() { console.log('[MOCK] send() should not be called'); } } // @ts-expect-error override globalThis.WebSocket = MockWebSocket; try { const compute = new RemoteCompute({ transport: 'websocket', endpoint: 'wss://example.com/ws' }); const resultPromise = compute.runTask('any', {}); await assert.rejects(resultPromise, /WebSocket not connected/); } finally { globalThis.WebSocket = OriginalWebSocket; } }); test('runTask() manually rejects for testing', async () => { const compute = { runTask: () => Promise.reject(new Error('WebSocket not connected')) }; await assert.rejects(() => compute.runTask('x', {}), /WebSocket not connected/); }); }); describe('createRemoteCompute', () => { test('returns instance of RemoteCompute', () => { const instance = createRemoteCompute({ transport: 'fetch', endpoint: '/compute' }); assert.ok(instance instanceof RemoteCompute); }); }); //# sourceMappingURL=remote.spec.js.map