- tests/runtime-gate.test.js lifts the shipped ensureRuntimeGateReady() and checks its behaviour against stub gates, and statically asserts that startSequence() awaits the gate before launching the engine, so a refactor cannot silently drop the first-run import wait. - packaging/wsl2/README.md documents the manual remote-session (SSH/RDP) verification, since the engine path is a console process that needs a real Windows host and cannot be covered by an automated test.
104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
// Checks the shared scan pipeline is wired to the shell's runtime gate.
|
|
//
|
|
// On Windows the bundled WSL2 engine is imported on first run, so a Run must
|
|
// wait for the gate before launching the engine. This test guards two things
|
|
// without needing a Windows host:
|
|
// 1. the behaviour of ensureRuntimeGateReady() against stub gates;
|
|
// 2. that startSequence() actually awaits it, so a future refactor cannot
|
|
// silently drop the gate and race the import.
|
|
//
|
|
// Run with: node tests/runtime-gate.test.js
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const assert = require('assert');
|
|
|
|
const libPath = path.join(__dirname, '..', 'TrimSPlib.js');
|
|
const src = fs.readFileSync(libPath, 'utf8');
|
|
|
|
function grab(re) {
|
|
const m = src.match(re);
|
|
if (!m) {
|
|
throw new Error('pattern not found in ' + libPath + ': ' + re);
|
|
}
|
|
return m[0];
|
|
}
|
|
|
|
// Lift the real ensureRuntimeGateReady() so its shipped code is exercised.
|
|
const gateSource = grab(/async function ensureRuntimeGateReady\s*\([^)]*\)\s*\{[\s\S]*?\n\}/m);
|
|
|
|
let statusCalls = [];
|
|
let stubWindow = {};
|
|
|
|
const factory = new Function('window', 'updateStatusBar',
|
|
gateSource + '\nreturn ensureRuntimeGateReady;');
|
|
|
|
function makeGateFn() {
|
|
statusCalls = [];
|
|
return factory(stubWindow, function (payload) { statusCalls.push(payload); });
|
|
}
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
function check(name, ok, detail) {
|
|
if (ok) { passed++; } else { failed++; }
|
|
console.log((ok ? 'PASS ' : 'FAIL ') + name.padEnd(46) + (detail || ''));
|
|
}
|
|
|
|
async function main() {
|
|
// 1. No gate installed (web/standalone) -> proceed, no status write.
|
|
stubWindow = {};
|
|
let gate = makeGateFn();
|
|
let result = await gate('Run');
|
|
check('no gate: proceeds', result === true && statusCalls.length === 0);
|
|
|
|
// 2. Gate resolves true -> proceed.
|
|
stubWindow = { TrimSPRuntimeGate: { ready: () => Promise.resolve(true) } };
|
|
gate = makeGateFn();
|
|
result = await gate('Run');
|
|
check('gate ready: proceeds', result === true);
|
|
|
|
// 3. Gate resolves false -> blocked and message surfaced.
|
|
stubWindow = {
|
|
TrimSPRuntimeGate: {
|
|
ready: () => Promise.resolve(false),
|
|
message: () => 'Check that WSL2 is installed, then try again.'
|
|
}
|
|
};
|
|
gate = makeGateFn();
|
|
result = await gate('Run');
|
|
check('gate not ready: blocked', result === false);
|
|
check('gate not ready: status shown',
|
|
statusCalls.length === 1
|
|
&& /runtime is not ready/.test(statusCalls[0].run)
|
|
&& /WSL2 is installed/.test(statusCalls[0].run),
|
|
statusCalls.length ? '"' + statusCalls[0].run + '"' : 'no status');
|
|
|
|
// 4. Gate that throws -> treated as not ready, not an unhandled rejection.
|
|
stubWindow = {
|
|
TrimSPRuntimeGate: {
|
|
ready: () => Promise.reject(new Error('boom')),
|
|
message: () => 'failed'
|
|
}
|
|
};
|
|
gate = makeGateFn();
|
|
result = await gate('Run');
|
|
check('gate throwing: blocked', result === false && statusCalls.length === 1);
|
|
|
|
// 5. startSequence must await the gate before running the engine.
|
|
const startSequence = grab(/async function startSequence\s*\([^)]*\)\s*\{[\s\S]*?\n\}/m);
|
|
const guardIndex = startSequence.indexOf('ensureRuntimeGateReady');
|
|
const launchIndex = startSequence.indexOf('runSimulationSequence');
|
|
check('startSequence awaits gate',
|
|
guardIndex !== -1,
|
|
guardIndex !== -1 ? '' : 'no ensureRuntimeGateReady() call');
|
|
check('gate checked before launch',
|
|
guardIndex !== -1 && launchIndex !== -1 && guardIndex < launchIndex);
|
|
|
|
console.log('\n' + passed + ' passed, ' + failed + ' failed');
|
|
process.exit(failed ? 1 : 0);
|
|
}
|
|
|
|
main();
|