test: add deterministic resilience matrix

This commit is contained in:
2026-09-02 07:24:48 +03:00
parent 5abd1c19ae
commit 8089d061ec
21 changed files with 809 additions and 22 deletions

View File

@@ -9,6 +9,10 @@ import { createSun } from '@/scene/world/sun';
import { createCar } from '@/scene/world/car';
import { createSign } from '@/scene/world/sign';
import { createParticles } from '@/scene/world/particles';
import { isTestFault, recordTestFaultEvent } from '@/testing/fault-hooks';
declare const __PORTFOLIO_TEST_BUILD__: boolean;
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
const skyColors: Readonly<Record<EnvironmentChapter, number>> = {
'deep-night': 0x040713,
@@ -29,6 +33,18 @@ export function createChaseCamera(aspect = 1) {
export async function createProceduralSceneGeneration(
context: SceneBuildContext,
): Promise<SceneGeneration> {
if (TEST_BUILD && isTestFault('F1-shader')) {
recordTestFaultEvent('shader-rejected');
throw new Error('Injected shader failure');
}
if (TEST_BUILD && isTestFault('F1-texture')) {
recordTestFaultEvent('texture-rejected');
throw new Error('Injected texture failure');
}
if (TEST_BUILD && isTestFault('F1-car')) {
recordTestFaultEvent('car-rejected');
throw new Error('Injected car failure');
}
if (context.signal.aborted) throw new DOMException('Scene build aborted', 'AbortError');
const canvas = context.canvas as HTMLCanvasElement;
if (typeof canvas.getContext !== 'function') throw new Error('A canvas element is required');
@@ -104,6 +120,7 @@ export async function createProceduralSceneGeneration(
let driveDistance = 0;
let lastNow: number | null = null;
let disposed = false;
let renderedFrames = 0;
const resize = (): void => {
const nextWidth = Math.max(1, canvas.clientWidth || canvas.width || 1);
@@ -128,6 +145,14 @@ export async function createProceduralSceneGeneration(
return {
render(snapshot: Readonly<JourneySnapshot>, now: number) {
if (disposed) return;
if (
TEST_BUILD
&& isTestFault('F3-post-first-frame-exception')
&& renderedFrames > 0
) {
recordTestFaultEvent('post-first-frame-exception');
throw new Error('Injected post-first-frame exception');
}
resize();
const deltaSeconds = lastNow === null ? 0 : Math.min(0.1, Math.max(0, (now - lastNow) / 1000));
lastNow = now;
@@ -152,6 +177,7 @@ export async function createProceduralSceneGeneration(
} else {
renderer.render(scene, camera);
}
renderedFrames += 1;
},
dispose() {
if (disposed) return;