79 lines
3.5 KiB
TypeScript
79 lines
3.5 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
test("loads the selected pthread engine with shared memory and its worker pool", async ({ page }) => {
|
|
const pthreadRequests: string[] = [];
|
|
page.on("request", (request) => {
|
|
const pathname = new URL(request.url()).pathname;
|
|
if (pathname.startsWith("/vendor/blender/pthread/")) pthreadRequests.push(pathname);
|
|
});
|
|
|
|
const documentResponse = await page.goto("/");
|
|
expect(documentResponse).not.toBeNull();
|
|
const headers = await documentResponse!.allHeaders();
|
|
expect(headers["cross-origin-opener-policy"]).toBe("same-origin");
|
|
expect(headers["cross-origin-embedder-policy"]).toBe("require-corp");
|
|
|
|
const result = await page.evaluate(async () => {
|
|
const { detectBrowserCapabilities, selectWebEngineVariant } = await import("/src/platform/capabilities.ts");
|
|
const manifest = await fetch("/engine-manifest.json", { cache: "no-store" }).then((response) => response.json());
|
|
const selection = selectWebEngineVariant(manifest, "PTHREAD_REQUIRED", detectBrowserCapabilities());
|
|
if (!selection.selectedVariant) {
|
|
return { selected: null, gate: selection.pthreadGate, shared: false, handle: 0, liveAfterDestroy: -1 };
|
|
}
|
|
|
|
const variant = selection.selectedVariant;
|
|
const wasmResponse = await fetch(variant.resources.wasm.url, { cache: "no-store" });
|
|
if (!wasmResponse.ok) throw new Error(`pthread WASM request failed: ${wasmResponse.status}`);
|
|
const wasmBinary = await wasmResponse.arrayBuffer();
|
|
const digest = await crypto.subtle.digest("SHA-256", wasmBinary);
|
|
const actualHash = [...new Uint8Array(digest)]
|
|
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
.join("");
|
|
if (actualHash !== variant.resources.wasm.sha256) throw new Error("pthread WASM hash mismatch");
|
|
|
|
const imported = await import(/* @vite-ignore */ variant.resources.js.url) as {
|
|
default: (options: { wasmBinary: ArrayBuffer }) => Promise<{
|
|
HEAPU8: Uint8Array;
|
|
_web_engine_create(): number;
|
|
_web_engine_destroy(handle: number): void;
|
|
_web_engine_get_live_handles(): number;
|
|
PThread: {
|
|
unusedWorkers: Worker[];
|
|
runningWorkers: Worker[];
|
|
terminateAllThreads(): void;
|
|
};
|
|
}>;
|
|
};
|
|
const module = await imported.default({ wasmBinary });
|
|
const handle = module._web_engine_create();
|
|
const shared = module.HEAPU8.buffer instanceof SharedArrayBuffer;
|
|
const liveBeforeDestroy = module._web_engine_get_live_handles();
|
|
const poolWorkersBeforeDispose = module.PThread.unusedWorkers.length + module.PThread.runningWorkers.length;
|
|
module._web_engine_destroy(handle);
|
|
module.PThread.terminateAllThreads();
|
|
return {
|
|
selected: variant.id,
|
|
gate: selection.pthreadGate,
|
|
shared,
|
|
handle,
|
|
liveBeforeDestroy,
|
|
liveAfterDestroy: module._web_engine_get_live_handles(),
|
|
poolWorkersBeforeDispose,
|
|
poolWorkersAfterDispose: module.PThread.unusedWorkers.length + module.PThread.runningWorkers.length,
|
|
};
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
selected: "pthread",
|
|
gate: { taskId: "M6-02", capability: "WASM_PTHREAD_ENGINE", status: "READY", issues: [] },
|
|
shared: true,
|
|
liveBeforeDestroy: 1,
|
|
liveAfterDestroy: 0,
|
|
poolWorkersBeforeDispose: 1,
|
|
poolWorkersAfterDispose: 0,
|
|
});
|
|
expect(result.handle).toBeGreaterThan(0);
|
|
expect(pthreadRequests.filter((url) => url.endsWith("/web_engine.wasm"))).toHaveLength(1);
|
|
expect(pthreadRequests.filter((url) => url.endsWith("/web_engine.js")).length).toBeGreaterThanOrEqual(2);
|
|
});
|