Files
orca/config/scripts/release-desktop-timing.test.mjs
T
Neil 309d71c003 Build adhoc Mac architectures in parallel (#31415)
* Parallelize adhoc Mac architecture packaging

* Include parallel Mac jobs in release timing reports

* Cover parallel Mac publication and failure gates

* Explicitly scope archive targets to each Mac architecture
2026-10-20 22:30:47 -07:00

134 lines
5.3 KiB
JavaScript

import { describe, expect, it } from 'vitest'
import {
compareReleaseDesktopTiming,
summarizeReleaseDesktopTiming
} from './release-desktop-timing.mjs'
const at = (seconds) => new Date(Date.UTC(2026, 0, 1) + seconds * 1000).toISOString()
function job(name, start, end, firstStep = start, steps = []) {
return {
name,
conclusion: 'success',
startedAt: at(start),
completedAt: at(end),
steps: [
{
name: 'Set up job',
conclusion: 'success',
startedAt: at(firstStep),
completedAt: at(firstStep + 1)
},
...steps
]
}
}
function run(windows, macStart = 20, macEnd = 100) {
return {
status: 'completed',
conclusion: 'success',
createdAt: at(0),
jobs: [
job('orcad-template-support', 2, 3),
job('orcad-template / desktop_template', 3, 10),
job('build-adhoc-mac', macStart, macEnd),
...windows
]
}
}
describe('release desktop timing evidence', () => {
it('measures the sequential baseline and actual candidate overlap without counting queue timestamps as execution', () => {
const baseline = run([job('build-adhoc-win / build-win', 100, 160, 110)])
const candidate = run([
job('build-adhoc-win / build-win', 10, 75, 25),
job('publish-adhoc-win / publish-win', 100, 110, 101)
])
const report = compareReleaseDesktopTiming(baseline, candidate)
expect(report.baseline.measuredSeconds.desktopJobOverlap).toBe(0)
expect(report.candidate.measuredSeconds.desktopJobOverlap).toBe(50)
expect(report.candidate.measuredSeconds.desktop).toBe(90)
expect(report.measuredSavingsSeconds.desktop).toBe(50)
expect(report.candidate.desktopJobs[1].reportedStartToFirstStepSeconds).toBe(15)
expect(report.candidate.measuredSeconds.templateReadyToWindowsFirstStep).toBe(15)
})
it('unions intersecting Windows intervals and ignores skipped jobs and skipped step timestamps', () => {
const windows = job('build-adhoc-win / build-win', 10, 80, 30)
windows.steps.unshift({ name: 'Skipped', conclusion: 'skipped', startedAt: at(10) })
const input = run([windows, job('publish-adhoc-win / publish-win', 70, 90)])
input.jobs.push({ name: 'build-adhoc-win-old', conclusion: 'skipped', steps: [] })
const report = summarizeReleaseDesktopTiming(input)
expect(report.measuredSeconds.desktopJobOverlap).toBe(60)
expect(report.measuredSeconds.windowsJobTotal).toBe(70)
})
it('retains measured step evidence and leaves missing phases unknown', () => {
const input = run([
job('build-adhoc-win / build-win', 100, 170, 100, [
{ name: 'Build app', conclusion: 'success', startedAt: at(101), completedAt: at(131) },
{
name: 'Publish Windows artifacts',
conclusion: 'success',
startedAt: at(131),
completedAt: at(160)
}
])
])
const report = summarizeReleaseDesktopTiming(input)
expect(report.windowsPhases.appBuild.seconds).toBe(30)
expect(report.windowsPhases.packagingAndUpload.seconds).toBe(29)
expect(report.windowsPhases.dependencies.seconds).toBeNull()
expect(report.windowsPhases.appBuild.steps[0].job).toBe('build-adhoc-win / build-win')
})
it('accounts for packaging and the extra artifact handoff in a split Windows build', () => {
const step = (name, start, end) => ({
name,
conclusion: 'success',
startedAt: at(start),
completedAt: at(end)
})
const report = summarizeReleaseDesktopTiming(
run([
job('stage-adhoc-win / build-win', 20, 80, 20, [
step('Package Windows artifacts without publishing', 30, 60),
step('Stage Windows artifacts for gated publishing', 60, 70)
]),
job('publish-adhoc-win / publish-win', 100, 130, 100, [
step('Download the staged Windows artifacts', 101, 111),
step('Publish Windows artifacts', 111, 125)
])
])
)
expect(report.windowsPhases.packagingAndUpload.seconds).toBe(44)
expect(report.windowsPhases.artifactHandoff.seconds).toBe(20)
})
it('includes parallel Mac packaging before the final publication job', () => {
const input = run([job('build-adhoc-win / build-win', 20, 80)], 90, 100)
input.jobs[1].name = 'orcad-template / qualify / desktop_template'
input.jobs.push(job('build-adhoc-mac-arch (x64)', 15, 85, 25))
input.jobs.push(job('build-adhoc-mac-arch (arm64)', 15, 90, 30))
const report = summarizeReleaseDesktopTiming(input)
expect(report.measuredSeconds.macJob).toBe(75)
expect(report.measuredSeconds.desktopJobOverlap).toBe(55)
expect(report.desktopJobs).toHaveLength(4)
input.jobs.at(-1).conclusion = 'failure'
expect(() => summarizeReleaseDesktopTiming(input)).toThrow('Desktop or template job failed')
})
it('rejects incomplete runs, failed desktop jobs, and missing timing evidence', () => {
const input = run([job('build-adhoc-win / build-win', 100, 160)])
expect(() => summarizeReleaseDesktopTiming({ ...input, status: 'in_progress' })).toThrow(
'completed successful run'
)
input.jobs.at(-1).conclusion = 'failure'
expect(() => summarizeReleaseDesktopTiming(input)).toThrow('Desktop or template job failed')
input.jobs.at(-1).conclusion = 'success'
input.jobs.at(-1).steps = []
expect(() => summarizeReleaseDesktopTiming(input)).toThrow('No started steps')
})
})