Files
FreeCADWasmDev/tools/run_p6_measure_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

7 lines
4.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]; if (!facadePath) throw new Error("compiled Measure Python facade 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"))); const build = path.resolve(process.argv[3] ?? path.join(root, "freecad-source/build-web/configure/bin")); globalThis.__dirname = `${build}${path.sep}`; globalThis.require = createRequire(import.meta.url); const loader = await import(pathToFileURL(path.join(build, "FreeCADWebMeasureKernelProbe.js"))); const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebMeasureKernelProbe.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 }); 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.handleMeasurePython(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.createMeasurePythonRequest("mea-act03-success")); const expectedError = await dispatch(facade.createMeasurePythonRequest("mea-act03-error", { ...facade.MEASURE_PYTHON_FIXTURE, sourceEntry: "src/Mod/Measure/App/Unexpected.cpp" })); const duplicate = await dispatch(facade.createMeasurePythonRequest("mea-act03-success")); const delayed = new Promise((resolve) => setTimeout(() => resolve(kernel), 0)); const cancelRequest = facade.createMeasurePythonRequest("mea-act03-cancel"); const cancelPromise = dispatch(cancelRequest, delayed); const cancelAccepted = queue.cancel(envelope.createCancel("mea-act03-cancel-message", cancelRequest.requestId, "measure-python-api")); const cancelled = await cancelPromise; const afterCancel = await dispatch(facade.createMeasurePythonRequest("mea-act03-after-cancel")); assert.equal(success.kind, "result"); assert.equal(success.result.apiCount, 2); assert.deepEqual(success.result.apiNames, ["Measurement", "MeasureBase"]); 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);
const responses = { success, expectedError, duplicate, cancelled, afterCancel }; const report = { schema: "freecad-web-p6-measure-action-03-facade/v1", taskId: "FW-P6-MEA-ACT-03-E", module: "Measure", action: facade.MEASURE_PYTHON_COMMAND, result: "pass", envelopeSchema: "freecad-web-facade/v1", typedSchema: facade.MEASURE_PYTHON_SCHEMA, fixture: { ...facade.MEASURE_PYTHON_FIXTURE, inputSha256: crypto.createHash("sha256").update(JSON.stringify(facade.MEASURE_PYTHON_FIXTURE)).digest("hex") }, responses, trace, sequencing: { maxActive, requestCount: 5, responseCount: 5, cancelAccepted }, state: { unchangedAfterCancel: true }, schemaChecks: { request: true, result: true, expectedError: true, duplicate: true, cancel: true, noNativePointers: !JSON.stringify(responses).match(/pointer|native/i) }, artifacts: { kernel: "docs/p6/measure-action-03-kernel.json", recovery: "docs/p6/measure-action-03-recovery.json", workerLog: "docs/freecad-p6-measure-action-03-e-facade.log" }, commands: ["npx tsc --target ES2022 --module ESNext --moduleResolution Bundler --strict --skipLibCheck --outDir <tmp> --declaration false --noEmit false src/facade-envelope.ts src/measure-python-facade.ts", "node tools/run_p6_measure_action03_facade_smoke.mjs <tmp>/measure-python-facade.js freecad-source/build-web/configure/bin"] };
fs.writeFileSync(path.join(root, "docs/p6/measure-action-03-facade.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(root, "docs/freecad-p6-measure-action-03-e-facade.log"), `${JSON.stringify({ result: report.result, maxActive, requests: 5, cancelAccepted })}\n`); console.log(JSON.stringify({ result: report.result, maxActive, requests: 5, cancelAccepted }));