Files
workinf_Blender_Wasm/tools/web/check-probe-identity.mjs
mes123456 380cbed4ff
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
Checkpoint web parity through Chromium input tasks
2026-08-19 10:39:03 -04:00

189 lines
9.5 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import http from "node:http";
import os from "node:os";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const distRoot = path.join(root, "web/dist");
const reportPath = path.join(root, "tests/golden/M14-01D/probe-identity-report.json");
const manifestPath = path.join(root, "tests/golden/M14-01D/manifest.json");
const digest = (value) => crypto.createHash("sha256").update(value).digest("hex");
const fileDigest = (file) => digest(fs.readFileSync(file));
const relative = (file) => path.relative(root, file).replaceAll(path.sep, "/");
const assetsRoot = path.join(distRoot, "assets");
assert.ok(fs.existsSync(assetsRoot), "production assets are missing; run npm --prefix web run build first");
const workerName = fs.readdirSync(assetsRoot).find((name) => /^storage\.worker-[\w-]+\.js$/u.test(name));
const wasmName = fs.readdirSync(assetsRoot).find((name) => /^web_engine-[\w-]+\.wasm$/u.test(name));
assert.ok(workerName && wasmName, "production worker/WASM assets are missing");
const mime = new Map([
[".html", "text/html; charset=utf-8"],
[".js", "text/javascript; charset=utf-8"],
[".css", "text/css; charset=utf-8"],
[".json", "application/json"],
[".wasm", "application/wasm"],
]);
const server = http.createServer((request, response) => {
const pathname = decodeURIComponent(new URL(request.url ?? "/", "http://127.0.0.1").pathname);
const relativePath = pathname === "/" ? "index.html" : pathname.replace(/^\//u, "");
const file = path.resolve(distRoot, relativePath);
if (!file.startsWith(`${distRoot}${path.sep}`) || !fs.existsSync(file) || !fs.statSync(file).isFile()) {
response.writeHead(404);
response.end("not found");
return;
}
response.statusCode = 200;
response.setHeader("Content-Type", mime.get(path.extname(file)) ?? "application/octet-stream");
response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
response.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
response.setHeader("Cross-Origin-Resource-Policy", "same-origin");
response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; font-src 'self'; img-src 'self'; media-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'");
fs.createReadStream(file).pipe(response);
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
assert.ok(address && typeof address === "object");
const origin = `http://127.0.0.1:${address.port}`;
let browser;
try {
const playwright = await import(pathToFileURL(path.join(root, "web/node_modules/playwright/index.mjs")).href);
browser = await playwright.chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(`${origin}/`, { waitUntil: "load" });
const probe = await page.evaluate(async ({ workerPath, wasmPath }) => {
const run = async (name, operation) => {
try {
return { name, ...await operation() };
} catch (error) {
return {
name,
status: "BLOCKED",
code: error instanceof Error ? error.name : "PROBE_FAILED",
detail: error instanceof Error ? error.message.slice(0, 200) : String(error),
};
}
};
const wasm = await run("wasm", async () => {
const response = await fetch(wasmPath);
if (!response.ok) throw new Error(`HTTP_${response.status}`);
const bytes = await response.arrayBuffer();
await WebAssembly.compile(bytes);
return { status: "PASS", code: "WASM_READY", bytes: bytes.byteLength };
});
const worker = await run("worker", async () => {
await new Promise((resolve, reject) => {
const value = new Worker(workerPath, { type: "module" });
const timer = setTimeout(() => { value.terminate(); resolve(); }, 500);
value.onerror = (event) => { clearTimeout(timer); value.terminate(); reject(new Error(event.message || "WORKER_LOAD_FAILED")); };
});
return { status: "PASS", code: "WORKER_READY" };
});
const webgl2 = await run("webgl2", async () => {
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl2");
if (!gl) return { status: "BLOCKED", code: "WEBGL2_UNAVAILABLE" };
const debug = gl.getExtension("WEBGL_debug_renderer_info");
return {
status: "PASS",
code: "WEBGL2_READY",
vendor: debug ? gl.getParameter(debug.UNMASKED_VENDOR_WEBGL) : "REDACTED",
renderer: debug ? gl.getParameter(debug.UNMASKED_RENDERER_WEBGL) : "REDACTED",
version: gl.getParameter(gl.VERSION),
};
});
const webgpu = await run("webgpu", async () => {
if (!("gpu" in navigator)) return { status: "BLOCKED", code: "WEBGPU_UNAVAILABLE" };
const adapter = await navigator.gpu.requestAdapter({ powerPreference: "high-performance" });
if (!adapter) return { status: "BLOCKED", code: "WEBGPU_ADAPTER_UNAVAILABLE" };
const info = adapter.info ?? {};
return {
status: "PASS",
code: "WEBGPU_READY",
vendor: info.vendor ?? "REDACTED",
architecture: info.architecture ?? "REDACTED",
device: info.device ?? "REDACTED",
description: info.description ?? "REDACTED",
isFallbackAdapter: Boolean(adapter.isFallbackAdapter),
};
});
return {
userAgent: navigator.userAgent,
platform: navigator.platform,
language: navigator.language,
hardwareConcurrency: navigator.hardwareConcurrency,
deviceMemory: typeof navigator.deviceMemory === "number" ? navigator.deviceMemory : null,
crossOriginIsolated,
capabilities: [wasm, worker, webgl2, webgpu],
};
}, { workerPath: `/assets/${workerName}`, wasmPath: `/assets/${wasmName}` });
const capabilities = Object.fromEntries(probe.capabilities.map((item) => [item.name, item]));
const reportWithoutIdentity = {
schemaVersion: 1,
task: "M14-01D",
operation: "PROBE_IDENTITY_GPU_OS_ADAPTER",
runtime: "PLAYWRIGHT_CHROMIUM",
browser: {
version: await browser.version(),
executablePath: playwright.chromium.executablePath(),
userAgent: probe.userAgent,
platform: probe.platform,
language: probe.language,
hardwareConcurrency: probe.hardwareConcurrency,
deviceMemory: probe.deviceMemory,
},
os: {
platform: os.platform(),
release: os.release(),
version: os.version(),
arch: os.arch(),
machine: os.machine(),
cpus: os.cpus().length,
},
adapter: {
webgl2: capabilities.webgl2,
webgpu: capabilities.webgpu,
},
isolation: { crossOriginIsolated: probe.crossOriginIsolated },
assets: {
worker: { path: relative(path.join(assetsRoot, workerName)), sha256: fileDigest(path.join(assetsRoot, workerName)) },
wasm: { path: relative(path.join(assetsRoot, wasmName)), sha256: fileDigest(path.join(assetsRoot, wasmName)) },
},
supportRule: "IDENTITY_IS_OBSERVED_ONLY; PASS_ONLY_WHEN_PROBED; BLOCKED_OR_UNAVAILABLE_DOES_NOT_CLAIM_SUPPORT",
execution: "DISABLED",
nextTask: "M14-01E",
};
const identityInput = JSON.stringify(reportWithoutIdentity);
const report = { ...reportWithoutIdentity, identitySha256: digest(identityInput) };
if (process.env.UPDATE_M14_01D_REPORT === "1") {
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
fs.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`);
if (process.env.UPDATE_M14_01D_REPORT === "1") {
const artifactPaths = {
parentManifest: path.join(root, "tests/golden/M14-01C/manifest.json"),
checker: path.join(root, "tools/web/check-probe-identity.mjs"),
package: path.join(root, "web/package.json"),
engineManifest: path.join(root, "web/app/public/engine-manifest.json"),
report: reportPath,
};
const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: relative(file), sha256: fileDigest(file) }]));
fs.writeFileSync(manifestPath, `${JSON.stringify({ schemaVersion: 1, task: "M14-01D", parentTask: "M14-01C", enablingTask: false, parityStateChange: false, runtime: "PLAYWRIGHT_CHROMIUM", operation: "PROBE_IDENTITY_GPU_OS_ADAPTER", artifacts, nextTask: "M14-01E" }, null, 2)}\n`);
}
}
assert.deepEqual(JSON.parse(fs.readFileSync(reportPath, "utf8")), report);
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
assert.deepEqual({ schemaVersion: manifest.schemaVersion, task: manifest.task, parentTask: manifest.parentTask, nextTask: manifest.nextTask }, { schemaVersion: 1, task: "M14-01D", parentTask: "M14-01C", nextTask: "M14-01E" });
for (const artifact of Object.values(manifest.artifacts)) assert.equal(fileDigest(path.join(root, artifact.path)), artifact.sha256, artifact.path);
assert.equal(report.identitySha256, digest(JSON.stringify(reportWithoutIdentity)));
const summary = [capabilities.webgl2, capabilities.webgpu].map((item) => `${item.name}=${item.status}`).join(",");
process.stdout.write(`probe-identity-ok version=${report.browser.version} os=${report.os.platform}/${report.os.arch} ${summary} identity=${report.identitySha256} execution=DISABLED next=${manifest.nextTask}\n`);
} finally {
await browser?.close();
await new Promise((resolve) => server.close(resolve));
}