mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 10:37:35 +00:00
* [comment audit] Shorten daemon, hook, and emulator comments [skip ci] * [comment audit] Shorten VM, conversation, SQLite, and theme-import comments [skip ci] * [comment audit] Tighten Git execution and source-control comment contracts [skip ci] * [comment audit] Clarify repository probes and maintenance comments [skip ci] * [comment audit] Shorten status, diff-cache, and checkout comments [skip ci] * [comment audit] Clarify worktree lifecycle and WSL routing comments [skip ci] * [comment audit] Shorten forge identity and review-refresh comments [skip ci] * [comment audit] Tighten hosted-review client comment contracts [skip ci] * [comment audit] Clarify GitLab compatibility and review comments [skip ci] * [comment audit] Tighten hook ownership and watchdog rationale [skip ci] * [comment audit] Condense host and integration compatibility comments [skip ci] * [comment audit] Clarify IPC authority and remote-routing rationale [skip ci] * [comment audit] Finalize file-import and containment comment cleanup * [comment audit] Fix stale Jira type imports blocking full CI --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
210 lines
7.1 KiB
TypeScript
210 lines
7.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const mocks = vi.hoisted(() => ({ gitExecFileAsync: vi.fn() }))
|
|
|
|
vi.mock('./runner', () => ({ gitExecFileAsync: mocks.gitExecFileAsync }))
|
|
|
|
import { GIT_READ_TIMEOUT_MS } from './command-runner/git-command-timeout'
|
|
import { GitAdmissionScheduler } from './command-runner/git-subprocess-admission'
|
|
import type { GitAdmissionTier } from './command-runner/git-exec-options'
|
|
import { WSL_GIT_READ_ENVIRONMENT_WAIT_MS } from './wsl-git-read-environment'
|
|
import {
|
|
measureRetargetDivergence,
|
|
RETARGET_DIVERGENCE_BUDGET_MS
|
|
} from './worktree-base-divergence'
|
|
|
|
type ExecOptions = {
|
|
cwd: string
|
|
timeout?: number
|
|
wslDistro?: string
|
|
signal?: AbortSignal
|
|
admissionTier?: GitAdmissionTier
|
|
}
|
|
|
|
function callOptions(): ExecOptions[] {
|
|
return mocks.gitExecFileAsync.mock.calls.map((call) => call[1] as ExecOptions)
|
|
}
|
|
|
|
function subcommands(): string[] {
|
|
return mocks.gitExecFileAsync.mock.calls.map((call) => (call[0] as string[])[0]!)
|
|
}
|
|
|
|
function answerProbes(count: string, mergeBase = 'abc123\n') {
|
|
mocks.gitExecFileAsync.mockImplementation(async (args: string[]) =>
|
|
args[0] === 'merge-base' ? { stdout: mergeBase } : { stdout: count }
|
|
)
|
|
}
|
|
|
|
function exitCodeError(code: number): Error & { code: number } {
|
|
return Object.assign(new Error('git exited'), { code })
|
|
}
|
|
|
|
beforeEach(() => {
|
|
mocks.gitExecFileAsync.mockReset()
|
|
})
|
|
|
|
describe('measureRetargetDivergence deadlines', () => {
|
|
it('finishes through interactive headroom while general capacity is occupied', async () => {
|
|
const scheduler = new GitAdmissionScheduler({ generalCap: 1, generalHeadroom: 1 })
|
|
const blocker = await scheduler.acquire({ args: ['status'], cwd: '/repo' })
|
|
mocks.gitExecFileAsync.mockImplementation(async (args: string[], options: ExecOptions) => {
|
|
const grant = await scheduler.acquire({
|
|
args,
|
|
cwd: options.cwd,
|
|
signal: options.signal,
|
|
tier: options.admissionTier
|
|
})
|
|
try {
|
|
return { stdout: args[0] === 'merge-base' ? 'abc123\n' : '1\n' }
|
|
} finally {
|
|
grant.release()
|
|
}
|
|
})
|
|
try {
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main', {
|
|
admissionTier: 'interactive',
|
|
budgetMsForTest: 200
|
|
})
|
|
).resolves.toBe('within')
|
|
expect(subcommands()).toEqual(['rev-list', 'rev-list', 'merge-base'])
|
|
} finally {
|
|
blocker.release()
|
|
}
|
|
})
|
|
|
|
it('puts every probe under one shared budget, not a budget each', async () => {
|
|
answerProbes('3\n')
|
|
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
).resolves.toBe('within')
|
|
|
|
expect(subcommands()).toEqual(['rev-list', 'rev-list', 'merge-base'])
|
|
const signals = callOptions().map((options) => options.signal)
|
|
// One budget spans all staged probes; per-probe budgets would add together.
|
|
expect(new Set(signals).size).toBe(1)
|
|
expect(signals[0]).toBeInstanceOf(AbortSignal)
|
|
})
|
|
|
|
it('also gives each probe a command timeout well below git default read deadline', async () => {
|
|
answerProbes('3\n')
|
|
|
|
await measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
|
|
// Signals cover pre-spawn waits; command timeouts still bound a hung spawn.
|
|
for (const options of callOptions()) {
|
|
expect(options.timeout).toBe(RETARGET_DIVERGENCE_BUDGET_MS)
|
|
}
|
|
expect(RETARGET_DIVERGENCE_BUDGET_MS).toBeLessThan(GIT_READ_TIMEOUT_MS)
|
|
})
|
|
|
|
it('really aborts the in-flight probes when the shared budget expires', async () => {
|
|
mocks.gitExecFileAsync.mockImplementation(
|
|
(_args: string[], options: ExecOptions) =>
|
|
new Promise((_resolve, reject) => {
|
|
options.signal?.addEventListener(
|
|
'abort',
|
|
() =>
|
|
reject(
|
|
Object.assign(new Error('The operation was aborted.'), { name: 'AbortError' })
|
|
),
|
|
{ once: true }
|
|
)
|
|
})
|
|
)
|
|
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main', {
|
|
budgetMsForTest: 25
|
|
})
|
|
).resolves.toBe('unknown')
|
|
})
|
|
|
|
it('clears the WSL read-environment wait, which starts before any command timeout', () => {
|
|
// Leave walk headroom after the first WSL environment probe.
|
|
expect(RETARGET_DIVERGENCE_BUDGET_MS).toBeGreaterThan(WSL_GIT_READ_ENVIRONMENT_WAIT_MS)
|
|
expect(RETARGET_DIVERGENCE_BUDGET_MS).toBeLessThan(GIT_READ_TIMEOUT_MS)
|
|
})
|
|
|
|
it('stops the probes when the create itself is cancelled, without waiting for the budget', async () => {
|
|
mocks.gitExecFileAsync.mockImplementation(
|
|
(_args: string[], options: ExecOptions) =>
|
|
new Promise((_resolve, reject) => {
|
|
options.signal?.addEventListener(
|
|
'abort',
|
|
() =>
|
|
reject(
|
|
Object.assign(new Error('The operation was aborted.'), { name: 'AbortError' })
|
|
),
|
|
{ once: true }
|
|
)
|
|
})
|
|
)
|
|
const controller = new AbortController()
|
|
const pending = measureRetargetDivergence(
|
|
'/repo',
|
|
'refs/heads/main',
|
|
'refs/remotes/origin/main',
|
|
// A budget long enough that only the caller's cancellation can end this in time.
|
|
{ signal: controller.signal, budgetMsForTest: 60_000 }
|
|
)
|
|
controller.abort()
|
|
|
|
await expect(pending).resolves.toBe('unknown')
|
|
})
|
|
|
|
it('reports a blown deadline as unverifiable rather than as excess drift', async () => {
|
|
mocks.gitExecFileAsync.mockRejectedValue(new Error('git timed out.'))
|
|
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
).resolves.toBe('unknown')
|
|
expect(subcommands()).not.toContain('merge-base')
|
|
})
|
|
|
|
it('separates merge-base saying no from merge-base failing', async () => {
|
|
mocks.gitExecFileAsync.mockImplementation(async (args: string[]) => {
|
|
if (args[0] === 'merge-base') {
|
|
throw exitCodeError(1)
|
|
}
|
|
return { stdout: '2\n' }
|
|
})
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
).resolves.toBe('exceeded')
|
|
|
|
mocks.gitExecFileAsync.mockReset()
|
|
mocks.gitExecFileAsync.mockImplementation(async (args: string[]) => {
|
|
if (args[0] === 'merge-base') {
|
|
throw new Error('git timed out.')
|
|
}
|
|
return { stdout: '2\n' }
|
|
})
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
).resolves.toBe('unknown')
|
|
})
|
|
|
|
it('reports drift past the cap without spending a merge-base walk', async () => {
|
|
answerProbes('101\n')
|
|
|
|
await expect(
|
|
measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main')
|
|
).resolves.toBe('exceeded')
|
|
expect(subcommands()).not.toContain('merge-base')
|
|
})
|
|
|
|
it('routes every probe to the caller-named WSL distro', async () => {
|
|
answerProbes('1\n')
|
|
|
|
await measureRetargetDivergence('/repo', 'refs/heads/main', 'refs/remotes/origin/main', {
|
|
wslDistro: 'Ubuntu'
|
|
})
|
|
|
|
for (const options of callOptions()) {
|
|
expect(options).toMatchObject({ cwd: '/repo', wslDistro: 'Ubuntu' })
|
|
}
|
|
})
|
|
})
|