refactor(test): organize SSH and terminal recovery fixtures (#17751)

This commit is contained in:
Neil
2026-08-31 18:18:15 -07:00
committed by GitHub
parent 40d245fe45
commit 2222e54754
16 changed files with 79 additions and 83 deletions
+3 -1
View File
@@ -316,7 +316,9 @@ describe('PR E2E gate contract', () => {
selectPrE2eSpecs(['src/renderer/src/hooks/remote-workspace-session-merge.test.ts'])
).toEqual([])
expect(
selectPrE2eSpecs(['src/renderer/src/hooks/remote-workspace-target-sync-test-harness.ts'])
selectPrE2eSpecs([
'src/renderer/src/hooks/__tests__/remote-workspace-target-sync-test-harness.ts'
])
).toEqual([])
})
@@ -1,8 +1,8 @@
import { vi, type Mock } from 'vitest'
import { makePaneKey } from '../../shared/stable-pane-id'
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
import type { RuntimeTerminalListResult } from '../../shared/runtime-types'
import { OrcaRuntimeService } from './orca-runtime'
import { makePaneKey } from '../../../shared/stable-pane-id'
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
import type { RuntimeTerminalListResult } from '../../../shared/runtime-types'
import { OrcaRuntimeService } from '../orca-runtime'
import {
CANARY_INCARNATION_ID,
CANARY_LEAF_ID,
@@ -1,5 +1,5 @@
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
import type { OrcaRuntimeService } from './orca-runtime'
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
import type { OrcaRuntimeService } from '../orca-runtime'
import {
CANARY_LEAF_ID,
CANARY_TAB_ID,
@@ -13,7 +13,7 @@ import {
canarySyncedLeaf,
canarySyncedTab
} from './orca-runtime-terminal-close-continuity-state-fixture'
import { makePaneKey } from '../../shared/stable-pane-id'
import { makePaneKey } from '../../../shared/stable-pane-id'
export type CloseContinuityGraphOptions = {
ptyId: string
@@ -1,6 +1,6 @@
import { getDefaultWorkspaceSession } from '../../shared/constants'
import { makePaneKey } from '../../shared/stable-pane-id'
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
import { getDefaultWorkspaceSession } from '../../../shared/constants'
import { makePaneKey } from '../../../shared/stable-pane-id'
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
export const REPO_ID = 'repo-close-continuity'
export const WORKTREE_PATH = '/tmp/terminal-close-continuity'
@@ -19,7 +19,7 @@ import {
STALE_TAB_ID,
TAB_ID,
WORKTREE_ID
} from './orca-runtime-terminal-close-continuity-fixtures'
} from './__fixtures__/orca-runtime-terminal-close-continuity-fixtures'
describe('terminal close and handle incarnation continuity', () => {
it('delegates a stale spawn-time tab through its current PTY-backed renderer surface', async () => {
+3 -3
View File
@@ -5,7 +5,7 @@ import type { MockSystemCommandChannel, MockSystemSshProcess } from './ssh-conne
import type { SshResolvedConfig } from './ssh-config-parser'
import type { SystemSshBuildArgsOptions } from './system-ssh-args'
import type { SshTarget } from '../../shared/ssh-types'
import { resetSsh2ClientState, ssh2Mock } from './ssh-connection-test-client'
import { resetSsh2ClientState, ssh2Mock } from './__tests__/ssh-connection-test-client'
export {
clientInstances,
connectAttempts,
@@ -17,8 +17,8 @@ export {
resetSsh2ClientState,
ssh2Mock,
VALID_ED25519_HOST_KEY
} from './ssh-connection-test-client'
export type { MockSshClient, Ssh2ModuleMock } from './ssh-connection-test-client'
} from './__tests__/ssh-connection-test-client'
export type { MockSshClient, Ssh2ModuleMock } from './__tests__/ssh-connection-test-client'
export type SystemSshBinaryModuleMock = { findSystemSsh: typeof findSystemSshMock }
@@ -2,14 +2,14 @@ import { vi } from 'vitest'
import type {
RemoteWorkspaceObservedPatchResult,
RemoteWorkspaceObservedSnapshot
} from '../../../shared/remote-workspace-types'
import type { DirectSshAuthority, SshProviderEpoch } from '../../../shared/ssh-types'
import type { AppState } from '../store/types'
} from '../../../../shared/remote-workspace-types'
import type { DirectSshAuthority, SshProviderEpoch } from '../../../../shared/ssh-types'
import type { AppState } from '../../store/types'
import type {
DirectSshPreparationInput,
DirectSshPreparationToken
} from './direct-ssh-reconnect-coordinator'
import { createRemoteWorkspaceTargetSync } from './remote-workspace-target-sync'
} from '../direct-ssh-reconnect-coordinator'
import { createRemoteWorkspaceTargetSync } from '../remote-workspace-target-sync'
export type Deferred<T> = {
promise: Promise<T>
@@ -18,7 +18,7 @@ import {
snapshot,
token,
worktree
} from './remote-workspace-target-sync-test-harness'
} from './__tests__/remote-workspace-target-sync-test-harness'
describe('createRemoteWorkspaceTargetSync', () => {
it('captures local tabs before get when deciding a revision-zero upload', async () => {
@@ -1,9 +1,9 @@
import type {
RuntimeMobileSessionTabsResult,
RuntimeMobileSessionTerminalClientTab
} from '../../../shared/runtime-types'
import { toRemoteRuntimePtyId } from './runtime-terminal-stream'
import type { TerminalOrphanRecoveryState } from './web-session-terminal-orphan-recovery-surface'
} from '../../../../shared/runtime-types'
import { toRemoteRuntimePtyId } from '../runtime-terminal-stream'
import type { TerminalOrphanRecoveryState } from '../web-session-terminal-orphan-recovery-surface'
export const ENVIRONMENT_ID = 'remote-runtime'
@@ -164,21 +164,45 @@ type ReceivedSessionTabsSnapshot = SnapshotFreshness & {
* minted by several publishers. Retain a bounded predecessor set so a frame
* queued by a restarted host cannot be mistaken for a fresh publication.
*/
type SessionTabsRuntimeHistory = {
type RetiredValueHistory = {
current: string | null
retired: string[]
}
function hasRetiredValue(history: RetiredValueHistory | undefined, value: string): boolean {
return history?.retired.includes(value) ?? false
}
function noteRetiredValue(
history: RetiredValueHistory | undefined,
value: string,
retiredLimit: number
): RetiredValueHistory {
if (!history) {
return { current: value, retired: [] }
}
if (history.current === value) {
return history
}
if (history.current && !history.retired.includes(history.current)) {
history.retired.push(history.current)
if (history.retired.length > retiredLimit) {
history.retired.splice(0, history.retired.length - retiredLimit)
}
}
history.current = value
return history
}
type SessionTabsRuntimeHistory = RetiredValueHistory
/**
* A host restart changes the publication epoch, but frames from the previous
* epoch can still be queued on a sibling subscription. Keep a small history
* of epochs that have already been superseded so those delayed frames cannot
* roll the mirror back after the replacement epoch is accepted.
*/
type SessionTabsPublicationEpochHistory = {
current: string
retired: string[]
}
type SessionTabsPublicationEpochHistory = RetiredValueHistory
type SessionTabsRecoveryState = {
pendingCount: number
@@ -438,32 +462,20 @@ function getSessionTabsRuntimeIdFromResponse(
}
function isRetiredSessionTabsRuntimeId(environmentId: string, runtimeId: string): boolean {
return (
sessionTabsRuntimeHistoryByEnvironment.get(environmentId)?.retired.includes(runtimeId) ?? false
)
return hasRetiredValue(sessionTabsRuntimeHistoryByEnvironment.get(environmentId), runtimeId)
}
function noteSessionTabsRuntimeId(
environmentId: string,
runtimeId: string
): SessionTabsRuntimeHistory {
const existing = sessionTabsRuntimeHistoryByEnvironment.get(environmentId)
if (!existing) {
const created: SessionTabsRuntimeHistory = { current: runtimeId, retired: [] }
sessionTabsRuntimeHistoryByEnvironment.set(environmentId, created)
return created
}
if (existing.current === runtimeId) {
return existing
}
if (existing.current && !existing.retired.includes(existing.current)) {
existing.retired.push(existing.current)
if (existing.retired.length > SESSION_TABS_RETIRED_RUNTIME_ID_LIMIT) {
existing.retired.splice(0, existing.retired.length - SESSION_TABS_RETIRED_RUNTIME_ID_LIMIT)
}
}
existing.current = runtimeId
return existing
const history = noteRetiredValue(
sessionTabsRuntimeHistoryByEnvironment.get(environmentId),
runtimeId,
SESSION_TABS_RETIRED_RUNTIME_ID_LIMIT
)
sessionTabsRuntimeHistoryByEnvironment.set(environmentId, history)
return history
}
function isCurrentSessionTabsRuntimeId(environmentId: string, runtimeId: string): boolean {
@@ -505,33 +517,20 @@ function acceptSessionTabsRuntimeId(
}
function isRetiredSessionTabsPublicationEpoch(key: string, publicationEpoch: string): boolean {
return (
sessionTabsPublicationEpochHistoryByWorktree.get(key)?.retired.includes(publicationEpoch) ??
false
)
return hasRetiredValue(sessionTabsPublicationEpochHistoryByWorktree.get(key), publicationEpoch)
}
function noteSessionTabsPublicationEpoch(
key: string,
publicationEpoch: string
): SessionTabsPublicationEpochHistory {
const existing = sessionTabsPublicationEpochHistoryByWorktree.get(key)
if (!existing) {
const created = { current: publicationEpoch, retired: [] }
sessionTabsPublicationEpochHistoryByWorktree.set(key, created)
return created
}
if (existing.current === publicationEpoch) {
return existing
}
if (!existing.retired.includes(existing.current)) {
existing.retired.push(existing.current)
if (existing.retired.length > SESSION_TABS_RETIRED_EPOCH_LIMIT) {
existing.retired.splice(0, existing.retired.length - SESSION_TABS_RETIRED_EPOCH_LIMIT)
}
}
existing.current = publicationEpoch
return existing
const history = noteRetiredValue(
sessionTabsPublicationEpochHistoryByWorktree.get(key),
publicationEpoch,
SESSION_TABS_RETIRED_EPOCH_LIMIT
)
sessionTabsPublicationEpochHistoryByWorktree.set(key, history)
return history
}
function recordReceivedWebSessionTabsSnapshot(
@@ -6,7 +6,7 @@ import {
makeSnapshot,
makeState,
pendingSurface
} from './web-session-terminal-orphan-recovery-regression-fixtures'
} from './__fixtures__/web-session-terminal-orphan-recovery-regression-fixtures'
import {
clearWebSessionTerminalOrphanRecoveryForTests,
recoverWebSessionTerminalOrphansBeforeApply
@@ -7,7 +7,7 @@ import {
makeSnapshot,
makeState,
pendingSurface
} from './web-session-terminal-orphan-recovery-regression-fixtures'
} from './__fixtures__/web-session-terminal-orphan-recovery-regression-fixtures'
import {
clearWebSessionTerminalOrphanRecoveryForTests,
recoverWebSessionTerminalOrphansBeforeApply
@@ -11,7 +11,7 @@ import {
makeSnapshot,
makeState,
pendingSurface
} from './web-session-terminal-orphan-recovery-regression-fixtures'
} from './__fixtures__/web-session-terminal-orphan-recovery-regression-fixtures'
import {
clearWebSessionTerminalOrphanRecoveryForTests,
recoverWebSessionTerminalOrphansBeforeApply
@@ -7,7 +7,7 @@ import {
makeSnapshot,
makeState,
pendingSurface
} from './web-session-terminal-orphan-recovery-regression-fixtures'
} from './__fixtures__/web-session-terminal-orphan-recovery-regression-fixtures'
import {
clearWebSessionTerminalOrphanRecoveryForTests,
recoverWebSessionTerminalOrphansBeforeApply
@@ -81,6 +81,7 @@ async function recoverTerminalOrphans(
const localTopologyIsCurrent = (): boolean =>
!getCurrentState ||
captureTerminalRecoveryTopologyToken(getCurrentState(), snapshot.worktree) === topologyToken
const isRecoveryCurrent = (): boolean => isCurrent() && localTopologyIsCurrent()
const prepared = prepareTerminalOrphanRecovery(recoveryState, snapshot, environmentId)
if (
prepared.candidates.length === 0 &&
@@ -97,10 +98,7 @@ async function recoverTerminalOrphans(
expectedEnvironmentPairingRevision,
isCurrent
})
if (!paneResolution || !isCurrent()) {
return null
}
if (!localTopologyIsCurrent()) {
if (!paneResolution || !isRecoveryCurrent()) {
return null
}
const candidates = [...prepared.candidates, ...paneResolution.resolved]
@@ -117,10 +115,7 @@ async function recoverTerminalOrphans(
expectedEnvironmentPairingRevision,
isCurrent
})
if (!inventory || !isCurrent()) {
return null
}
if (!localTopologyIsCurrent()) {
if (!inventory || !isRecoveryCurrent()) {
return null
}
const { retained, removed, claims } = inventory
@@ -220,7 +215,7 @@ async function recoverTerminalOrphans(
const adoptedSnapshot = adoptionResponse.result.snapshot
const adoptedRows = terminalRowsBySurface(adoptedSnapshot)
const missingClaims = claimSurfaces(candidates, claims).filter((surface) => {
const missingClaims = claimedSurfaces.filter((surface) => {
const rows = adoptedRows.get(surfaceKey(surface.tabId, surface.leafId))
return !rows?.some(isValidReadySurface)
})