MiniCPM5-2B-WebGPU-Pi / test /worker.test.js
Xenova's picture
Xenova HF Staff
Upload 65 files
ea7122c verified
Raw History Blame Contribute Delete
4.55 kB
import assert from 'node:assert/strict';
import { once } from 'node:events';
import { Worker } from 'node:worker_threads';
import test from 'node:test';
test('actual worker module initializes and serves shell/editor/export RPCs without loading a model', { timeout: 10_000 }, async t => {
// Supply only browser worker messaging globals. The app's real module graph,
// real shell, actual runtime imports, and RPC entrypoint execute unchanged.
const url = new URL('../src/agent.worker.js', import.meta.url).href;
const worker = new Worker(`
const { parentPort } = require('node:worker_threads');
globalThis.self = globalThis;
globalThis.postMessage = message => parentPort.postMessage(message);
parentPort.on('message', data => globalThis.onmessage({ data }));
import(${JSON.stringify(url)}).catch(error => { throw error; });
`, { eval: true });
t.after(() => worker.terminate());
const events = [];
worker.on('message', message => events.push(message));
let initialized;
while (!initialized) {
const [event] = await once(worker, 'message');
if (event.type === 'fatal') throw new Error(event.error);
if (event.type === 'initialized') initialized = event;
}
assert.match(initialized.files['/workspace/sales.csv'], /Notebook,12/);
assert.deepEqual(initialized.messages, []);
assert(events.some(event => event.type === 'persistence_error'));
let id = 0;
async function rpc(action, args) {
const requestId = ++id;
worker.postMessage({ id: requestId, action, args });
for (;;) {
const [event] = await once(worker, 'message');
if (event.type === 'reply' && event.id === requestId) {
if (event.error) throw Object.assign(new Error(event.error), { code: event.errorCode });
return event.value;
}
}
}
assert.equal(await rpc('cache_status'), false);
const shell = await rpc('shell', { command: 'printf "verified\\n" > /workspace/worker-check.txt; cat /workspace/worker-check.txt' });
assert.equal(shell.exitCode, 0);
assert.equal(shell.stdout, 'verified\n');
await rpc('write', { path: 'worker-check.txt', content: 'edited' });
assert.equal(await rpc('read', { path: 'worker-check.txt' }), 'edited');
const exported = await rpc('snapshot');
assert.equal(exported.runtime, 'minicpm5-gguf');
assert.equal(exported.files['/workspace/worker-check.txt'], 'edited');
assert(exported.entries.some(([path]) => path === '/workspace/worker-check.txt'));
const fresh = await rpc('new_chat');
assert.deepEqual(fresh.messages, []);
assert.equal(fresh.files['/workspace/worker-check.txt'], 'edited');
await assert.rejects(rpc('prompt', { text: 'hello' }), /Load the model first/);
await assert.rejects(rpc('load', { cachedOnly: true }), error => error.code === 'MODEL_CACHE_MISS');
assert.equal(await rpc('stop'), true);
assert(events.some(event => event.type === 'workspace'));
assert(events.some(event => event.type === 'idle'));
});
test('a failed worker initialization identifies the failure stage and rejects subsequent RPCs', { timeout: 10_000 }, async t => {
const url = new URL('../src/agent.worker.js', import.meta.url).href;
const worker = new Worker(`
const { parentPort } = require('node:worker_threads');
globalThis.self = globalThis;
globalThis.postMessage = message => parentPort.postMessage(message);
parentPort.on('message', data => globalThis.onmessage({ data }));
// Simulate an unreadable workspace rather than a model or storage outage.
// Loading malformed saved entries fails after IndexedDB has opened.
globalThis.indexedDB = { open() {
const db = { transaction() { return { objectStore() { return { get() {
const request = { result: { entries: [['/workspace/file', { type: 'file', base64: 'invalid!' }]] } };
queueMicrotask(() => request.onsuccess());
return request;
} }; } }; } };
const request = { result: db };
queueMicrotask(() => request.onsuccess());
return request;
} };
import(${JSON.stringify(url)}).catch(error => { throw error; });
`, { eval: true });
t.after(() => worker.terminate());
const [fatal] = await once(worker, 'message');
assert.equal(fatal.type, 'fatal');
assert.equal(fatal.stage, 'initialization');
assert.match(fatal.error, /Reload the page/);
worker.postMessage({ id: 1, action: 'read', args: { path: 'README.md' } });
const [reply] = await once(worker, 'message');
assert.equal(reply.type, 'reply');
assert.equal(reply.id, 1);
assert(reply.error);
});