blob: 3ccf8684cc8efc549e7ce816ad9efebdfde2854c [file]
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const { File } = require('node:buffer');
const typescript = require('typescript');
const previousTypeScriptLoader = require.extensions['.ts'];
require.extensions['.ts'] = (module, filename) => {
const output = typescript.transpileModule(fs.readFileSync(filename, 'utf8'), {
compilerOptions: { module: typescript.ModuleKind.CommonJS, target: typescript.ScriptTarget.ES2020 },
}).outputText;
module._compile(output, filename);
};
const client = require('./profile-analysis.parser-client.ts');
const parser = require('./profile-analysis.parser.ts');
const workerParser = require('./profile-analysis.parser.worker.ts');
require.extensions['.ts'] = previousTypeScriptLoader;
class FakeWorker {
onmessage = null;
onerror = null;
posted = [];
terminated = 0;
postMessage(message) {
this.posted.push(message);
}
terminate() {
this.terminated += 1;
}
}
const file = new File(['MergedProfile:'], 'profile.txt', { type: 'text/plain' });
const dag = {
schemaVersion: '1.0',
graph: { direction: 'BOTTOM_TO_TOP', nodes: [], edges: [] },
profile: {}, fragments: [], pipelines: [], unresolvedReferences: [], warnings: [],
summary: { fragmentCount: 0, pipelineCount: 0, nodeCount: 0, edgeCount: 0, unresolvedEdgeCount: 0 },
};
test('posts one file request, accepts only its request id, and terminates after success', async () => {
const worker = new FakeWorker();
const operation = client.startProfileParse(file, () => worker, 1_000);
assert.equal(worker.posted.length, 1);
assert.equal(worker.posted[0].type, 'PARSE_PROFILE');
assert.equal(worker.posted[0].file, file);
worker.onmessage({ data: { type: 'PARSE_SUCCESS', requestId: 'stale', dag } });
assert.equal(worker.terminated, 0);
worker.onmessage({ data: { type: 'PARSE_SUCCESS', requestId: operation.requestId, dag } });
assert.equal(await operation.promise, dag);
assert.equal(worker.terminated, 1);
});
test('maps stable parser failures and terminates the worker', async () => {
const worker = new FakeWorker();
const operation = client.startProfileParse(file, () => worker, 1_000);
worker.onmessage({ data: { type: 'PARSE_FAILURE', requestId: operation.requestId, code: 'DAG_UNAVAILABLE' } });
await assert.rejects(operation.promise, error => error.code === 'DAG_UNAVAILABLE');
assert.equal(worker.terminated, 1);
});
test('terminates and rejects an operation on timeout', async () => {
const worker = new FakeWorker();
const operation = client.startProfileParse(file, () => worker, 5);
await assert.rejects(operation.promise, /timed out/);
assert.equal(worker.terminated, 1);
});
test('cancels an in-flight operation and ignores late worker responses', async () => {
const worker = new FakeWorker();
const operation = client.startProfileParse(file, () => worker, 1_000);
operation.cancel();
worker.onmessage({ data: { type: 'PARSE_SUCCESS', requestId: operation.requestId, dag } });
await assert.rejects(operation.promise, error => error.name === 'AbortError');
assert.equal(worker.terminated, 1);
});
test('rejects oversized prepared files before creating a worker', async () => {
let workerCalls = 0;
const oversized = { name: 'large.txt', size: parser.MAX_PARSER_BYTES + 1 };
const operation = client.startProfileParse(oversized, () => {
workerCalls += 1;
return new FakeWorker();
});
await assert.rejects(operation.promise, error => error.code === 'DAG_TOO_LARGE');
assert.equal(workerCalls, 0);
});
test('rejects invalid UTF-8 before parsing Profile structure', async () => {
const invalidUtf8 = new File([new Uint8Array([0xc3, 0x28])], 'invalid.txt', { type: 'text/plain' });
await assert.rejects(workerParser.parseProfileFile(invalidUtf8), error => {
assert.equal(error.code, 'DAG_PARSE_FAILED');
assert.match(error.message, /valid UTF-8/);
return true;
});
});