Files
orca/src/main/node-runtime/managed-runtime-installation.test.ts
T
NeilandJinwoo-H e7b0e4029e fix(antigravity): say why a downloaded chat runtime failed its start check (#39456)
The managed-runtime install message now names the observed cause after the
existing headline: a timeout, an exit code with a redacted stderr excerpt, or
the version the server answered as. The host agy check that shares the
initialize helper is unchanged.

Takes over #34167 by @Jinwoo-H (away), ported onto main after #39006.

Co-authored-by: Jinwoo-H <73622457+Jinwoo-H@users.noreply.github.com>
2026-11-07 03:17:56 -08:00

138 lines
5.2 KiB
TypeScript

import { createHash } from 'node:crypto'
import { mkdtemp, readdir, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { strToU8, zipSync } from 'fflate'
import { afterEach, expect, it, vi } from 'vitest'
import type * as ReleaseModule from './managed-runtime-release'
import {
ManagedRuntimeStartError,
RUNTIME_RELEASE_RECEIPT,
type ManagedRuntime
} from './managed-runtime-release'
import { ManagedRuntimeInstallation } from './managed-runtime-installation'
vi.mock('./managed-runtime-release', async (importOriginal) => {
const actual = await importOriginal<typeof ReleaseModule>()
return { ...actual, reclaimRuntimeReleases: vi.fn(actual.reclaimRuntimeReleases) }
})
const sha256 = (bytes: string | Uint8Array) => createHash('sha256').update(bytes).digest('hex')
const ARCHIVE = zipSync({ server: strToU8('server bytes') })
const roots: string[] = []
afterEach(() => Promise.all(roots.splice(0).map((r) => rm(r, { recursive: true, force: true }))))
async function rig(bodies: ('hang' | 'whole')[], validate?: ManagedRuntime['validate']) {
const dataDirectory = await mkdtemp(join(tmpdir(), 'orca-runtime-install-'))
roots.push(dataDirectory)
const root = join(dataDirectory, 'agent-runtimes', 'agent')
const pin = {
version: '1.0',
url: 'https://example.test/agent-1.0.zip',
archiveSha256: sha256(ARCHIVE),
archiveBytes: ARCHIVE.length,
members: [{ path: 'server', sha256: sha256('server bytes'), bytes: 12 }]
}
const runtime = { label: 'Agent', root: () => root, pin: () => pin, validate }
const fetcher = async () => {
const body = bodies.shift()
return new Response(
new ReadableStream({
start(controller) {
controller.enqueue(ARCHIVE.slice(0, 5))
if (body === 'whole') {
controller.enqueue(ARCHIVE.slice(5))
controller.close()
}
}
})
)
}
const host = () =>
new ManagedRuntimeInstallation('agent', runtime, {
dataDirectory,
findExternal: async () => false,
fence: (work) => work(),
fetcher
})
const phase = async (installation: ManagedRuntimeInstallation) =>
(await installation.status()).operation?.phase
return { root, host, phase }
}
it('installs only when asked, with progress, cancel, retry, and a status read from disk', async () => {
const { root, host, phase } = await rig(['hang', 'whole'])
const installation = host()
expect(await installation.status()).toMatchObject({ installedVersion: null, source: null })
const started = installation.install()
await vi.waitFor(async () =>
expect((await installation.status()).operation?.downloadedBytes).toBe(5)
)
expect(installation.install().id).toBe(started.id)
expect(await installation.cancel(started.id)).toMatchObject({ phase: 'cancelled' })
expect(await readdir(root)).toEqual([])
expect(installation.install().id).not.toBe(started.id)
await vi.waitFor(async () => expect(await phase(installation)).toBe('succeeded'))
expect(await host().status()).toMatchObject({
installedVersion: '1.0',
installedCurrent: true,
source: 'managed',
operation: null
})
expect(await readdir(root)).toEqual(['1.0'])
await rm(join(root, '1.0', RUNTIME_RELEASE_RECEIPT))
expect(await installation.status()).toMatchObject({ damaged: true })
const rewrite = installation.install()
await vi.waitFor(async () =>
expect((await installation.status()).operation).toMatchObject({
id: rewrite.id,
phase: 'succeeded'
})
)
expect(await installation.status()).toMatchObject({ installedCurrent: true })
})
it('repairs a damaged copy when Install is clicked again', async () => {
const { root, host, phase } = await rig(['whole', 'whole'])
const installation = host()
installation.install()
await vi.waitFor(async () => expect(await phase(installation)).toBe('succeeded'))
await writeFile(join(root, '1.0', 'server'), 'cut')
expect(await installation.status()).toMatchObject({
installedVersion: null,
damaged: true,
canRemove: true
})
installation.install()
await vi.waitFor(async () => expect(await phase(installation)).toBe('succeeded'))
const repaired = await installation.status()
expect(repaired).toMatchObject({ installedVersion: '1.0', installedCurrent: true })
expect(repaired.damaged).toBeUndefined()
expect(await readdir(root)).toEqual(['1.0'])
})
it.each([
['at the excerpt boundary', `${'x'.repeat(220)} ghp_${'a'.repeat(36)}`],
['with terminal formatting', `ghp_${'a'.repeat(18)}\u001b[0m${'a'.repeat(18)}`]
])('redacts secrets %s in a failed start diagnostic', async (_label, stderr) => {
const { root, host, phase } = await rig(['whole'], async () => {
throw new ManagedRuntimeStartError('Start failed', {
kind: 'exit',
exit: { code: 3, signal: null, processless: false },
stderr
})
})
const installation = host()
installation.install()
await vi.waitFor(async () => expect(await phase(installation)).toBe('failed'))
const { operation, installedVersion } = await installation.status()
expect(operation?.error).toContain('It exited with code 3:')
expect(operation?.error).not.toContain('ghp_')
expect(installedVersion).toBeNull()
expect(await readdir(root)).toEqual([])
})