mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
test(e2e): track WSL stub agent staging state for precise cleanup
Refactor `stageWslGoldenStubAgent` to track which artifacts it creates during setup, then only remove those artifacts during cleanup. This prevents the test from destructively removing pre-existing symlinks or state from previous runs, improving test isolation and idempotency.
This commit is contained in:
@@ -17,11 +17,7 @@ import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } fro
|
||||
import { getTerminalContent } from './helpers/terminal'
|
||||
import type { BuiltInWindowsTerminalShell } from '../../src/shared/windows-terminal-shell'
|
||||
|
||||
// Covers the full tab-bar `+` agent launch chain — detection row, startup-plan
|
||||
// build, tab create, PTY spawn under the configured runtime, startup-command
|
||||
// injection. golden-agent-tui-launch.spec.ts covers one agent on the default
|
||||
// shell and never runs in the Windows golden lane, so a Windows-only break
|
||||
// anywhere in that chain ships as "clicking an agent does nothing".
|
||||
// Covers the Windows-only tab-bar launch path that the default-shell test misses.
|
||||
|
||||
test.use({ launchEnv: getGoldenStubAgentLaunchEnv() })
|
||||
|
||||
@@ -80,10 +76,8 @@ test.describe('Windows runtimes', () => {
|
||||
|
||||
const distro = await getFirstWslDistro(orcaPage)
|
||||
test.skip(!distro, 'No WSL distro is available on this Windows host')
|
||||
test.skip(
|
||||
!stageWslGoldenStubAgent(distro!),
|
||||
'WSL distro would not accept the staged stub agent'
|
||||
)
|
||||
const stage = stageWslGoldenStubAgent(distro!)
|
||||
test.skip(!stage, 'WSL distro would not accept the staged stub agent')
|
||||
|
||||
try {
|
||||
// Why the runtime switch and not terminalWindowsShell: WSL is a project
|
||||
@@ -97,7 +91,7 @@ test.describe('Windows runtimes', () => {
|
||||
// ran in WSL rather than on the Windows host.
|
||||
expect(await getTerminalContent(orcaPage)).toContain(GOLDEN_STUB_READY_MARKER)
|
||||
} finally {
|
||||
removeWslGoldenStubAgent(distro!)
|
||||
removeWslGoldenStubAgent(distro!, stage!)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,8 +7,7 @@ import type { BuiltInWindowsTerminalShell } from '../../../src/shared/windows-te
|
||||
export const GOLDEN_STUB_READY_MARKER = 'GOLDEN_STUB_AGENT_READY'
|
||||
export const GOLDEN_STUB_EXIT_MARKER = 'GOLDEN_STUB_AGENT_EXITED'
|
||||
|
||||
/** Agents the fixture dir shims onto PATH, so detection lists them and the
|
||||
* tab-bar `+` menu renders a launch row for each. */
|
||||
/** Agents exposed by the fixture directory for tab-bar detection. */
|
||||
export const GOLDEN_STUB_AGENTS = [
|
||||
{ id: 'codex', menuItemName: /^Codex(?:\s|$)/i },
|
||||
{ id: 'claude', menuItemName: /^Claude(?:\s|$)/i }
|
||||
|
||||
@@ -2,8 +2,7 @@ import { execFileSync } from 'node:child_process'
|
||||
import type { Page } from '@stablyai/playwright-test'
|
||||
import { buildWslExecArgs } from '../../../src/shared/wsl-login-shell-command'
|
||||
|
||||
/** Distro path the stub is staged at. Only reachable from inside WSL, so the
|
||||
* stub's marker in a pane is itself proof the pane executed in the distro. */
|
||||
/** A WSL-only path makes the stub marker proof that the pane ran in the distro. */
|
||||
const WSL_STUB_PATH = '/usr/local/bin/golden-stub-agent'
|
||||
const WSL_STUB_AGENT_LINK = '/usr/local/bin/codex'
|
||||
|
||||
@@ -12,18 +11,23 @@ const WSL_STUB_AGENT_LINK = '/usr/local/bin/codex'
|
||||
const STAGE_SCRIPT =
|
||||
`mkdir -p /usr/local/bin && ` +
|
||||
`printf '#!/bin/sh\\necho GOLDEN_STUB_AGENT_READY\\nexec sleep 3600\\n' > ${WSL_STUB_PATH} && ` +
|
||||
`chmod 0755 ${WSL_STUB_PATH} && ` +
|
||||
`ln -sf ${WSL_STUB_PATH} ${WSL_STUB_AGENT_LINK}`
|
||||
`chmod 0755 ${WSL_STUB_PATH}`
|
||||
|
||||
const UNSTAGE_SCRIPT = `rm -f ${WSL_STUB_AGENT_LINK} ${WSL_STUB_PATH}`
|
||||
const STAGE_CODEX_LINK_IF_MISSING_SCRIPT =
|
||||
`if [ -e ${WSL_STUB_AGENT_LINK} ] || [ -L ${WSL_STUB_AGENT_LINK} ]; then ` +
|
||||
`printf existing; else ln -s ${WSL_STUB_PATH} ${WSL_STUB_AGENT_LINK} && printf created; fi`
|
||||
|
||||
const REMOVE_STUB_SCRIPT = `rm -f ${WSL_STUB_PATH}`
|
||||
const REMOVE_CODEX_LINK_AND_STUB_SCRIPT = `rm -f ${WSL_STUB_AGENT_LINK} ${WSL_STUB_PATH}`
|
||||
|
||||
// Why --exec (via buildWslExecArgs): under `--`, wsl.exe expands `$name` in
|
||||
// every argument and silently rewrites the script.
|
||||
function runInWslAsRoot(distro: string, script: string): void {
|
||||
execFileSync('wsl.exe', ['-u', 'root', ...buildWslExecArgs(distro, ['sh', '-c', script])], {
|
||||
stdio: 'pipe',
|
||||
windowsHide: true
|
||||
})
|
||||
function runInWslAsRoot(distro: string, script: string): string {
|
||||
return execFileSync(
|
||||
'wsl.exe',
|
||||
['-u', 'root', ...buildWslExecArgs(distro, ['sh', '-c', script])],
|
||||
{ encoding: 'utf8', stdio: 'pipe', windowsHide: true }
|
||||
)
|
||||
}
|
||||
|
||||
export async function getFirstWslDistro(page: Page): Promise<string | null> {
|
||||
@@ -34,20 +38,30 @@ export async function getFirstWslDistro(page: Page): Promise<string | null> {
|
||||
return wsl.available ? (wsl.distros[0] ?? null) : null
|
||||
}
|
||||
|
||||
/** Returns false when the distro won't take the stub (no root interop, read-only
|
||||
* rootfs); callers skip rather than fail, since that is a host limitation. */
|
||||
export function stageWslGoldenStubAgent(distro: string): boolean {
|
||||
export type WslGoldenStubAgentStage = {
|
||||
createdCodexLink: boolean
|
||||
}
|
||||
|
||||
/** Returns null when the distro cannot stage the stub. */
|
||||
export function stageWslGoldenStubAgent(distro: string): WslGoldenStubAgentStage | null {
|
||||
try {
|
||||
runInWslAsRoot(distro, STAGE_SCRIPT)
|
||||
return true
|
||||
return {
|
||||
createdCodexLink:
|
||||
runInWslAsRoot(distro, STAGE_CODEX_LINK_IF_MISSING_SCRIPT).trim() === 'created'
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
removeWslGoldenStubAgent(distro, { createdCodexLink: false })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function removeWslGoldenStubAgent(distro: string): void {
|
||||
export function removeWslGoldenStubAgent(distro: string, stage: WslGoldenStubAgentStage): void {
|
||||
try {
|
||||
runInWslAsRoot(distro, UNSTAGE_SCRIPT)
|
||||
runInWslAsRoot(
|
||||
distro,
|
||||
stage.createdCodexLink ? REMOVE_CODEX_LINK_AND_STUB_SCRIPT : REMOVE_STUB_SCRIPT
|
||||
)
|
||||
} catch {
|
||||
// Best-effort cleanup; a leftover stub only affects this fixture's own name.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user