codeburn/app/scripts/verify-windows-installer.test.ts
2026-08-13 20:01:00 +05:30

168 lines
5.7 KiB
TypeScript

import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import { rootFromModuleUrl } from './windows-installer-paths.mjs'
const verifier = new URL('./verify-windows-installer.mjs', import.meta.url)
const verifierPath = fileURLToPath(verifier)
function fixture(options: {
appVersion?: string
rootVersion?: string
files?: string[]
tag?: string
} = {}) {
const root = mkdtempSync(join(tmpdir(), 'codeburn-windows-manifest-'))
const appDir = join(root, 'app')
const releaseDir = join(appDir, 'release')
mkdirSync(releaseDir, { recursive: true })
const appVersion = options.appVersion ?? '1.2.3'
writeFileSync(join(root, 'package.json'), JSON.stringify({ version: options.rootVersion ?? appVersion }))
writeFileSync(join(appDir, 'package.json'), JSON.stringify({ version: appVersion }))
for (const file of options.files ?? [
`CodeBurn-Setup-${appVersion}.exe`,
`CodeBurn-Setup-${appVersion}.exe.blockmap`,
]) {
const path = join(releaseDir, file)
mkdirSync(join(path, '..'), { recursive: true })
writeFileSync(path, 'fixture')
}
const args = [verifierPath, '--root', root, '--artifacts', releaseDir]
if (options.tag) args.push('--tag', options.tag)
return spawnSync(process.execPath, args, { encoding: 'utf8' })
}
function releaseFixture(files: string[]) {
const root = mkdtempSync(join(tmpdir(), 'codeburn-windows-release-'))
const assets = join(root, 'assets.json')
writeFileSync(assets, JSON.stringify(files))
return spawnSync(process.execPath, [
verifierPath,
'--tag',
'desktop-v1.2.3',
'--release-assets',
assets,
], { encoding: 'utf8' })
}
describe('Windows installer release manifest verifier', () => {
it('converts a Windows module URL into a valid drive-letter repository root', () => {
expect(rootFromModuleUrl(
'file:///D:/a/codeburn/codeburn/app/scripts/verify-windows-installer.mjs',
true,
)).toBe('D:\\a\\codeburn\\codeburn')
})
it('accepts one exact installer and blockmap for matching package versions and tag', () => {
const result = fixture({ tag: 'desktop-v1.2.3' })
expect(result.status).toBe(0)
expect(result.stdout).toContain('Windows installer manifest verified for 1.2.3')
})
it('rejects a desktop tag that does not match the app version', () => {
const result = fixture({ tag: 'desktop-v1.2.4' })
expect(result.status).toBe(1)
expect(result.stderr).toContain('desktop-v1.2.4 does not match app version 1.2.3')
})
it('rejects divergent root and app versions', () => {
const result = fixture({ rootVersion: '1.2.2' })
expect(result.status).toBe(1)
expect(result.stderr).toContain('root version 1.2.2 does not match app version 1.2.3')
})
it('rejects a missing installer blockmap', () => {
const result = fixture({ files: ['CodeBurn-Setup-1.2.3.exe'] })
expect(result.status).toBe(1)
expect(result.stderr).toContain('expected exactly one CodeBurn-Setup-1.2.3.exe.blockmap, found 0')
})
it('requires installer artifacts at the documented top-level output', () => {
const result = fixture({
files: [
'CodeBurn-Setup-1.2.3.exe.blockmap',
'duplicate/CodeBurn-Setup-1.2.3.exe',
],
})
expect(result.status).toBe(1)
expect(result.stderr).toContain('expected exactly one CodeBurn-Setup-1.2.3.exe, found 0')
})
it('rejects stale installer artifacts from another version', () => {
const result = fixture({
files: [
'CodeBurn-Setup-1.2.3.exe',
'CodeBurn-Setup-1.2.3.exe.blockmap',
'CodeBurn-Setup-1.2.2.exe',
'CodeBurn-Setup-1.2.2.exe.blockmap',
],
})
expect(result.status).toBe(1)
expect(result.stderr).toContain('unexpected Windows installer artifacts')
})
it('accepts a complete live desktop release asset manifest', () => {
const result = releaseFixture([
'CodeBurn-1.2.3-arm64.dmg',
'CodeBurn-1.2.3.dmg',
'CodeBurn-1.2.3-arm64-mac.zip',
'CodeBurn-1.2.3-mac.zip',
'CodeBurn-1.2.3.AppImage',
'codeburn-desktop_1.2.3_amd64.deb',
'codeburn-desktop-1.2.3.x86_64.rpm',
'CodeBurn-Setup-1.2.3.exe',
'CodeBurn-Setup-1.2.3.exe.blockmap',
])
expect(result.status).toBe(0)
expect(result.stdout).toContain('Live desktop release assets verified for 1.2.3')
})
it('rejects a live desktop release missing the Windows installer', () => {
const result = releaseFixture([
'CodeBurn-1.2.3-arm64.dmg',
'CodeBurn-1.2.3.dmg',
'CodeBurn-1.2.3-arm64-mac.zip',
'CodeBurn-1.2.3-mac.zip',
'CodeBurn-1.2.3.AppImage',
'codeburn-desktop_1.2.3_amd64.deb',
'codeburn-desktop-1.2.3.x86_64.rpm',
'CodeBurn-Setup-1.2.3.exe.blockmap',
])
expect(result.status).toBe(1)
expect(result.stderr).toContain('live release is missing CodeBurn-Setup-1.2.3.exe')
})
it.each([
'codeburn-desktop_1.2.3_amd64.deb',
'codeburn-desktop-1.2.3.x86_64.rpm',
])('rejects a live desktop release missing %s', missing => {
const required = [
'CodeBurn-1.2.3-arm64.dmg',
'CodeBurn-1.2.3.dmg',
'CodeBurn-1.2.3-arm64-mac.zip',
'CodeBurn-1.2.3-mac.zip',
'CodeBurn-1.2.3.AppImage',
'codeburn-desktop_1.2.3_amd64.deb',
'codeburn-desktop-1.2.3.x86_64.rpm',
'CodeBurn-Setup-1.2.3.exe',
'CodeBurn-Setup-1.2.3.exe.blockmap',
]
const result = releaseFixture(required.filter(asset => asset !== missing))
expect(result.status).toBe(1)
expect(result.stderr).toContain(`live release is missing ${missing}`)
})
})