Files
FreeCADWasmDev/tools/run_p6_inspection_action03_facade_smoke.mjs
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

82 lines
5.7 KiB
JavaScript

#!/usr/bin/env node
import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";
import { pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
const facadePath = process.argv[2];
const buildDirectory = path.resolve(process.argv[3] ?? path.join(root, "freecad-source/build-web/configure/bin"));
if (!facadePath) throw new Error("compiled inspection-python-facade module path is required");
const facade = await import(pathToFileURL(path.resolve(facadePath)));
const envelope = await import(pathToFileURL(path.join(path.dirname(path.resolve(facadePath)), "facade-envelope.js")));
globalThis.__dirname = `${buildDirectory}${path.sep}`;
globalThis.require = createRequire(import.meta.url);
const loader = await import(pathToFileURL(path.join(buildDirectory, "FreeCADWebInspectionRuntimeProbe.js")));
const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(buildDirectory, "FreeCADWebInspectionRuntimeProbe.wasm")) });
const queue = new envelope.FacadeSerialQueue();
const trace = [];
let active = 0;
let maxActive = 0;
async function dispatch(request, source = kernel) {
trace.push({ direction: "request", requestId: request.requestId, command: request.command });
const response = await queue.dispatch(request, async (payload, signal) => {
active += 1;
maxActive = Math.max(maxActive, active);
trace.push({ direction: "handler-start", requestId: request.requestId });
try { return await facade.handleInspectionPython(payload, signal, source); }
finally { active -= 1; trace.push({ direction: "handler-end", requestId: request.requestId }); }
});
trace.push({ direction: "response", requestId: response.requestId, kind: response.kind, code: response.kind === "error" ? response.error.code : null });
return response;
}
const success = await dispatch(facade.createInspectionPythonRequest("inspection-act03-e-success"));
const expectedError = await dispatch(facade.createInspectionPythonRequest("inspection-act03-e-error", { ...facade.INSPECTION_PYTHON_FIXTURE, sourceRevision: "wrong-revision" }));
const duplicate = await dispatch(facade.createInspectionPythonRequest("inspection-act03-e-success"));
const cancelRequest = facade.createInspectionPythonRequest("inspection-act03-e-cancel");
let resolveKernel;
const delayedKernel = new Promise((resolve) => { resolveKernel = resolve; });
const cancelPromise = dispatch(cancelRequest, delayedKernel);
const cancelAccepted = queue.cancel(envelope.createCancel("inspection-act03-e-cancel-message", cancelRequest.requestId, "inspection-python-doc"));
resolveKernel(kernel);
const cancelled = await cancelPromise;
const afterCancel = await dispatch(facade.createInspectionPythonRequest("inspection-act03-e-after-cancel"));
assert.equal(facade.isInspectionPythonRequest(facade.createInspectionPythonRequest("schema-test")), true);
assert.equal(facade.isInspectionPythonRequest({ ...facade.createInspectionPythonRequest("schema-test"), command: "other" }), false);
assert.equal(success.kind, "result");
assert.equal(success.result.apiCount, 3);
assert.equal(success.result.apiNames.length, 3);
assert.equal(success.result.readOnly, true);
assert.equal(success.result.moduleHandleAfterRelease, 0);
assert.equal(expectedError.kind, "error");
assert.equal(expectedError.error.code, "revision_mismatch");
assert.equal(duplicate.error.code, "duplicate_request");
assert.equal(cancelAccepted, true);
assert.equal(cancelled.error.code, "cancelled");
assert.deepEqual(afterCancel.result, success.result);
assert.equal(maxActive, 1);
assert.equal(active, 0);
for (const response of [success, expectedError, duplicate, cancelled, afterCancel]) assert.equal(envelope.isFacadeResponse(response), true);
const report = {
schema: "freecad-web-p6-inspection-action-03-facade/v1",
taskId: "FW-P6-INS-ACT-03-E",
module: "Inspection",
action: facade.INSPECTION_PYTHON_COMMAND,
result: "pass",
envelopeSchema: "freecad-web-facade/v1",
typedSchema: facade.INSPECTION_PYTHON_SCHEMA,
fixture: { ...facade.INSPECTION_PYTHON_FIXTURE, inputSha256: crypto.createHash("sha256").update(JSON.stringify(facade.INSPECTION_PYTHON_FIXTURE)).digest("hex") },
responses: { success, expectedError, duplicate, cancelled, afterCancel },
trace,
sequencing: { maxActive, activeAfter: active, requestCount: 5, responseCount: 5, cancelAccepted },
state: { beforeCancel: success.result.stateSha256, afterCancel: afterCancel.result.stateSha256, unchangedAfterCancel: true },
schemaChecks: { request: true, result: true, expectedError: true, duplicate: true, cancel: true, noNativePointers: !JSON.stringify({ success, expectedError, duplicate, cancelled, afterCancel, trace }).match(/pointer|native/i) },
artifacts: { workerLog: "docs/freecad-p6-inspection-action-03-e-facade.log", wasm: "freecad-source/build-web/configure/bin/FreeCADWebInspectionRuntimeProbe.wasm" },
commands: ["npx tsc --target ES2022 --module ESNext --moduleResolution Bundler --strict --skipLibCheck --outDir <tmp> --declaration false --noEmit false src/facade-envelope.ts src/inspection-python-facade.ts", "node tools/run_p6_inspection_action03_facade_smoke.mjs <tmp>/inspection-python-facade.js freecad-source/build-web/configure/bin"],
};
fs.writeFileSync(path.join(root, "docs/p6/inspection-action-03-facade.json"), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(path.join(root, "docs/freecad-p6-inspection-action-03-e-facade.log"), `${trace.map((event, index) => `${String(index + 1).padStart(2, "0")} ${JSON.stringify(event)}`).join("\n")}\nresult=pass\nmaxActive=${maxActive}\n`);
console.log(JSON.stringify({ result: report.result, apiCount: success.result.apiCount, requests: 5, cancelAccepted }));