198 lines
7.4 KiB
TypeScript
198 lines
7.4 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
test("M8-02 through M8-10 gates, pins and bounded redraws manifest-backed page faults", async ({ page }) => {
|
|
test.setTimeout(90_000);
|
|
await page.goto("/");
|
|
const result = await page.evaluate(() => new Promise<any>((resolve, reject) => {
|
|
const worker = new Worker("/src/workers/nanovdb-page-feedback-test.worker.ts", { type: "module" });
|
|
worker.onmessage = (event) => {
|
|
worker.terminate();
|
|
event.data.error ? reject(new Error(event.data.error)) : resolve(event.data);
|
|
};
|
|
worker.onerror = (event) => { worker.terminate(); reject(new Error(event.message)); };
|
|
worker.postMessage({});
|
|
}));
|
|
|
|
expect(result.leafByteOffset).toBeGreaterThan(0);
|
|
expect(result.leafPageId).toBeGreaterThan(0);
|
|
expect(result.leafPageId).toBeLessThan(result.pageCount);
|
|
expect(result.manifestPageBytes).toBe(4 * 1024 * 1024);
|
|
expect(result.leafSampleCount).toBe(256);
|
|
expect(result.leafSamplesFallback).toBe(true);
|
|
expect(result.leafResult).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 17,
|
|
attemptedCount: 1,
|
|
gpuStoredCount: 1,
|
|
uniqueCount: 1,
|
|
pageIds: [result.leafPageId],
|
|
status: "READY",
|
|
errorCode: null,
|
|
});
|
|
expect(result.leafGuard).toEqual(result.guardWords);
|
|
expect(result.staleDispatch).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 17,
|
|
currentRenderRevision: 18,
|
|
status: "STALE",
|
|
requestedPageIds: [],
|
|
requestedCount: 0,
|
|
errorCode: "REVISION_CONFLICT",
|
|
});
|
|
expect(result.stalePageIoCount).toBe(0);
|
|
expect(result.currentDispatch).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 17,
|
|
currentRenderRevision: 17,
|
|
status: "ACCEPTED",
|
|
requestedPageIds: [result.leafPageId],
|
|
requestedCount: 1,
|
|
errorCode: null,
|
|
});
|
|
expect(result.pageIoRequests).toEqual([{ pageId: result.leafPageId, renderRevision: 17 }]);
|
|
expect(result.manifestFeedbackResult).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 19,
|
|
attemptedCount: 1,
|
|
gpuStoredCount: 1,
|
|
uniqueCount: 1,
|
|
pageIds: [0],
|
|
status: "READY",
|
|
errorCode: null,
|
|
});
|
|
expect(result.manifestWordsZero).toBe(true);
|
|
expect(result.manifestStaleDispatch).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 19,
|
|
currentRenderRevision: 20,
|
|
status: "STALE",
|
|
requestedPageIds: [],
|
|
requestedCount: 0,
|
|
errorCode: "REVISION_CONFLICT",
|
|
});
|
|
expect(result.staleManifestRangeCount).toBe(0);
|
|
expect(result.manifestDispatch).toEqual({
|
|
schemaVersion: 1,
|
|
renderRevision: 19,
|
|
currentRenderRevision: 19,
|
|
status: "ACCEPTED",
|
|
requestedPageIds: [0],
|
|
requestedCount: 1,
|
|
errorCode: null,
|
|
});
|
|
expect(result.manifestPageIoRequests).toEqual([{ pageId: 0, renderRevision: 19 }]);
|
|
expect(result.manifestRanges.length).toBeGreaterThan(0);
|
|
expect(result.manifestRanges).toEqual(result.declaredManifestRanges);
|
|
expect(result.manifestRanges.every((range: { sha256: string }) => /^[a-f0-9]{64}$/.test(range.sha256))).toBe(true);
|
|
expect(result.manifestPageMatchesPayload).toBe(true);
|
|
expect(result.coalesced.rangeCalls).toBe(1);
|
|
expect(result.coalesced.underlyingAborts).toBe(0);
|
|
expect(result.coalesced.beforeCancel).toEqual({ pendingPages: 1, subscribers: 2, pageIds: [0] });
|
|
expect(result.coalesced.afterFirstCancel).toEqual({ pendingPages: 1, subscribers: 1, pageIds: [0] });
|
|
expect(result.coalesced.afterResolve).toEqual({ pendingPages: 0, subscribers: 0, pageIds: [] });
|
|
expect(result.coalesced.outcomes[0]).toEqual({ status: "REJECTED", name: "AbortError" });
|
|
expect(result.coalesced.outcomes[1].status).toBe("RESOLVED");
|
|
expect(result.coalesced.consumers).toEqual(["second:0"]);
|
|
expect(result.lastCancel.rangeCalls).toBe(1);
|
|
expect(result.lastCancel.underlyingAborts).toBe(1);
|
|
expect(result.lastCancel.afterFirst).toEqual({
|
|
stats: { pendingPages: 1, subscribers: 1, pageIds: [0] },
|
|
underlyingAborts: 0,
|
|
});
|
|
expect(result.lastCancel.afterLast).toEqual({ pendingPages: 0, subscribers: 0, pageIds: [] });
|
|
expect(result.lastCancel.outcomes).toEqual([
|
|
{ status: "REJECTED", name: "AbortError" },
|
|
{ status: "REJECTED", name: "AbortError" },
|
|
]);
|
|
expect(result.tamperedPage).toEqual({
|
|
rangeCalls: 1,
|
|
residentWrites: 0,
|
|
errorCode: "NANOVDB_HASH_MISMATCH",
|
|
errorMessage: expect.stringContaining("NANOVDB_HASH_MISMATCH"),
|
|
cache: {
|
|
residentPageCount: 0,
|
|
residentBytes: 0,
|
|
residentVirtualPages: [],
|
|
coordinator: { pendingPages: 0, subscribers: 0, pageIds: [] },
|
|
},
|
|
});
|
|
expect(result.framePin).toEqual({
|
|
pinnedPage0: true,
|
|
pinnedMissingPage: false,
|
|
afterPinnedEviction: {
|
|
residentVirtualPages: [0, 2],
|
|
evictionCount: 1,
|
|
page0: true,
|
|
page1: false,
|
|
page2: true,
|
|
},
|
|
allPinnedError: expect.stringContaining("NANOVDB_GPU_BUDGET_EXCEEDED: all resident NanoVDB pages are pinned"),
|
|
afterAllPinned: {
|
|
residentVirtualPages: [0, 2],
|
|
evictionCount: 1,
|
|
page3: false,
|
|
},
|
|
afterNextFrame: {
|
|
residentVirtualPages: [2, 3],
|
|
evictionCount: 2,
|
|
page0: false,
|
|
page2: true,
|
|
page3: true,
|
|
},
|
|
pageTable: [0xffffffff, 0xffffffff, 1, 0],
|
|
});
|
|
expect(result.progressiveRedraw).toEqual({
|
|
firstUpload: { pageId: 0, redrawScheduled: true },
|
|
secondUpload: { pageId: 1, redrawScheduled: false },
|
|
failedUpload: expect.stringContaining("NANOVDB_STREAM_INCOMPLETE"),
|
|
beforeFirst: {
|
|
queuedFrames: 1,
|
|
callbacks: 0,
|
|
stats: { pending: true, scheduledCount: 1, redrawCount: 0, maxRedraws: 32, capped: false, errorCode: null },
|
|
},
|
|
afterFirst: {
|
|
queuedFrames: 0,
|
|
callbacks: 1,
|
|
stats: { pending: false, scheduledCount: 1, redrawCount: 1, maxRedraws: 32, capped: false, errorCode: null },
|
|
},
|
|
thirdUpload: { pageId: 2, redrawScheduled: true },
|
|
beforeSecond: {
|
|
queuedFrames: 1,
|
|
callbacks: 1,
|
|
stats: { pending: true, scheduledCount: 2, redrawCount: 1, maxRedraws: 32, capped: false, errorCode: null },
|
|
},
|
|
afterSecond: {
|
|
queuedFrames: 0,
|
|
callbacks: 2,
|
|
stats: { pending: false, scheduledCount: 2, redrawCount: 2, maxRedraws: 32, capped: false, errorCode: null },
|
|
},
|
|
});
|
|
|
|
expect(result.progressiveRedrawCap).toEqual({
|
|
cappedRedraw: {
|
|
uploads: [
|
|
{ pageId: 0, redrawScheduled: true },
|
|
{ pageId: 0, redrawScheduled: true },
|
|
{ pageId: 0, redrawScheduled: false },
|
|
{ pageId: 0, redrawScheduled: false },
|
|
],
|
|
callbacks: 2,
|
|
queuedFrames: 0,
|
|
stats: { pending: false, scheduledCount: 2, redrawCount: 2, maxRedraws: 2, capped: true, errorCode: "NANOVDB_PROGRESSIVE_REDRAW_LIMIT" },
|
|
},
|
|
afterCappedReset: { pending: false, scheduledCount: 0, redrawCount: 0, maxRedraws: 2, capped: false, errorCode: null },
|
|
});
|
|
|
|
expect(result.missingWordsZero).toBe(true);
|
|
expect(result.overflowResult.status).toBe("OVERFLOW");
|
|
expect(result.overflowResult.renderRevision).toBe(18);
|
|
expect(result.overflowResult.errorCode).toBe("NANOVDB_PAGE_FEEDBACK_OVERFLOW");
|
|
expect(result.overflowResult.attemptedCount).toBeGreaterThan(2);
|
|
expect(result.overflowResult.gpuStoredCount).toBe(2);
|
|
expect(result.overflowResult.uniqueCount).toBe(2);
|
|
expect(new Set(result.overflowResult.pageIds).size).toBe(2);
|
|
expect(result.overflowResult.pageIds).toEqual([...result.overflowResult.pageIds].sort((left, right) => left - right));
|
|
expect(result.overflowResult.pageIds.every((pageId: number) => result.missingPageIds.includes(pageId))).toBe(true);
|
|
expect(result.overflowGuard).toEqual(result.guardWords);
|
|
});
|