mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
refactor(test): organize SSH and terminal recovery fixtures (#17751)
This commit is contained in:
@@ -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([])
|
||||
})
|
||||
|
||||
|
||||
+4
-4
@@ -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,
|
||||
+3
-3
@@ -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
|
||||
+3
-3
@@ -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 () => {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
+5
-5
@@ -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 () => {
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user