Advance M7 workflows and release operations
This commit is contained in:
78
web/tests/e2e/pthread-engine-isolated.spec.ts
Normal file
78
web/tests/e2e/pthread-engine-isolated.spec.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user