126 lines
5.0 KiB
JavaScript
126 lines
5.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import ts from "typescript";
|
|
|
|
const repoRoot = path.resolve(import.meta.dirname, "../../..");
|
|
|
|
function transpileDataUrl(filePath, replacements = new Map()) {
|
|
const result = ts.transpileModule(fs.readFileSync(filePath, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: filePath,
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(result.diagnostics, []);
|
|
let source = result.outputText;
|
|
for (const [specifier, replacement] of replacements) {
|
|
source = source.replaceAll(`"${specifier}"`, JSON.stringify(replacement));
|
|
}
|
|
return `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`;
|
|
}
|
|
|
|
const gatesUrl = transpileDataUrl(path.join(repoRoot, "web/protocol/capability-gates.ts"));
|
|
const selectorUrl = transpileDataUrl(
|
|
path.join(repoRoot, "web/protocol/engine-variant.ts"),
|
|
new Map([["./capability-gates", gatesUrl]]),
|
|
);
|
|
const { bindWebEngineRelease, gateWasmThreadingCapability, selectWebEngineVariant } = await import(selectorUrl);
|
|
const manifest = JSON.parse(fs.readFileSync(
|
|
path.join(repoRoot, "tests/golden/M6-04A/engine-manifest-v2.json"),
|
|
"utf8",
|
|
));
|
|
const ready = { crossOriginIsolated: true, sharedArrayBuffer: true, worker: true };
|
|
|
|
function deepFreeze(value) {
|
|
if (value && typeof value === "object") {
|
|
Object.freeze(value);
|
|
for (const item of Object.values(value)) deepFreeze(item);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
test("M6-04C selects from only its manifest, policy and capability inputs", () => {
|
|
const frozenManifest = deepFreeze(structuredClone(manifest));
|
|
const frozenCapabilities = deepFreeze({ ...ready });
|
|
const first = selectWebEngineVariant(frozenManifest, "SINGLE_REQUIRED", frozenCapabilities);
|
|
const second = selectWebEngineVariant(frozenManifest, "SINGLE_REQUIRED", frozenCapabilities);
|
|
|
|
assert.deepEqual(first, second);
|
|
assert.equal(first.policy, "SINGLE_REQUIRED");
|
|
assert.equal(first.selectedVariant, frozenManifest.variants[0]);
|
|
assert.equal(first.selectedVariant.id, "single");
|
|
assert.equal(first.pthreadGate.status, "READY");
|
|
assert.throws(
|
|
() => selectWebEngineVariant(frozenManifest, "INVALID", frozenCapabilities),
|
|
/ENGINE_VARIANT_POLICY_INVALID/,
|
|
);
|
|
});
|
|
|
|
test("M6-04D AUTO selects pthread only when the M6-02 gate is READY", () => {
|
|
const capabilityCases = [
|
|
[ready, "pthread", []],
|
|
[{ ...ready, crossOriginIsolated: false }, "single", ["crossOriginIsolated"]],
|
|
[{ ...ready, sharedArrayBuffer: false }, "single", ["sharedArrayBuffer"]],
|
|
[{ ...ready, worker: false }, "single", ["worker"]],
|
|
[
|
|
{ crossOriginIsolated: false, sharedArrayBuffer: false, worker: false },
|
|
"single",
|
|
["crossOriginIsolated", "sharedArrayBuffer", "worker"],
|
|
],
|
|
];
|
|
|
|
for (const [capabilities, expectedId, expectedPaths] of capabilityCases) {
|
|
const selection = selectWebEngineVariant(manifest, "AUTO", capabilities);
|
|
assert.equal(selection.selectedVariant.id, expectedId);
|
|
assert.equal(selection.pthreadGate.status, expectedId === "pthread" ? "READY" : "BLOCKED");
|
|
assert.deepEqual(selection.pthreadGate.issues.map((issue) => issue.path), expectedPaths);
|
|
}
|
|
});
|
|
|
|
test("M6-04E PTHREAD_REQUIRED exposes the M6-02 block without a requestable variant", () => {
|
|
const capabilities = { crossOriginIsolated: false, sharedArrayBuffer: false, worker: true };
|
|
const expectedGate = gateWasmThreadingCapability(capabilities);
|
|
const blocked = selectWebEngineVariant(manifest, "PTHREAD_REQUIRED", capabilities);
|
|
assert.equal(blocked.selectedVariant, null);
|
|
assert.deepEqual(blocked.pthreadGate, expectedGate);
|
|
assert.deepEqual(blocked.pthreadGate, {
|
|
taskId: "M6-02",
|
|
capability: "WASM_PTHREAD_ENGINE",
|
|
status: "BLOCKED",
|
|
issues: [
|
|
{
|
|
code: "PLATFORM_CAPABILITY_UNAVAILABLE",
|
|
message: "Cross-origin isolation is required for the pthread WASM engine",
|
|
path: "crossOriginIsolated",
|
|
recoverable: true,
|
|
},
|
|
{
|
|
code: "PLATFORM_CAPABILITY_UNAVAILABLE",
|
|
message: "SharedArrayBuffer is required for the pthread WASM engine",
|
|
path: "sharedArrayBuffer",
|
|
recoverable: true,
|
|
},
|
|
],
|
|
});
|
|
|
|
const allowed = selectWebEngineVariant(manifest, "PTHREAD_REQUIRED", ready);
|
|
assert.equal(allowed.selectedVariant.id, "pthread");
|
|
assert.equal(allowed.pthreadGate.status, "READY");
|
|
});
|
|
|
|
test("M6-08C/D binds both variants to one release and refuses mixed-version startup", () => {
|
|
const current = bindWebEngineRelease(manifest.releaseId, manifest);
|
|
assert.equal(current.status, "READY");
|
|
assert.equal(current.manifest, manifest);
|
|
assert.deepEqual(current.manifest.variants.map((variant) => variant.id), ["single", "pthread"]);
|
|
|
|
const switched = bindWebEngineRelease("blender-wasm-previous", manifest);
|
|
assert.deepEqual(switched, {
|
|
status: "REFRESH_REQUIRED",
|
|
expectedReleaseId: "blender-wasm-previous",
|
|
actualReleaseId: manifest.releaseId,
|
|
manifest: null,
|
|
});
|
|
});
|