Files
orca/config/scripts/linux-package-fixture-cache.test.mjs
T
OrcaWinandOrcaWin 1864543ade ci: warm GitHub-hosted runner caches and drop the serve-switch installer cache (#34576)
* ci: warm hosted runner caches and drop the serve-switch installer cache

* ci: seed only restored caches from hosted warm legs

* docs(ci): hosted dev builds and no larger runners

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 15:33:07 -07:00

196 lines
7.9 KiB
JavaScript

import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { runInNewContext } from 'node:vm'
import { delimiter, join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { parse } from 'yaml'
import { runProcessSync } from '@orca/process-host'
import { classifyPrJobs } from './pr-code-change-scope.mjs'
const action = parse(
readFileSync('.github/actions/prepare-linux-package-fixture/action.yml', 'utf8')
)
const load = action.runs.steps.find((step) => step.id === 'image')
const workflow = (name) => parse(readFileSync(`.github/workflows/${name}.yml`, 'utf8'))
let directory
afterEach(() => {
if (directory) {
rmSync(directory, { recursive: true, force: true })
}
})
function exercise({
hit = false,
save = false,
loadFails = false,
inspectFails = false,
fixture = 'cli-launch-contract'
} = {}) {
directory = mkdtempSync(join(tmpdir(), 'orca-package-cache-'))
const bin = join(directory, 'bin')
mkdirSync(bin)
const commandLog = join(directory, 'commands')
const output = join(directory, 'output')
writeFileSync(commandLog, '')
writeFileSync(output, '')
const docker = join(bin, 'docker')
writeFileSync(
docker,
'#!/bin/bash\n' +
'echo "$*" >> "$COMMAND_LOG"\n' +
'if [[ "$1" == load && "$LOAD_FAILS" == true ]]; then exit 1; fi\n' +
'if [[ "$1 $2" == "image inspect" ]]; then\n' +
' if [[ "$INSPECT_FAILS" == true ]]; then exit 1; fi\n' +
' echo sha256:fixture-image\n' +
'fi\n'
)
chmodSync(docker, 0o755)
const result = runProcessSync({
program: 'bash',
args: ['-c', load.run],
env: {
...process.env,
ORCA_BACKGROUND_LAUNCH: '1',
PATH: `${bin}${delimiter}${process.env.PATH ?? ''}`,
GITHUB_ACTION_PATH: join(process.cwd(), '.github/actions/prepare-linux-package-fixture'),
RUNNER_TEMP: directory,
GITHUB_OUTPUT: output,
COMMAND_LOG: commandLog,
FIXTURE: fixture,
CACHE_HIT: String(hit),
SAVE_CACHE: String(save),
LOAD_FAILS: String(loadFails),
INSPECT_FAILS: String(inspectFails)
},
timeoutMs: 10_000
})
expect(result.code, result.stderr).toBe(0)
return { commands: readFileSync(commandLog, 'utf8'), output: readFileSync(output, 'utf8') }
}
describe.runIf(process.platform !== 'win32')('fixture cache fallbacks', () => {
it('leaves a PR cache miss to the existing runner without building or exporting', () => {
expect(exercise()).toEqual({ commands: '', output: '' })
})
it.each([{ loadFails: true }, { inspectFails: true }])(
'discards an unusable restored cache: %j',
(failure) => {
const result = exercise({ hit: true, ...failure })
expect(result.output).toBe('')
expect(result.commands).toContain('load --input')
expect(result.commands).not.toMatch(/(?:build|save) /)
}
)
it('returns the local image tag after a successful load', () => {
const result = exercise({ hit: true })
expect(result.output).toBe('image=orca-package-fixture-cli-launch-contract:cache\n')
expect(result.commands).not.toMatch(/(?:build|save) /)
})
it('loads the daemon shutdown fixture without running package or source tests in the cache action', () => {
const result = exercise({ hit: true, fixture: 'daemon-shutdown-descendants' })
expect(result.output).toBe('image=orca-package-fixture-daemon-shutdown-descendants:cache\n')
expect(result.commands).not.toMatch(/(?:build|save|run) /)
})
it('builds and exports inline cache only when the warmer has no usable image', () => {
const result = exercise({ save: true })
expect(result.commands).toContain(
'build --platform linux/amd64 --build-arg BUILDKIT_INLINE_CACHE=1'
)
expect(result.commands).toContain(
'--file config/docker/cli-launch-contract/Dockerfile config/docker/cli-launch-contract'
)
expect(result.commands).toContain('save --output')
expect(result.output).toBe('image=orca-package-fixture-cli-launch-contract:cache\nbuilt=true\n')
})
})
it('uses exact context/platform keys and the same restore-only action in package checks', () => {
const cache = action.runs.steps.find((step) => step.id === 'cache')
expect(cache.with.key).toContain('linux-amd64')
expect(cache.with.key).toContain("format('config/docker/{0}/**', inputs.fixture)")
expect(cache.with.key).toContain('.github/actions/prepare-linux-package-fixture/action.yml')
expect(cache.with.key).toContain('.github/actions/prepare-linux-package-fixture/load-fixture.sh')
expect(cache.with['restore-keys']).toBeUndefined()
expect(action.inputs['save-cache'].default).toBe('false')
const prepared = workflow('pr').jobs.package.steps.filter((step) =>
step.uses?.endsWith('/prepare-linux-package-fixture')
)
expect(prepared.map((step) => step.with)).toEqual([
{ fixture: 'daemon-shutdown-descendants', load: 'false' },
{ fixture: 'headless-serve-shutdown', load: 'false' },
{ fixture: 'cli-launch-contract', load: 'false' }
])
const steps = workflow('pr').jobs.package.steps
for (const restore of prepared) {
// Only the single load step runs in the background; the restore action stays foreground.
const loader = steps.find((step) => step.env?.CACHE_HIT?.includes(`steps.${restore.id}.`))
expect(restore.background).toBeUndefined()
expect(loader).toMatchObject({
id: restore.id.replace(/-restore$/, ''),
background: true,
env: { FIXTURE: restore.with.fixture },
run: 'bash .github/actions/prepare-linux-package-fixture/load-fixture.sh'
})
expect(steps.indexOf(loader)).toBe(steps.findIndex((step) => step.id === restore.id) + 1)
}
const platformSource = workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses
const warm = parse(readFileSync(platformSource, 'utf8')).jobs['warm-linux-package-fixtures']
expect(warm.steps.slice(1).map((step) => step.with.fixture)).toEqual(
prepared.map((step) => step.with.fixture)
)
expect(
warm.steps
.slice(1)
.every((step) => step.with['save-cache'] === "${{ github.event_name != 'pull_request' }}")
).toBe(true)
})
it.each([
['pull_request', false],
['push', true],
['schedule', true],
['workflow_dispatch', true]
])('keeps fixture seeding available without a redundant PR runner on %s', (event, runs) => {
const source = workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses
const warm = parse(readFileSync(source, 'utf8')).jobs['warm-linux-package-fixtures']
const context = { github: { event_name: event } }
expect(warm['runs-on']).toBe('${{ matrix.runner }}')
expect(warm.strategy.matrix.runner).toEqual(['blacksmith-4vcpu-ubuntu-2404', 'ubuntu-24.04'])
expect(warm.steps.map((step) => step.uses)).toEqual([
'actions/checkout@v6',
'./.github/actions/prepare-linux-package-fixture',
'./.github/actions/prepare-linux-package-fixture',
'./.github/actions/prepare-linux-package-fixture'
])
expect(runInNewContext(warm.if, context)).toBe(runs)
for (const step of warm.steps.slice(1)) {
expect(runInNewContext(step.with['save-cache'].slice(3, -2), context)).toBe(runs)
}
const consumers = workflow('pr').jobs.package.steps.filter((step) =>
step.uses?.endsWith('/prepare-linux-package-fixture')
)
expect(consumers.every((step) => step.with['save-cache'] === undefined)).toBe(true)
expect(consumers.map((step) => step.with.fixture)).toEqual(
warm.steps.slice(1).map((step) => step.with.fixture)
)
})
it.each([
'.github/actions/prepare-linux-package-fixture/action.yml',
'.github/actions/prepare-linux-package-fixture/load-fixture.sh',
'config/docker/daemon-shutdown-descendants/Dockerfile',
'config/docker/headless-serve-shutdown/Dockerfile',
'config/docker/cli-launch-contract/Dockerfile'
])('validates a changed fixture in Linux packaging: %s', (file) => {
expect(classifyPrJobs([file])).toMatchObject({
test: true,
package: true,
package_windows: false
})
})