Files
workinf_Blender_Wasm/tools/web/check-vdb-server-job.mjs
mes123456 7c16b279ae
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
Advance M7 workflows and release operations
2026-08-15 17:43:53 -04:00

128 lines
6.6 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import fsp from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import { VDBJobService, createVDBJobHttpServer } from "../vdb/server/vdb-job-service.mjs";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const converter = path.join(root, "build_vdb_tools/vdb_to_nanovdb");
const resourceRoot = path.resolve(process.env.VDB_RESOURCE_ROOT ?? path.join(os.homedir(), "resource-library/blender-web-vdb"));
const source = path.join(resourceRoot, "generated/generated-smoke.vdb");
const secret = "vdb-server-test-signing-key-000000000000000000000000";
assert.ok(fs.existsSync(converter), "native converter is missing");
assert.ok(fs.existsSync(source), "real OpenVDB fixture is missing");
assert.equal(spawnSync("/usr/bin/bwrap", ["--version"], { encoding: "utf8" }).status, 0, "bwrap is unavailable");
const temporary = await fsp.mkdtemp(path.join(os.tmpdir(), "vdb-server-test-"));
const service = new VDBJobService({ converter, root: temporary, secret, timeoutMs: 30_000 });
const server = createVDBJobHttpServer(service);
await new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", resolve);
});
const address = server.address();
assert.ok(address && typeof address !== "string");
const origin = `http://127.0.0.1:${address.port}`;
const sourceBytes = fs.readFileSync(source);
const sourceSha256 = crypto.createHash("sha256").update(sourceBytes).digest("hex");
const headers = {
"Content-Type": "application/x-openvdb",
"X-VDB-Project-Id": "vdb-server-test",
"X-VDB-Source-Path": "//volumes/generated-smoke.vdb",
"X-VDB-Source-SHA256": sourceSha256,
"X-VDB-Grids": "density",
"X-VDB-Quantization": "LOSSLESS",
"X-VDB-Chunk-Bytes": String(4 * 1024 * 1024),
};
async function submit() {
const response = await fetch(`${origin}/v1/vdb/jobs`, { method: "POST", headers, body: sourceBytes, duplex: "half" });
if (response.status !== 200 && response.status !== 202) throw new Error(await response.text());
return { status: response.status, body: await response.json() };
}
async function waitFor(id, states, timeoutMs = 30_000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const response = await fetch(`${origin}/v1/vdb/jobs/${id}`);
assert.equal(response.status, 200);
const body = await response.json();
if (states.includes(body.state)) return body;
await new Promise((resolve) => setTimeout(resolve, 25));
}
throw new Error(`VDB server job ${id} timed out in test`);
}
try {
const health = await (await fetch(`${origin}/healthz`)).json();
assert.equal(health.sandbox, true);
assert.match(health.converterSha256, /^[a-f0-9]{64}$/);
const first = await submit();
assert.equal(first.status, 202);
assert.equal(first.body.deduplicated, false);
const completed = await waitFor(first.body.id, ["SUCCEEDED", "FAILED"]);
assert.equal(completed.state, "SUCCEEDED", completed.error);
assert.equal(completed.sandbox, "bwrap-unshare-all+readonly-root+prlimit");
const manifestResponse = await fetch(`${origin}${completed.artifacts.manifest}`);
const bundleResponse = await fetch(`${origin}${completed.artifacts.bundle}`);
assert.equal(manifestResponse.status, 200);
assert.equal(bundleResponse.status, 200);
const manifestBytes = Buffer.from(await manifestResponse.arrayBuffer());
const bundleBytes = Buffer.from(await bundleResponse.arrayBuffer());
const manifest = JSON.parse(manifestBytes.toString("utf8"));
assert.equal(manifest.converter.target, "SERVER");
assert.equal(manifest.sourceSha256, sourceSha256);
assert.deepEqual(manifest.grids.map((grid) => grid.name), ["density"]);
assert.equal(crypto.createHash("sha256").update(bundleBytes).digest("hex"), manifest.bundleSha256);
const expectedSignature = crypto.createHmac("sha256", secret).update(`${completed.id}:${crypto.createHash("sha256").update(manifestBytes).digest("hex")}:${manifest.bundleSha256}`).digest("hex");
assert.equal(manifestResponse.headers.get("x-vdb-signature"), expectedSignature);
assert.equal(bundleResponse.headers.get("x-vdb-signature"), expectedSignature);
const desktopBundle = path.join(temporary, "desktop-density.nvdb");
const desktopReport = path.join(temporary, "desktop-density.json");
const desktopConversion = spawnSync(converter, [
"--input", source,
"--output", desktopBundle,
"--report", desktopReport,
"--grid", "density",
"--quantization", "LOSSLESS",
], { encoding: "utf8" });
assert.equal(desktopConversion.status, 0, desktopConversion.stderr);
assert.equal(crypto.createHash("sha256").update(fs.readFileSync(desktopBundle)).digest("hex"), manifest.bundleSha256,
"desktop and isolated server conversion produced different NanoVDB bytes");
const repeated = await submit();
assert.equal(repeated.status, 200);
assert.equal(repeated.body.deduplicated, true);
assert.equal(repeated.body.id, completed.id);
const cancellationHeaders = { ...headers, "X-VDB-Grids": "color,density,temperature,velocity", "X-VDB-Quantization": "FP16" };
const cancellationResponse = await fetch(`${origin}/v1/vdb/jobs`, { method: "POST", headers: cancellationHeaders, body: sourceBytes, duplex: "half" });
assert.equal(cancellationResponse.status, 202);
const cancellation = await cancellationResponse.json();
const cancelledResponse = await fetch(`${origin}/v1/vdb/jobs/${cancellation.id}`, { method: "DELETE" });
assert.equal(cancelledResponse.status, 200);
const cancelled = await waitFor(cancellation.id, ["CANCELLED"]);
assert.equal(cancelled.state, "CANCELLED");
assert.equal(fs.existsSync(path.join(temporary, "jobs", cancellation.id, "bundle.nvdb")), false);
const cancelFile = path.join(temporary, "native-cancel");
fs.writeFileSync(cancelFile, "cancel\n");
const cancelledNative = spawnSync(converter, ["--input", source, "--output", path.join(temporary, "cancelled.nvdb"), "--report", path.join(temporary, "cancelled.json"), "--cancel-file", cancelFile, "--timeout-ms", "30000"], { encoding: "utf8" });
assert.notEqual(cancelledNative.status, 0);
assert.match(cancelledNative.stderr, /conversion cancelled/);
assert.equal(fs.existsSync(path.join(temporary, "cancelled.nvdb")), false);
process.stdout.write(`vdb-server-job-ok job=${completed.id} bytes=${bundleBytes.length} idempotent=1 signed=1 isolated=1 cancelled=1 atomic=1 desktop-server-hash=equal\n`);
}
finally {
await new Promise((resolve) => server.close(resolve));
await fsp.rm(temporary, { recursive: true, force: true });
}