Files
orca/src/cli/index-automation-source-context.test.ts
T
Jinjing 02775968ff Add all-host automations with scoped ownership and multi-authority suppo
Enable automations to run on multiple hosts (SSH targets and local) with
owner-fenced mutations, scoped list queries per host, and conflict
resolution. Introduces desktop and runtime authorities as distinct
automation storage owners, with per-host caching, invalidation, and
retry scheduling on the renderer. Captures registration generations for
SSH hosts to survive re-adoption. Adds CLI support for destination
selection and conflict recovery.
2026-08-23 15:43:11 -07:00

169 lines
4.4 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
const {
callMock,
runtimeClientConstructorMock,
serveOrcaAppMock,
getDefaultUserDataPathMock,
addEnvironmentFromPairingCodeMock,
listEnvironmentsMock,
spawnMock
} = vi.hoisted(() => ({
callMock: vi.fn(),
runtimeClientConstructorMock: vi.fn(),
serveOrcaAppMock: vi.fn(),
getDefaultUserDataPathMock: vi.fn(() => '/tmp/orca-user-data'),
addEnvironmentFromPairingCodeMock: vi.fn(),
listEnvironmentsMock: vi.fn(),
spawnMock: vi.fn()
}))
vi.mock('./runtime-client', async () => {
const { createRuntimeClientModuleMock } = await import('./index-test-harness.js')
return createRuntimeClientModuleMock({
callMock,
runtimeClientConstructorMock,
serveOrcaAppMock,
getDefaultUserDataPathMock
})
})
vi.mock('./runtime/environments', () => ({
addEnvironmentFromPairingCode: addEnvironmentFromPairingCodeMock,
listEnvironments: listEnvironmentsMock,
removeEnvironment: vi.fn(),
resolveEnvironment: vi.fn()
}))
vi.mock('child_process', async () => {
const { createChildProcessModuleMock } = await import('./index-test-harness.js')
return createChildProcessModuleMock(spawnMock)
})
import { main } from './index'
import { localRepoDestinationFixtures, okFixture, queueFixtures } from './test-fixtures'
const SELF_OWNER = { selector: { kind: 'self' } }
import { useWorktreeAwarenessEnvironment } from './index-test-harness'
describe('orca cli worktree awareness', () => {
useWorktreeAwarenessEnvironment({
callMock,
serveOrcaAppMock,
getDefaultUserDataPathMock,
addEnvironmentFromPairingCodeMock,
listEnvironmentsMock,
spawnMock
})
it('passes automation source context JSON through create', async () => {
const sourceContext = {
kind: 'task-source',
provider: 'github',
projectId: 'github:stablyai/orca',
hostId: 'runtime:gpu',
projectHostSetupId: 'setup-gpu',
repoId: 'repo-gpu',
providerIdentity: { provider: 'github', owner: 'stablyai', repo: 'orca' },
accountLabel: 'gpu-bot'
}
queueFixtures(
callMock,
...localRepoDestinationFixtures('repo-gpu'),
okFixture('req_automation_create', {
automation: { id: 'auto-1', name: 'GPU task review' }
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'automations',
'create',
'--name',
'GPU task review',
'--trigger',
'daily',
'--prompt',
'Review open work',
'--provider',
'codex',
'--repo',
'id:repo-gpu',
'--source-context',
JSON.stringify(sourceContext),
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenNthCalledWith(
2,
'automation.create',
expect.objectContaining({
repo: 'id:repo-gpu',
sourceContext
})
)
})
it('clears automation source context on edit with null', async () => {
queueFixtures(
callMock,
okFixture('req_owner', { automation: { id: 'auto-1' }, owner: SELF_OWNER }),
okFixture('req_edit', {
automation: { id: 'auto-1', name: 'GPU task review' }
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(['automations', 'edit', 'auto-1', '--source-context', 'null', '--json'], '/tmp/repo')
expect(callMock).toHaveBeenNthCalledWith(
2,
'automation.update',
expect.objectContaining({
id: 'auto-1',
updates: expect.objectContaining({
sourceContext: null
})
})
)
})
it('rejects invalid automation source context JSON before calling the runtime', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(
[
'automations',
'create',
'--name',
'GPU task review',
'--trigger',
'daily',
'--prompt',
'Review open work',
'--provider',
'codex',
'--repo',
'id:repo-gpu',
'--source-context',
'{nope',
'--json'
],
'/tmp/repo'
)
expect(callMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'--source-context must be valid JSON'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
})