Files
orca/config/scripts/ci-branch-cache-sweep.test.mjs
T

62 lines
2.6 KiB
JavaScript

import { readFileSync } from 'node:fs'
import { runInNewContext } from 'node:vm'
import { expect, it, vi } from 'vitest'
import { parse } from 'yaml'
const workflow = parse(readFileSync('.github/workflows/ci-branch-cache-sweep.yml', 'utf8'))
const step = workflow.jobs.sweep.steps[0]
const hoursAgo = (hours) => new Date(Date.now() - hours * 3600000).toISOString()
function sweep(caches, { dryRun = false, remove = vi.fn().mockResolvedValue(undefined) } = {}) {
const result = runInNewContext(`(async () => { ${step.with.script} })()`, {
context: { repo: { owner: 'owner', repo: 'repo' } },
github: {
paginate: vi.fn().mockResolvedValue(caches),
rest: { actions: { getActionsCacheList: vi.fn(), deleteActionsCacheById: remove } }
},
core: { info: vi.fn() },
process: { env: { DRY_RUN: String(dryRun) } }
})
return { result, remove }
}
it('runs trusted code on a schedule and only dry-runs by default when dispatched', () => {
expect(Object.keys(workflow.on)).toEqual(['schedule', 'workflow_dispatch'])
expect(workflow.on.workflow_dispatch.inputs.dry_run.default).toBe(true)
expect(workflow.permissions).toEqual({ actions: 'write' })
expect(workflow.jobs.sweep.steps).toHaveLength(1)
expect(step.env.DRY_RUN).toBe("${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}")
})
it('deletes only idle caches on non-default branches', async () => {
const { result, remove } = sweep([
{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) },
{ id: 2, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(1) },
{ id: 3, ref: 'refs/heads/main', last_accessed_at: hoursAgo(48) },
{ id: 4, ref: 'refs/pull/9/merge', last_accessed_at: hoursAgo(48) },
{ id: 5, ref: 'refs/tags/mobile-ios-v1.0.0', last_accessed_at: hoursAgo(48) },
{ id: 6, ref: 'refs/heads/other', last_accessed_at: 'not a date' }
])
await result
expect(remove.mock.calls).toEqual([[{ owner: 'owner', repo: 'repo', cache_id: 1 }]])
})
it('lists without deleting on a dry run', async () => {
const { result, remove } = sweep(
[{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) }],
{ dryRun: true }
)
await result
expect(remove).not.toHaveBeenCalled()
})
it('tolerates an eviction race but surfaces permission failures', async () => {
const idle = [{ id: 1, ref: 'refs/heads/scratch', last_accessed_at: hoursAgo(7) }]
await expect(
sweep(idle, { remove: vi.fn().mockRejectedValue({ status: 404 }) }).result
).resolves.toBeUndefined()
await expect(
sweep(idle, { remove: vi.fn().mockRejectedValue({ status: 403 }) }).result
).rejects.toEqual({ status: 403 })
})