mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* fix(persistence): repo writes take the row's identity, never a bare id updateRepo(target, updates) now takes Pick<Repo,'id'|'connectionId'|'executionHostId'> (RepoHostTarget) and resolves the host from it, so a caller that holds the row can no longer drop its host and write a same-id sibling on another host. The id-only callers (project host setup controller and IPC handler, folder-to-Git upgrade watch, both clone paths, registration adoption, fork backfill) pass the row they resolved. Co-Authored-By: Claude <noreply@anthropic.com> * test: migrate the remaining Store.updateRepo callers to row targets Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import {
|
|
RuntimeProjectHostSetupController,
|
|
SERVER_SSH_PROJECT_ADD_UNAVAILABLE_MESSAGE
|
|
} from './runtime-project-host-setup-controller'
|
|
import { getProjectHostSetupForRepo } from '../../shared/project-host-setup-lookup'
|
|
import { projectHostSetupProjectionFromRepos } from '../../shared/project-host-setup-projection'
|
|
import type { Repo } from '../../shared/repo-types'
|
|
import { SshHostNotServedError } from '../providers/ssh-host-not-served-error'
|
|
|
|
const TARGET_ID = 'target-1'
|
|
const REPO_PATH = '/srv/app'
|
|
|
|
const repo: Repo = {
|
|
id: 'repo-1',
|
|
path: REPO_PATH,
|
|
displayName: 'app',
|
|
badgeColor: 'blue',
|
|
addedAt: 1,
|
|
kind: 'git'
|
|
}
|
|
|
|
function makeController(): {
|
|
controller: RuntimeProjectHostSetupController
|
|
addRepo: ReturnType<typeof vi.fn>
|
|
cloneRepo: ReturnType<typeof vi.fn>
|
|
projectId: string
|
|
} {
|
|
const store = {
|
|
getProjects: () => projectHostSetupProjectionFromRepos([repo]).projects,
|
|
getProjectHostSetups: () => [],
|
|
updateRepo: (_target: unknown, updates: Record<string, unknown>) => ({ ...repo, ...updates })
|
|
}
|
|
const addRepo = vi.fn().mockResolvedValue(repo)
|
|
const cloneRepo = vi.fn().mockResolvedValue(repo)
|
|
const controller = new RuntimeProjectHostSetupController({
|
|
getStore: () => store as never,
|
|
listRepos: () => [repo],
|
|
addRepo,
|
|
cloneRepo,
|
|
invalidateResolvedWorktrees: vi.fn(),
|
|
invalidateWorktreeScan: vi.fn(),
|
|
notifyReposChanged: vi.fn(),
|
|
countLiveTerminalsForRepo: () => 0
|
|
})
|
|
return {
|
|
controller,
|
|
addRepo,
|
|
cloneRepo,
|
|
projectId: getProjectHostSetupForRepo([], repo).projectId
|
|
}
|
|
}
|
|
|
|
describe('RuntimeProjectHostSetupController host routing', () => {
|
|
it('refuses an existing folder on an SSH target with the not-connected text, never locally', async () => {
|
|
const { controller, addRepo, projectId } = makeController()
|
|
|
|
const setup = controller.setupExistingFolder({
|
|
projectId,
|
|
hostId: `ssh:${TARGET_ID}`,
|
|
path: REPO_PATH,
|
|
kind: 'git'
|
|
})
|
|
|
|
await expect(setup).rejects.toThrow(SshHostNotServedError)
|
|
await expect(setup).rejects.toThrow(`SSH connection "${TARGET_ID}" not found or not connected`)
|
|
expect(addRepo).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('names the decoded connection id of a percent-encoded SSH target', async () => {
|
|
const { controller, addRepo, projectId } = makeController()
|
|
|
|
await expect(
|
|
controller.setupExistingFolder({
|
|
projectId,
|
|
hostId: 'ssh:my%20host',
|
|
path: REPO_PATH,
|
|
kind: 'folder'
|
|
})
|
|
).rejects.toThrow('SSH connection "my host" not found or not connected')
|
|
expect(addRepo).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('refuses repo.addRemote by saying where the project can be added instead', () => {
|
|
const { controller, addRepo } = makeController()
|
|
|
|
expect(() => controller.addSshRepo({ connectionId: TARGET_ID })).toThrow(
|
|
SERVER_SSH_PROJECT_ADD_UNAVAILABLE_MESSAGE
|
|
)
|
|
expect(addRepo).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('still uses the local registration for local and runtime hosts', async () => {
|
|
const { controller, addRepo, projectId } = makeController()
|
|
|
|
await controller.setupExistingFolder({
|
|
projectId,
|
|
hostId: 'local',
|
|
path: REPO_PATH,
|
|
kind: 'git'
|
|
})
|
|
|
|
expect(addRepo).toHaveBeenCalledWith(REPO_PATH, 'git', 'local')
|
|
})
|
|
|
|
it('refuses to clone onto an SSH host, because nothing here clones remotely', async () => {
|
|
const { controller, cloneRepo, projectId } = makeController()
|
|
|
|
await expect(
|
|
controller.setupClone({
|
|
projectId,
|
|
hostId: `ssh:${TARGET_ID}`,
|
|
url: 'https://example.com/app.git',
|
|
destination: REPO_PATH
|
|
})
|
|
).rejects.toThrow(/Cloning onto an SSH host is not supported/)
|
|
expect(cloneRepo).not.toHaveBeenCalled()
|
|
})
|
|
})
|