mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 10:27:33 +00:00
test: remove low-value startup and account coverage
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,66 +0,0 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { resolveGhAccountRequiredHost } from './account-binding-required-host'
|
||||
|
||||
function repoFor(remoteUrl: string, canonicalHost?: string) {
|
||||
const host =
|
||||
canonicalHost ??
|
||||
remoteUrl
|
||||
.replace(/^git@/, '')
|
||||
.replace(/^ssh:\/\/(?:[^@]+@)?/, '')
|
||||
.split(/[:/]/)[0]
|
||||
?.toLowerCase() ??
|
||||
'github.com'
|
||||
return {
|
||||
path: '/repos/sample-app',
|
||||
connectionId: null,
|
||||
gitRemoteIdentity: {
|
||||
canonicalKey: `${host}/example/sample-app`,
|
||||
remoteUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('resolveGhAccountRequiredHost', () => {
|
||||
it('keeps a dotted enterprise host literal unless ssh config points it at github.com', async () => {
|
||||
for (const resolveAlias of [
|
||||
async () => ({ hostname: '10.0.0.5' }),
|
||||
async () => ({ hostname: null }),
|
||||
async () => {
|
||||
throw new Error('ssh -G failed')
|
||||
}
|
||||
]) {
|
||||
await expect(
|
||||
resolveGhAccountRequiredHost(
|
||||
repoFor('git@ghe.example.com:example/sample-app.git'),
|
||||
{},
|
||||
resolveAlias
|
||||
)
|
||||
).resolves.toBe('ghe.example.com')
|
||||
}
|
||||
})
|
||||
|
||||
it('filters a dotted alias that resolves to github.com to github.com', async () => {
|
||||
const resolveAlias = vi.fn(async () => ({ hostname: 'github.com' }))
|
||||
await expect(
|
||||
resolveGhAccountRequiredHost(
|
||||
repoFor('git@work.github.com:example/sample-app.git'),
|
||||
{},
|
||||
resolveAlias
|
||||
)
|
||||
).resolves.toBe('github.com')
|
||||
expect(resolveAlias).toHaveBeenCalledWith('work.github.com', {
|
||||
repoPath: '/repos/sample-app',
|
||||
connectionId: null
|
||||
})
|
||||
})
|
||||
|
||||
it('expands an SCP alias whose path has a leading slash', async () => {
|
||||
await expect(
|
||||
resolveGhAccountRequiredHost(
|
||||
repoFor('git@github-work:/example/sample-app.git', 'github-work'),
|
||||
{},
|
||||
async () => ({ hostname: 'github.com' })
|
||||
)
|
||||
).resolves.toBe('github.com')
|
||||
})
|
||||
})
|
||||
@@ -1,12 +1,5 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { ghExecFileAsyncMock } = vi.hoisted(() => ({ ghExecFileAsyncMock: vi.fn() }))
|
||||
|
||||
vi.mock('../../git/command-runner/hosted-cli/gh-exec-file', async (importOriginal) => ({
|
||||
...(await importOriginal<Record<string, unknown>>()),
|
||||
ghExecFileAsync: ghExecFileAsyncMock
|
||||
}))
|
||||
import { diagnoseGhAuth, parseAuthStatus } from './auth-diagnose'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { parseAuthStatus } from './auth-diagnose'
|
||||
|
||||
describe('parseAuthStatus', () => {
|
||||
it('parses an env-shadowed login alongside a keyring login (real gh output)', () => {
|
||||
@@ -39,49 +32,4 @@ describe('parseAuthStatus', () => {
|
||||
source: 'keyring'
|
||||
})
|
||||
})
|
||||
|
||||
it('parses a ported GHES auth-status section', () => {
|
||||
const text = `ghe.acme.io:8443
|
||||
✓ Logged in to ghe.acme.io:8443 account bob (keyring)
|
||||
- Active account: true
|
||||
- Token scopes: 'project', 'repo'
|
||||
`
|
||||
|
||||
expect(parseAuthStatus(text)).toEqual([
|
||||
expect.objectContaining({ host: 'ghe.acme.io:8443', user: 'bob', active: true })
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('diagnoseGhAuth host scoping', () => {
|
||||
const TWO_HOST_STATUS = `github.com
|
||||
✓ Logged in to github.com account alice (keyring)
|
||||
- Active account: true
|
||||
- Token scopes: 'project', 'read:org', 'repo'
|
||||
ghe.acme.io
|
||||
✓ Logged in to ghe.acme.io account bob (keyring)
|
||||
- Active account: true
|
||||
- Token scopes: 'repo'
|
||||
`
|
||||
|
||||
it('reports an unauthenticated required host and keeps scope advice host-scoped', async () => {
|
||||
ghExecFileAsyncMock.mockResolvedValue({ stdout: TWO_HOST_STATUS, stderr: '' })
|
||||
|
||||
const diag = await diagnoseGhAuth('github.other-corp.com')
|
||||
|
||||
expect(diag.requiredHost).toBe('github.other-corp.com')
|
||||
expect(diag.requiredHostAuthenticated).toBe(false)
|
||||
expect(diag.activeAccount).toBeNull()
|
||||
})
|
||||
|
||||
it("scopes the diagnosis to the required host's account", async () => {
|
||||
ghExecFileAsyncMock.mockResolvedValue({ stdout: TWO_HOST_STATUS, stderr: '' })
|
||||
|
||||
const diag = await diagnoseGhAuth('GHE.Acme.IO')
|
||||
|
||||
expect(diag.requiredHost).toBe('ghe.acme.io')
|
||||
expect(diag.requiredHostAuthenticated).toBe(true)
|
||||
expect(diag.activeAccount?.user).toBe('bob')
|
||||
expect(diag.missingScopes).toEqual(['project', 'read:org'])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -20,7 +20,6 @@ import { registerGitHubPRReviewHandlers } from '../../ipc/source-control/github-
|
||||
import { ghPullRequestsAndWorkItemsApi } from '../../../preload/api/github/gh-bridge-pull-requests-and-work-items'
|
||||
import { ghMutationsAndProjectsApi } from '../../../preload/api/github/gh-bridge-mutations-and-projects'
|
||||
import type { GhAccountBinding } from '../../../shared/github/accounts/account-binding'
|
||||
import { RPC_PARAMS_BY_METHOD } from '../../../shared/rpc-contract/rpc-params-catalog.generated'
|
||||
|
||||
const { exec, handle, invoke } = vi.hoisted(() => ({
|
||||
exec: vi.fn<typeof GhUtilsOwner1.ghExecFileAsync>(),
|
||||
@@ -60,8 +59,6 @@ import type { Project } from '../../../shared/project-types'
|
||||
import type { Repo } from '../../../shared/repo-types'
|
||||
import { ghRepoExecOptions, githubRepoContext } from '../repositories/github-repository-identity'
|
||||
import { installGitHubProjectAccounts } from './github-project-account'
|
||||
import { codeHostReadExecutionScope as githubReadExecutionScope } from '../../source-control/code-host-read-execution-scope'
|
||||
import { resolveGitHubRepoExecution } from '../repositories/github-api-repository'
|
||||
|
||||
let release: (() => void) | undefined
|
||||
afterEach(() => release?.())
|
||||
@@ -82,20 +79,6 @@ function options(path: string, connectionId?: string | null, extra = {}) {
|
||||
return ghRepoExecOptions(githubRepoContext(path, connectionId, extra))
|
||||
}
|
||||
|
||||
it('uses the saved bound or unbound selection over stale caller options, and isolates cache keys', () => {
|
||||
let current = repo()
|
||||
release = installGitHubProjectAccounts({ getRepos: () => [current] })
|
||||
const first = options('/repo', null, { ghAccount: bob })
|
||||
expect(first.ghAccount).toEqual(alice)
|
||||
current = repo({ ghAccount: bob })
|
||||
const second = options('/repo', null, { ghAccount: alice })
|
||||
expect(second.ghAccount).toEqual(bob)
|
||||
expect(githubReadExecutionScope(first, {})).not.toBe(githubReadExecutionScope(second, {}))
|
||||
current = repo({ ghAccount: undefined })
|
||||
expect(options('/repo', null, { ghAccount: alice }).ghAccount).toBeUndefined()
|
||||
expect(first.ghAccount).toEqual(alice)
|
||||
})
|
||||
|
||||
it.each(['cold', 'warm'] as const)(
|
||||
'resolves a %s child worktree by its host-qualified owning project',
|
||||
(mode) => {
|
||||
@@ -117,23 +100,6 @@ it.each(['cold', 'warm'] as const)(
|
||||
}
|
||||
)
|
||||
|
||||
it('selects before an asynchronous repository lookup and retains that account for execution', async () => {
|
||||
let current = repo()
|
||||
release = installGitHubProjectAccounts({ getRepos: () => [current] })
|
||||
let finish: () => void = () => {}
|
||||
const waiting = new Promise<void>((resolve) => {
|
||||
finish = resolve
|
||||
})
|
||||
const pending = resolveGitHubRepoExecution('/repo', async () => {
|
||||
await waiting
|
||||
return { owner: 'acme', repo: 'widgets', host: 'github.com' }
|
||||
})
|
||||
current = repo({ ghAccount: bob })
|
||||
finish()
|
||||
expect((await pending).ghOptions.ghAccount).toEqual(alice)
|
||||
expect(options('/repo').ghAccount).toEqual(bob)
|
||||
})
|
||||
|
||||
it('derives runtime ownership again after project runtime changes', () => {
|
||||
const platform = process.platform
|
||||
Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' })
|
||||
@@ -300,88 +266,6 @@ describe('host account expectation through registered RPC and local preload', ()
|
||||
rmSync(testState.dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
it('validates all four schemas and rejects mismatches before provider work on RPC and IPC without changing omission', async () => {
|
||||
applied(bob)
|
||||
for (const operation of operations) {
|
||||
const payload = {
|
||||
repo: 'id:repo',
|
||||
...operation.params,
|
||||
expectedGhAccount: { host: ' GitHub.COM ', user: ' Bob ' }
|
||||
}
|
||||
expect(RPC_PARAMS_BY_METHOD[operation.method].parse(payload)).toEqual({
|
||||
...payload,
|
||||
expectedGhAccount: bob
|
||||
})
|
||||
for (const malformed of [
|
||||
{ host: 'github.com' },
|
||||
{ host: 'bad/host', user: 'Alice' },
|
||||
false
|
||||
]) {
|
||||
expect(
|
||||
RPC_PARAMS_BY_METHOD[operation.method].safeParse({
|
||||
...payload,
|
||||
expectedGhAccount: malformed
|
||||
}).success
|
||||
).toBe(false)
|
||||
}
|
||||
exec.mockClear()
|
||||
expect(
|
||||
await dispatcher.dispatch({
|
||||
id: 'malformed',
|
||||
authToken: 'fixture',
|
||||
method: operation.method,
|
||||
params: { ...payload, expectedGhAccount: false }
|
||||
})
|
||||
).toMatchObject({ ok: false, error: { code: 'invalid_argument' } })
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
expect(await dispatch(operation, alice)).toMatchObject({
|
||||
ok: false,
|
||||
error: { message: expect.stringContaining('GitHub account changed') }
|
||||
})
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
await expect(operation.local(alice)).rejects.toThrow('GitHub account changed')
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
expect(await dispatch(operation, bob)).toMatchObject({ ok: true })
|
||||
expect(exec).toHaveBeenCalled()
|
||||
expect(exec.mock.calls.every(([, options]) => options?.ghAccount?.user === 'Bob')).toBe(true)
|
||||
exec.mockClear()
|
||||
await operation.local(bob)
|
||||
expect(exec).toHaveBeenCalled()
|
||||
expect(exec.mock.calls.every(([, options]) => options?.ghAccount?.user === 'Bob')).toBe(true)
|
||||
exec.mockClear()
|
||||
expect(await dispatch(operation)).toMatchObject({ ok: true })
|
||||
expect(exec).toHaveBeenCalled()
|
||||
expect(exec.mock.calls.every(([, options]) => options?.ghAccount?.user === 'Bob')).toBe(true)
|
||||
}
|
||||
exec.mockClear()
|
||||
expect(await dispatch(operations[1], null)).toMatchObject({ ok: false })
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
applied(null)
|
||||
expect(await dispatch(operations[1], null)).toMatchObject({ ok: true, result: ['bug'] })
|
||||
expect(exec.mock.calls.at(-1)?.[1]?.ghAccount).toBeUndefined()
|
||||
await expect(operations[1].local(null)).resolves.toEqual(['bug'])
|
||||
expect(exec.mock.calls.at(-1)?.[1]?.ghAccount).toBeUndefined()
|
||||
exec.mockClear()
|
||||
expect(await dispatch(operations[3], alice)).toMatchObject({ ok: false })
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
await expect(
|
||||
invoke('gh:listLabels', {
|
||||
...local,
|
||||
ownerRepo: repository,
|
||||
expectedGhAccount: { user: 'Alice' }
|
||||
})
|
||||
).rejects.toThrow('Invalid GitHub account expectation')
|
||||
expect(exec).not.toHaveBeenCalled()
|
||||
applied(alice)
|
||||
expect(await dispatch(operations[0], alice)).toMatchObject({
|
||||
ok: true,
|
||||
result: { item: { number: 7, type: 'issue' }, body: 'Alice' }
|
||||
})
|
||||
expect(
|
||||
await dispatch({ ...operations[0], params: { ...item, canonical: false } }, alice)
|
||||
).toMatchObject({ ok: true, result: { body: 'Alice' } })
|
||||
})
|
||||
|
||||
it('keeps the actual admitted A capture through a later B update for full details and Viewed, then fails a fresh stale-A request', async () => {
|
||||
for (const operation of [operations[0], operations[3]]) {
|
||||
applied(alice)
|
||||
|
||||
@@ -94,11 +94,4 @@ describe.skipIf(process.platform === 'win32')('external Chromium profile path',
|
||||
|
||||
await expect(resolve(launcher)).resolves.toBe(stateProfile)
|
||||
})
|
||||
|
||||
it('leaves non-Linux hosts on the state profile', async () => {
|
||||
const launcher = await installSnap('chromium', 'name: chromium\n')
|
||||
environment = { ...environment, platform: 'darwin' }
|
||||
|
||||
await expect(resolve(launcher)).resolves.toBe(join(root, 'state', 'browser-chromium'))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -55,16 +55,6 @@ describe('migratePlaintextCredentials', () => {
|
||||
expect(logs.join('\n')).not.toContain('lin_api_plaintext')
|
||||
})
|
||||
|
||||
it("stages in its own temp file, never a concurrent writer's shared one", () => {
|
||||
const path = join(dir, 'linear-token.enc')
|
||||
writeFileSync(path, 'lin_api_plaintext', 'utf8')
|
||||
writeFileSync(`${path}.tmp`, 'other-writer-in-progress', 'utf8')
|
||||
|
||||
migratePlaintextCredentials(store, [{ path, raw: true }], log)
|
||||
expect(readFileSync(`${path}.tmp`, 'utf8')).toBe('other-writer-in-progress')
|
||||
expect(readStoredCredentialToken('Linear', readFileSync(path))).toBe('lin_api_plaintext')
|
||||
})
|
||||
|
||||
it('rewrites a plaintext envelope as an encrypted one', () => {
|
||||
const path = join(dir, 'minimax-api-key.enc')
|
||||
const prefix = 'orca-minimax-api-key:v1:'
|
||||
|
||||
@@ -2,43 +2,6 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { createServeDesktopActivationGate } from './serve-desktop-activation'
|
||||
|
||||
describe('createServeDesktopActivationGate', () => {
|
||||
it('coalesces activation requests while serve is initializing and drains once when ready', () => {
|
||||
const activateWindow = vi.fn()
|
||||
const gate = createServeDesktopActivationGate({
|
||||
initialState: 'initializing',
|
||||
activateWindow
|
||||
})
|
||||
|
||||
gate.requestActivation()
|
||||
gate.requestActivation()
|
||||
|
||||
expect(activateWindow).not.toHaveBeenCalled()
|
||||
expect(gate.getState()).toBe('initializing')
|
||||
|
||||
gate.markReady()
|
||||
|
||||
expect(activateWindow).toHaveBeenCalledOnce()
|
||||
expect(gate.getState()).toBe('ready')
|
||||
})
|
||||
|
||||
it('drops pending activation and fails closed when promotion is blocked', () => {
|
||||
const activateWindow = vi.fn()
|
||||
const onBlocked = vi.fn()
|
||||
const gate = createServeDesktopActivationGate({
|
||||
initialState: 'initializing',
|
||||
activateWindow,
|
||||
onBlocked
|
||||
})
|
||||
|
||||
gate.requestActivation()
|
||||
gate.markBlocked('persistent PTY provider unavailable')
|
||||
gate.requestActivation()
|
||||
|
||||
expect(activateWindow).not.toHaveBeenCalled()
|
||||
expect(onBlocked).toHaveBeenCalledTimes(2)
|
||||
expect(gate.getState()).toBe('blocked')
|
||||
})
|
||||
|
||||
it('lets a queued user activation keep the foreground over a background open', () => {
|
||||
const activateWindow = vi.fn()
|
||||
const gate = createServeDesktopActivationGate({ initialState: 'initializing', activateWindow })
|
||||
|
||||
@@ -47,24 +47,6 @@ describe('serve-mode-argv', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('leaves real GUI launch argv alone', () => {
|
||||
// False serve detection replaces a desktop window with a listening runtime; exercise actual desktop argv shapes.
|
||||
for (const argv of [
|
||||
['/Applications/Orca.app/Contents/MacOS/Orca', '-psn_0_123456'],
|
||||
['C:\\Program Files\\Orca\\Orca.exe', '--squirrel-firstrun'],
|
||||
['C:\\Program Files\\Orca\\Orca.exe', 'orca://worktree/serve'],
|
||||
['/opt/orca/orca-ide', '/home/u/serve'],
|
||||
// Value tokens named serve are never subcommands.
|
||||
['/opt/orca/orca-ide', '--pairing-code', 'serve'],
|
||||
['/opt/orca/orca-ide', '--environment=serve'],
|
||||
['/opt/orca/orca-ide', '--', 'serve'],
|
||||
['/opt/orca/orca-ide', 'Serve']
|
||||
]) {
|
||||
expect(argvRequestsServeMode(argv), argv.join(' ')).toBe(false)
|
||||
expect(normalizeServeModeArgv(argv)).toEqual(argv)
|
||||
}
|
||||
})
|
||||
|
||||
it('does not treat a later positional serve as the subcommand after another command', () => {
|
||||
expect(findServeSubcommandIndex(['app', 'status', 'serve'])).toBe(-1)
|
||||
expect(argvRequestsServeMode(['app', 'status', 'serve'])).toBe(false)
|
||||
@@ -78,14 +60,6 @@ describe('serve-mode-argv', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('does not splice prototype members onto argv for stray positionals', () => {
|
||||
expect(normalizeServeModeArgv(['/AppRun', 'serve', 'toString'])).toEqual([
|
||||
'/AppRun',
|
||||
'--serve',
|
||||
'toString'
|
||||
])
|
||||
})
|
||||
|
||||
it('passes args after `--` through verbatim', () => {
|
||||
expect(normalizeServeModeArgv(['/AppRun', 'serve', '--json', '--', '--port', '1'])).toEqual([
|
||||
'/AppRun',
|
||||
|
||||
@@ -5,13 +5,7 @@ import { getServeOptions } from './serve-options'
|
||||
import './serve-pinned-bind-host'
|
||||
|
||||
describe('Electron serve listener pin', () => {
|
||||
it('rejects hostnames, empty values and --mobile-pairing with a narrower bind', () => {
|
||||
expect(() => getServeOptions(['/AppRun', '--serve', '--serve-bind'])).toThrow(
|
||||
'Missing value for --serve-bind.'
|
||||
)
|
||||
expect(() => getServeOptions(['/AppRun', '--serve', '--serve-bind', 'host.example'])).toThrow(
|
||||
/literal IP address/
|
||||
)
|
||||
it('rejects --mobile-pairing with a narrower bind', () => {
|
||||
expect(() =>
|
||||
getServeOptions(['/AppRun', '--serve', '--serve-bind', '127.0.0.1', '--serve-mobile-pairing'])
|
||||
).toThrow(/--mobile-pairing needs --bind 0\.0\.0\.0/)
|
||||
|
||||
@@ -2,14 +2,6 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { checkServeUserDataPath } from './serve-user-data-path-guard'
|
||||
|
||||
describe('checkServeUserDataPath', () => {
|
||||
it('refuses a serve that landed on a profile other than the one the CLI chose', () => {
|
||||
const env: NodeJS.ProcessEnv = { ORCA_SERVE_USER_DATA_PATH: '/isolated/profile' }
|
||||
expect(
|
||||
checkServeUserDataPath({ isServeMode: true, userDataPath: '/default/orca', env })
|
||||
).toContain('/isolated/profile')
|
||||
expect(env.ORCA_SERVE_USER_DATA_PATH).toBeUndefined()
|
||||
})
|
||||
|
||||
it('allows the chosen profile, including another spelling of it', () => {
|
||||
expect(
|
||||
checkServeUserDataPath({
|
||||
@@ -27,13 +19,6 @@ describe('checkServeUserDataPath', () => {
|
||||
})
|
||||
).toBeNull()
|
||||
})
|
||||
|
||||
it('leaves launches without a CLI choice, or outside serve, alone', () => {
|
||||
expect(checkServeUserDataPath({ isServeMode: true, userDataPath: '/a', env: {} })).toBeNull()
|
||||
const env: NodeJS.ProcessEnv = { ORCA_SERVE_USER_DATA_PATH: '/b' }
|
||||
expect(checkServeUserDataPath({ isServeMode: false, userDataPath: '/a', env })).toBeNull()
|
||||
expect(env.ORCA_SERVE_USER_DATA_PATH).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('configureOrcaUserDataPathEnv on a serve launch', () => {
|
||||
|
||||
Reference in New Issue
Block a user