diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 58c18ae68d7..2a612c5b922 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1301,9 +1301,10 @@ jobs: # vitest runs here directly rather than through `pnpm test`, so the addon # assertions only hold once install-node-dependencies has rebuilt natives. - name: Test Windows installer process probe - # Keep cold CIM startup out of the concurrent Electron/native process workload. + # Serialize the two suites so their cold PowerShell/CIM starts cannot contend. run: >- pnpm exec vitest run --config config/vitest.config.ts + --no-file-parallelism config/scripts/nsis-process-check.test.mjs config/scripts/idle-cpu-process-sampling.test.mjs diff --git a/config/scripts/ci-shard-assignment.test.mjs b/config/scripts/ci-shard-assignment.test.mjs index 3baedc084e9..a2c4729cade 100644 --- a/config/scripts/ci-shard-assignment.test.mjs +++ b/config/scripts/ci-shard-assignment.test.mjs @@ -63,7 +63,7 @@ describe('timing-weighted shard selection', () => { expect(new Set(selected)).toEqual(new Set(specs)) }) - it('keeps global sharding and runs the Node measurement after ordinary projects', async () => { + it('keeps global sharding and isolates measurements after ordinary projects', async () => { vi.stubEnv('ORCA_BALANCE_UNIT_SHARDS', '1') const { default: config } = await import('../vitest.config') expect(config.test.sequence.sequencer).toBe(TimingSequencer) @@ -72,7 +72,12 @@ describe('timing-weighted shard selection', () => { 'src/main/foreign-sqlite-readers/foreign-sqlite-reader-event-loop.test.ts' const projects = config.test.projects const measurement = projects.filter((project) => project.test.name === 'node-measurement') - const ordinary = projects.filter((project) => project.test.name !== 'node-measurement') + const paletteMeasurementFile = + 'src/renderer/src/lib/palette-match/palette-match-performance.test.ts' + const paletteMeasurement = projects.filter( + (project) => project.test.name === 'palette-measurement' + ) + const ordinary = projects.filter((project) => project.test.sequence.groupOrder === 1) expect(measurement).toHaveLength(1) expect(ordinary).toHaveLength(process.versions.bun ? 2 : 1) expect(measurement[0].test).toMatchObject({ @@ -84,9 +89,21 @@ describe('timing-weighted shard selection', () => { pool: process.versions.bun ? 'node-runtime' : 'forks' }) expect(measurement[0].test.poolRunner).toBe(process.versions.bun ? nodeRuntimePool : undefined) + expect(paletteMeasurement).toHaveLength(1) + expect(paletteMeasurement[0].test).toMatchObject({ + include: [paletteMeasurementFile], + exclude: UNIT_EXCLUDE, + maxWorkers: 1, + sequence: { groupOrder: 3 }, + env: { ORCA_VITEST_RUNTIME: process.versions.bun ? 'bun' : 'node' }, + pool: 'forks' + }) + expect(paletteMeasurement[0].test.poolRunner).toBeUndefined() for (const project of ordinary) { expect(project.test.sequence.groupOrder).toBe(1) - expect(project.test.exclude).toContain(measurementFile) + expect(project.test.exclude).toEqual( + expect.arrayContaining([measurementFile, paletteMeasurementFile]) + ) } const ordinaryNode = ordinary.find((project) => project.test.name !== 'bun') expect(ordinaryNode.test.include).toEqual( diff --git a/config/vitest.config.ts b/config/vitest.config.ts index eab4441b407..6af92217a6e 100644 --- a/config/vitest.config.ts +++ b/config/vitest.config.ts @@ -9,6 +9,9 @@ import { createWorkspaceSourceResolver } from './scripts/workspace-source-export const balancedShards = process.env.ORCA_BALANCE_UNIT_SHARDS === '1' const measurementFile = 'src/main/foreign-sqlite-readers/foreign-sqlite-reader-event-loop.test.ts' +const paletteMeasurementFile = + 'src/renderer/src/lib/palette-match/palette-match-performance.test.ts' +const measurementFiles = [measurementFile, paletteMeasurementFile] const transforms = { define: { ORCA_FEATURE_WALL_ENABLED: 'true', @@ -59,30 +62,28 @@ const nodeProject = { name: process.versions.bun ? 'node-runtime' : 'node', env: { ORCA_VITEST_RUNTIME: process.versions.bun ? 'node-runtime' : 'node' }, include: process.versions.bun ? NODE_RUNTIME_INCLUDE : UNIT_INCLUDE, - exclude: [...testOptions.exclude, measurementFile], + exclude: [...testOptions.exclude, ...measurementFiles], sequence: { groupOrder: 1 }, ...(process.versions.bun ? { pool: 'node-runtime', poolRunner: nodeRuntimePool } : { pool: 'forks' }) } } +const bunProject = { + extends: false, + ...transforms, + test: { + ...testOptions, + name: 'bun', + env: { ORCA_VITEST_RUNTIME: 'bun' }, + pool: 'forks', + exclude: [...testOptions.exclude, ...NODE_RUNTIME_INCLUDE, ...measurementFiles], + sequence: { groupOrder: 1 } + } +} +const paletteRuntimeProject = process.versions.bun ? bunProject : nodeProject const projects = [ - ...(process.versions.bun - ? [ - { - extends: false, - ...transforms, - test: { - ...testOptions, - name: 'bun', - env: { ORCA_VITEST_RUNTIME: 'bun' }, - pool: 'forks', - exclude: [...testOptions.exclude, ...NODE_RUNTIME_INCLUDE, measurementFile], - sequence: { groupOrder: 1 } - } - } - ] - : []), + ...(process.versions.bun ? [bunProject] : []), nodeProject, // Keep the event-loop measurement free of other suites without weakening its limits. { @@ -95,6 +96,18 @@ const projects = [ maxWorkers: 1, sequence: { groupOrder: 2 } } + }, + // Preserve the palette test's runtime and budgets while keeping other suites off its CPU. + { + ...paletteRuntimeProject, + test: { + ...paletteRuntimeProject.test, + name: 'palette-measurement', + include: [paletteMeasurementFile], + exclude: testOptions.exclude, + maxWorkers: 1, + sequence: { groupOrder: 3 } + } } ]