Files
orca/config/scripts/agent-state-rules-bundle.test.mjs
T

133 lines
5.1 KiB
JavaScript

import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
import {
BUNDLED_AGENT_STATE_RULES_VERSION,
LIVE_UPDATABLE_AGENT_STATE_RULE_IDS,
parseAgentStateRulesBundle
} from '../../src/main/runtime/agent-state-rules/agent-state-rules-bundle.ts'
import { BUNDLED_AGENT_STATE_RULE_FILES } from '../../src/main/runtime/agent-state-rules/agent-state-rules-catalog.ts'
import { agentStateRulesDownloadUrl } from '../../src/main/runtime/agent-state-rules/agent-state-rules-live-update.ts'
import { AGENT_STATE_RULES_ENGINE_VERSION } from '../../src/main/runtime/agent-state-rules/agent-state-rules-schema.ts'
import {
AGENT_STATE_RULES_ASSET,
buildAgentStateRulesBundle,
promoteAgentStateRules,
publishAgentStateRules
} from './agent-state-rules-bundle.mjs'
import { agentStateRulesTag } from './release-tag-patterns.mjs'
const REPO = 'stablyai/orca'
const NEXT = agentStateRulesTag(1, 'next')
const STABLE = agentStateRulesTag(1, 'stable')
describe('agent state rules bundle build', () => {
it('builds a bundle the app accepts, under the bundled version and engine', () => {
const text = buildAgentStateRulesBundle()
const parsed = parseAgentStateRulesBundle(text, 'live-updatable')
expect(parsed.ok).toBe(true)
const bundle = JSON.parse(text)
expect(bundle.engineVersion).toBe(AGENT_STATE_RULES_ENGINE_VERSION)
expect(bundle.version).toBe(BUNDLED_AGENT_STATE_RULES_VERSION)
expect(bundle.files).toEqual(
BUNDLED_AGENT_STATE_RULE_FILES.filter((file) =>
LIVE_UPDATABLE_AGENT_STATE_RULE_IDS.has(file.id)
)
)
expect(bundle.bundledOnly).toBeUndefined()
expect(JSON.parse(buildAgentStateRulesBundle({ bundledOnly: true })).bundledOnly).toBe(true)
})
it('publishes to the exact URL the app fetches', () => {
for (const channel of ['next', 'stable']) {
expect(agentStateRulesDownloadUrl(channel)).toBe(
`https://github.com/${REPO}/releases/download/${agentStateRulesTag(AGENT_STATE_RULES_ENGINE_VERSION, channel)}/${AGENT_STATE_RULES_ASSET}`
)
}
})
})
/** A `gh` stand-in over an in-memory set of releases, recording each call. */
function fakeGh(releases = {}) {
const calls = []
const gh = (args) => {
calls.push(args)
const [, verb, tag] = args
if (verb === 'download') {
return tag in releases
? { status: 0, stdout: releases[tag], stderr: '' }
: { status: 1, stdout: '', stderr: 'release not found' }
}
if (verb === 'upload' || verb === 'create') {
expect(args[3].endsWith(`/${AGENT_STATE_RULES_ASSET}`)).toBe(true)
releases[tag] = readFileSync(args[3], 'utf8')
}
return { status: 0, stdout: '', stderr: '' }
}
return { gh, calls, releases }
}
const at = (version, engineVersion = 1) =>
`${JSON.stringify({ version, engineVersion, files: [] })}\n`
describe('publishAgentStateRules', () => {
it("creates the engine's channel release as a prerelease that can never be Latest", () => {
const fake = fakeGh()
expect(
publishAgentStateRules({
repo: REPO,
channel: 'next',
text: at(2),
target: 'abc',
gh: fake.gh
})
).toEqual({ tag: NEXT, version: 2 })
expect(fake.calls.find((args) => args[1] === 'create')).toEqual(
expect.arrayContaining([NEXT, '--prerelease', '--latest=false', '--target', 'abc'])
)
expect(fake.releases[NEXT]).toBe(at(2))
})
it('replaces the asset in place on an existing release, keeping the tag', () => {
const fake = fakeGh({ [NEXT]: at(1) })
publishAgentStateRules({ repo: REPO, channel: 'next', text: at(2), target: 'abc', gh: fake.gh })
expect(fake.calls.map((args) => args[1])).toEqual(['download', 'upload'])
expect(fake.calls[1]).toContain('--clobber')
expect(fake.releases[NEXT]).toBe(at(2))
})
it.each([1, 2])('refuses version %s over a published 2, uploading nothing', (version) => {
const fake = fakeGh({ [NEXT]: at(2) })
expect(() =>
publishAgentStateRules({
repo: REPO,
channel: 'next',
text: at(version),
target: 'abc',
gh: fake.gh
})
).toThrow('bump agent-state-rules-release.json')
expect(fake.calls.map((args) => args[1])).toEqual(['download'])
})
it('fails when the release exists but its download fails', () => {
const gh = () => ({ status: 1, stdout: '', stderr: 'no assets match the file pattern' })
expect(() =>
publishAgentStateRules({ repo: REPO, channel: 'next', text: at(2), target: 'abc', gh })
).toThrow('no assets match')
})
it('promotes the identical next bytes to stable', () => {
const nextText = JSON.stringify({ version: 3, engineVersion: 1, files: [] }, null, 2)
const fake = fakeGh({ [NEXT]: nextText, [STABLE]: at(2) })
promoteAgentStateRules({ repo: REPO, engineVersion: 1, target: 'abc', gh: fake.gh })
expect(fake.releases[STABLE]).toBe(nextText)
})
it('refuses to promote before next exists', () => {
const fake = fakeGh()
expect(() =>
promoteAgentStateRules({ repo: REPO, engineVersion: 1, target: 'abc', gh: fake.gh })
).toThrow('has not been published')
})
})