mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 10:27:33 +00:00
Desktop automation runs now launch from the main process through the same launcher orca serve uses. The renderer dispatch path is deleted.
122 lines
4.4 KiB
TypeScript
122 lines
4.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { mkdtempSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import {
|
|
closeTestStores,
|
|
testState,
|
|
createStore,
|
|
writeDataFile,
|
|
makeRepo
|
|
} from '../../src/main/persistence/persistence-test-harness'
|
|
import { getDefaultPersistedState } from '../../src/shared/constants'
|
|
import { OrcaRuntimeService } from '../../src/main/runtime/orca-runtime'
|
|
import { resolveAutomationRunTarget } from '../../src/main/automations/run-target-resolution'
|
|
import { buildAutomationWorktreeCreateArgs } from '../../src/main/automations/automation-workspace-create'
|
|
|
|
vi.mock('../../src/main/ssh/config/ssh-config-parser', () => ({
|
|
loadUserSshConfig: () => ({ hosts: [] }),
|
|
sshConfigHostsToTargets: () => []
|
|
}))
|
|
vi.mock('../../src/main/telemetry/client', () => ({ track: vi.fn() }))
|
|
vi.mock('../../src/main/telemetry/cohort-classifier', () => ({
|
|
getCohortAtEmit: () => ({ nth_repo_added: 2 })
|
|
}))
|
|
|
|
beforeEach(() => {
|
|
testState.dir = mkdtempSync(join(tmpdir(), 'orca-target-dispatch-'))
|
|
})
|
|
afterEach(async () => {
|
|
await closeTestStores()
|
|
rmSync(testState.dir, { recursive: true, force: true })
|
|
})
|
|
|
|
describe('persisted automation target dispatch', () => {
|
|
it.each([false, true])(
|
|
'retains copied local and SSH targets through runtime writes, reload and dispatch, reversed=%s',
|
|
async (reverse) => {
|
|
const repos = [
|
|
makeRepo({ executionHostId: 'local', path: '/same/path' }),
|
|
makeRepo({ executionHostId: 'ssh:box', connectionId: 'box', path: '/same/path' })
|
|
]
|
|
writeDataFile({
|
|
...getDefaultPersistedState(testState.dir),
|
|
repos: reverse ? repos.toReversed() : repos,
|
|
sshTargets: [
|
|
{
|
|
id: 'box',
|
|
label: 'Box',
|
|
host: 'example.test',
|
|
username: 'test',
|
|
port: 22,
|
|
generation: 7
|
|
}
|
|
]
|
|
})
|
|
const store = await createStore()
|
|
const runtime = new OrcaRuntimeService(store)
|
|
const ids: string[] = []
|
|
for (const hostId of ['local', 'ssh:box'] as const) {
|
|
const setup = store
|
|
.getProjectHostSetups()
|
|
.find((row) => row.repoId === 'r1' && row.hostId === hostId)!
|
|
expect(setup).toBeDefined()
|
|
const created = await runtime.createAutomation({
|
|
name: hostId,
|
|
prompt: 'Run checks',
|
|
agentId: 'codex',
|
|
repo: 'id:r1',
|
|
workspaceMode: 'new_per_run',
|
|
timezone: 'UTC',
|
|
rrule: 'FREQ=DAILY;BYHOUR=9;BYMINUTE=0',
|
|
dtstart: 1,
|
|
runContext: {
|
|
kind: 'workspace-run',
|
|
projectId: setup.projectId,
|
|
projectHostSetupId: setup.id,
|
|
hostId,
|
|
repoId: 'r1',
|
|
path: '/same/path'
|
|
}
|
|
})
|
|
ids.push(created.id)
|
|
const owner = store.automationOwnerPrecondition(created.id)!
|
|
const edited = await runtime.updateAutomation(
|
|
created.id,
|
|
{ name: `${hostId} edited` },
|
|
{ expectedOwner: owner }
|
|
)
|
|
expect(edited.runContext).toMatchObject({ hostId, repoId: 'r1', path: '/same/path' })
|
|
expect(edited.executionTargetId).toBe(hostId === 'local' ? 'local' : 'box')
|
|
}
|
|
await store.flushPendingOrThrowAsync()
|
|
const reloaded = await createStore()
|
|
for (const [index, hostId] of (['local', 'ssh:box'] as const).entries()) {
|
|
const saved = reloaded.listAutomations().find((row) => row.id === ids[index])!
|
|
const selector = reloaded
|
|
.listAutomationsForScope()
|
|
.items.find((row) => row.automationId === saved.id)?.selector
|
|
expect(selector).toEqual(
|
|
hostId === 'local'
|
|
? { kind: 'self' }
|
|
: { kind: 'ssh', targetId: 'box', targetGeneration: 7 }
|
|
)
|
|
const resolvedTarget = resolveAutomationRunTarget(reloaded, saved)
|
|
expect(resolvedTarget.ok).toBe(true)
|
|
if (!resolvedTarget.ok) {
|
|
throw new Error(resolvedTarget.error)
|
|
}
|
|
expect(resolvedTarget.repo.executionHostId).toBe(hostId)
|
|
const run = reloaded.createAutomationRun(saved, 1, 'manual')
|
|
expect(
|
|
buildAutomationWorktreeCreateArgs({
|
|
automation: saved,
|
|
repo: resolvedTarget.repo,
|
|
run
|
|
}).repoSelector
|
|
).toEqual({ selector: 'id:r1', hostId })
|
|
}
|
|
}
|
|
)
|
|
})
|