From faec40ff7b9cb03180eb02c6f21df098b098424c Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:55:49 +0200 Subject: [PATCH] test(performance): stabilize Xtream benchmark startup (#1304) * test(performance): stabilize Xtream benchmark startup * test(performance): bound cancellation clock skew --- .../xtream-benchmark-iteration-support.ts | 8 +++ .../xtream-iteration-assembler.spec.ts | 54 +++++++++++++++++++ .../xtream-iteration-assembly-scenarios.ts | 7 ++- .../xtream-scenario-driver-wiring.spec.ts | 9 +++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/apps/electron-backend-e2e/src/performance/xtream-benchmark-iteration-support.ts b/apps/electron-backend-e2e/src/performance/xtream-benchmark-iteration-support.ts index 2f43572b6..6d3066d8b 100644 --- a/apps/electron-backend-e2e/src/performance/xtream-benchmark-iteration-support.ts +++ b/apps/electron-backend-e2e/src/performance/xtream-benchmark-iteration-support.ts @@ -50,6 +50,14 @@ export interface SeedXtreamExistingPortalOptions { export async function prearmXtreamDatabaseWorker( app: LaunchedElectronApp ): Promise { + // Main owns schema creation but loads the renderer first. Fence that + // startup promise before the independent worker opens the fresh database. + const downloads = await app.mainWindow.evaluate(() => + window.electron.downloadsGetList() + ); + if (!Array.isArray(downloads)) { + throw new Error('xtream-main-database-readiness-invalid'); + } const playlists = await app.mainWindow.evaluate(() => window.electron.dbGetAppPlaylists() ); diff --git a/apps/electron-backend-e2e/src/performance/xtream-iteration-assembler.spec.ts b/apps/electron-backend-e2e/src/performance/xtream-iteration-assembler.spec.ts index fc529d740..31a47bf63 100644 --- a/apps/electron-backend-e2e/src/performance/xtream-iteration-assembler.spec.ts +++ b/apps/electron-backend-e2e/src/performance/xtream-iteration-assembler.spec.ts @@ -173,6 +173,60 @@ describe('Xtream raw iteration assembler', () => { ); }); + it('accepts sub-millisecond skew between renderer and main cancellation clocks', () => { + const input = createXtreamAssemblerFixture( + XTREAM_SCENARIO_ID.CANCEL_IMPORT + ); + const workerTerminal = input.mainCapture.cancelTimeline.find( + ({ type }) => type === 'db-cancel-terminal-received' + ); + assert.ok(workerTerminal); + const rendererTerminalEpochMs = workerTerminal.epochMs - 0.1; + assert.ok( + rendererTerminalEpochMs > + Number(input.rendererCapture.probe.cancellationClickEpochMs) + ); + + assert.doesNotThrow(() => + assembleXtreamRawIteration({ + ...input, + rendererCapture: { + ...input.rendererCapture, + probe: { + ...input.rendererCapture.probe, + dbCancellationTerminalEpochMs: rendererTerminalEpochMs, + }, + }, + }) + ); + }); + + it('rejects a cancellation terminal that substantially predates the main receipt', () => { + const input = createXtreamAssemblerFixture( + XTREAM_SCENARIO_ID.CANCEL_IMPORT + ); + const workerTerminal = input.mainCapture.cancelTimeline.find( + ({ type }) => type === 'db-cancel-terminal-received' + ); + assert.ok(workerTerminal); + + assert.throws( + () => + assembleXtreamRawIteration({ + ...input, + rendererCapture: { + ...input.rendererCapture, + probe: { + ...input.rendererCapture.probe, + dbCancellationTerminalEpochMs: + workerTerminal.epochMs - 2, + }, + }, + }), + /xtream-iteration-assembly-invalid/ + ); + }); + it('accepts main observing a network cancel response after the next renderer IPC starts', () => { const input = createXtreamAssemblerFixture( XTREAM_SCENARIO_ID.CANCEL_IMPORT diff --git a/apps/electron-backend-e2e/src/performance/xtream-iteration-assembly-scenarios.ts b/apps/electron-backend-e2e/src/performance/xtream-iteration-assembly-scenarios.ts index e07ce6dd9..ed4b72541 100644 --- a/apps/electron-backend-e2e/src/performance/xtream-iteration-assembly-scenarios.ts +++ b/apps/electron-backend-e2e/src/performance/xtream-iteration-assembly-scenarios.ts @@ -26,6 +26,8 @@ import { type XtreamUiActionSample, } from './xtream-ui-action-probe'; +const CANCELLATION_CLOCK_SKEW_TOLERANCE_MS = 1; + export interface XtreamScenarioAssembly { readonly backgroundMetrics: { readonly actionLatencyMs: number; @@ -264,6 +266,8 @@ function cancellationEvidence( const preload = ipcPair(input.phaseCapture.ipcSpans, 'dbCancelOperation'); const authoritative = request.responseEpochMs; const painted = requireNumber(renderer.uiPaintedEpochMs); + // Renderer and main sample independent clocks, so allow their correlated + // terminal timestamps to invert only within the known sub-millisecond skew. if ( !dispatch || !receipt || @@ -271,7 +275,8 @@ function cancellationEvidence( dispatch.type !== 'db-cancel-dispatched' || receipt.type !== 'db-cancel-received' || workerTerminal.type !== 'db-cancel-terminal-received' || - renderer.dbCancellationTerminalEpochMs < workerTerminal.epochMs || + renderer.dbCancellationTerminalEpochMs < + workerTerminal.epochMs - CANCELLATION_CLOCK_SKEW_TOLERANCE_MS || renderer.dbCancellationTerminalEpochMs > painted || authoritative > painted ) { diff --git a/apps/electron-backend-e2e/src/performance/xtream-scenario-driver-wiring.spec.ts b/apps/electron-backend-e2e/src/performance/xtream-scenario-driver-wiring.spec.ts index abaa38811..504049d1d 100644 --- a/apps/electron-backend-e2e/src/performance/xtream-scenario-driver-wiring.spec.ts +++ b/apps/electron-backend-e2e/src/performance/xtream-scenario-driver-wiring.spec.ts @@ -145,7 +145,14 @@ describe('Xtream scenario driver source wiring', () => { support, /export async function prearmXtreamDatabaseWorker/ ); - assert.match(support, /window\.electron\.dbGetAppPlaylists\(\)/); + const mainDatabaseReady = support.indexOf( + 'window.electron.downloadsGetList()' + ); + const workerPrearm = support.indexOf( + 'window.electron.dbGetAppPlaylists()' + ); + assert.ok(mainDatabaseReady >= 0); + assert.ok(workerPrearm > mainDatabaseReady); assert.ok(install >= 0); assert.ok(prearm > install); assert.ok(captureOptions > prearm);