Files
orca/config/scripts/release/versioning/hourly-build-version.test.mjs
T
Neil 9bd6272fdf refactor(tooling): organize build, CI, and test owners (#38130)
* refactor(tooling): organize test runtime and maintenance owners

* test(tooling): preserve relocated runtime fixture dependency edges

* refactor(tooling): preserve xterm routing owner checks

* ci(tooling): include routing owner in sparse checkout

* test(tooling): preserve copied workflow dependency closures

* fix(tooling): normalize hashed JSON assets in release parity

* fix(tooling): distinguish asset aliases from literal references

* fix(tooling): frame normalized asset reference payloads

* fix(tooling): normalize decoded JSON asset references

* refactor(tooling): organize build, CI and release owners

* fix(tooling): align moved generator and workflow path contracts

* fix(tooling): update generated plugin bundle owner banners

* test(tooling): create relocated mobile verifier fixture directories

* test(tooling): copy headless detector dependency closure

* test(tooling): align native batch policy fixtures with owner path

* fix(tooling): link moved reliability command to historical evidence

* fix(tooling): preserve nested sandbox owners and canonical guide source

* fix(tooling): target release version owners in checkout fixture
2026-11-04 21:08:19 -08:00

134 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import {
createHourlyBuildVersion,
formatHourlyReleaseName,
getHourlyBuildIdentity,
nextHourlyBuildNumber
} from './hourly-build-version.mjs'
import { compareAppVersions } from '../../../../src/shared/app-version'
describe('createHourlyBuildVersion', () => {
it('stamps the version with a zero-padded UTC timestamp', () => {
expect(createHourlyBuildVersion('1.4.160', new Date('2026-07-28T04:05:00Z'))).toBe(
'1.4.160-hourly.202607280405'
)
})
// RC-tail hourlies outrank RC; drop tail so routine checks cannot offer untested builds over RC/stable.
it('drops an in-flight rc tail so hourlies never outrank the rc series', () => {
const version = createHourlyBuildVersion('1.4.160-rc.3', new Date('2026-07-28T14:00:00Z'))
expect(version).toBe('1.4.160-hourly.202607281400')
expect(compareAppVersions(version, '1.4.160-rc.3')).toBeLessThan(0)
})
it('rejects invalid input', () => {
expect(() => createHourlyBuildVersion('nope', new Date())).toThrow(/valid semver/)
expect(() => createHourlyBuildVersion('1.4.160', new Date('nope'))).toThrow(/invalid/)
})
})
describe('formatHourlyReleaseName', () => {
const name = (iso, buildNumber = 1, commit = 'e698241abcde') =>
formatHourlyReleaseName('1.4.163-hourly.x', buildNumber, commit, new Date(iso))
it('renders version, number, Pacific timestamp, and short sha', () => {
expect(name('2026-07-31T20:54:00Z')).toBe('1.4.163 • 01 • Jul 31, 1:54PM • e698241')
})
// Tag is UTC, title Pacific; test both DST offsets to catch seasonal failures.
it('follows the Pacific offset across DST', () => {
expect(name('2026-01-15T02:30:00Z')).toBe('1.4.163 • 01 • Jan 14, 6:30PM • e698241')
expect(name('2026-07-31T07:00:00Z')).toBe('1.4.163 • 01 • Jul 31, 12:00AM • e698241')
})
it('renders noon as 12', () => {
expect(name('2026-07-31T19:00:00Z')).toContain('12:00PM')
})
it('pads to two digits and grows past them', () => {
expect(name('2026-07-31T20:54:00Z', 9)).toContain(' • 09 • ')
expect(name('2026-07-31T20:54:00Z', 42)).toContain(' • 42 • ')
expect(name('2026-07-31T20:54:00Z', 1234)).toContain(' • 1234 • ')
})
it('rejects a build number that is not a positive integer', () => {
expect(() => name('2026-07-31T20:54:00Z', 0)).toThrow(/positive integer/)
expect(() => name('2026-07-31T20:54:00Z', -1)).toThrow(/positive integer/)
expect(() => name('2026-07-31T20:54:00Z', 1.5)).toThrow(/positive integer/)
expect(() => name('2026-07-31T20:54:00Z', Number.NaN)).toThrow(/positive integer/)
})
it('rejects an invalid timestamp', () => {
expect(() => formatHourlyReleaseName('1.4.163', 1, 'abcdefg', new Date('nope'))).toThrow(
/invalid/
)
})
})
describe('nextHourlyBuildNumber', () => {
const titles = [
'1.4.163 • 01 • Jul 31, 1:54PM • e698241',
'1.4.163 • 02 • Jul 31, 2:54PM • aaaaaaa',
'1.4.163 • 37 • Aug 01, 9:00AM • bbbbbbb'
]
it('continues the series for the version being built', () => {
expect(nextHourlyBuildNumber('1.4.163', titles)).toBe(38)
})
// New patch starts at 01 instead of inheriting unrelated prior-patch build count.
it('restarts at 1 when the base version moves', () => {
expect(nextHourlyBuildNumber('1.4.164', titles)).toBe(1)
expect(
nextHourlyBuildNumber('1.4.164', [...titles, '1.4.164 • 01 • Aug 02, 8:00AM • ccccccc'])
).toBe(2)
})
// Retention pruning shrinks count; max avoids reissuing numbers.
it('takes the highest number, not the count', () => {
expect(nextHourlyBuildNumber('1.4.163', ['1.4.163 • 09 • Jul 31, 1:54PM • e698241'])).toBe(10)
})
it('starts at 1 with no history at all', () => {
expect(nextHourlyBuildNumber('1.4.163')).toBe(1)
expect(nextHourlyBuildNumber('1.4.163', [])).toBe(1)
})
// Legacy raw-tag titles must not make 1.4.16 match 1.4.163’s series.
it('ignores titles that are not this version', () => {
expect(nextHourlyBuildNumber('1.4.16', ['1.4.163 • 37 • Aug 01, 9:00AM • bbbbbbb'])).toBe(1)
expect(nextHourlyBuildNumber('1.4.163', ['v1.4.163-hourly.202607311354', null, ''])).toBe(1)
})
})
describe('getHourlyBuildIdentity', () => {
// Deleted stable release must not reset hourlies below installed 1.4.203; retained/channel tags keep floor.
it('stays on the already-shipped hourly base after a buggy main release is unpublished', () => {
const identity = getHourlyBuildIdentity(new Date('2026-09-14T20:00:00Z'), {
packageVersion: '1.4.201',
publishedVersions: [
'v1.4.201',
'v1.4.202',
'v1.4.202-hourly.202609141912',
'v1.4.203-hourly.202609140417'
],
releaseNames: [
'1.4.202 • 14 • Sep 14, 12:12PM • 875b86d',
'1.4.203 • 04 • Sep 13, 9:17PM • 2ce252f'
]
})
expect(identity.version).toBe('1.4.203-hourly.202609142000')
expect(identity.buildNumber).toBe(5)
})
it('keeps a newer package version as the hourly base floor', () => {
const identity = getHourlyBuildIdentity(new Date('2026-09-14T20:00:00Z'), {
packageVersion: '1.4.214',
publishedVersions: ['v1.4.202', 'v1.4.203-hourly.202609140417'],
releaseNames: ['1.4.203 • 04 • Sep 13, 9:17PM • 2ce252f']
})
expect(identity.version).toBe('1.4.214-hourly.202609142000')
expect(identity.buildNumber).toBe(1)
})
})