import { beforeEach, describe, expect, it, vi } from 'vitest' import { SshRelaySession } from './ssh-relay-session' import { createMockDeps, mockDeploySuccess } from './ssh-relay-session-test-fixtures' const { acceptOutputDataMock, muxRequestMock, onNotificationByMethodMock, notifyWithSettlementMock, openConsumerSessionMock, pauseAdapterMock, muxDisposeMock, attachForReconnectMock, beginMigrationMock, ptyDataHandlerRef } = vi.hoisted(() => ({ acceptOutputDataMock: vi.fn().mockResolvedValue(undefined), muxRequestMock: vi.fn(), onNotificationByMethodMock: vi.fn(), notifyWithSettlementMock: vi.fn(), openConsumerSessionMock: vi.fn(), pauseAdapterMock: vi.fn(), muxDisposeMock: vi.fn(), attachForReconnectMock: vi.fn().mockResolvedValue({}), beginMigrationMock: vi.fn(() => ({ byPty: new Map(), completion: Promise.resolve() })), ptyDataHandlerRef: { current: undefined as undefined | ((payload: unknown) => void) } })) vi.mock('./ssh-relay-deploy', () => ({ deployAndLaunchRelay: vi.fn() })) vi.mock('./ssh-pty-consumer-session', () => ({ openSshPtyConsumerSession: openConsumerSessionMock })) vi.mock('../ipc/ssh-pty-output-intake-registry', () => ({ acceptSshPtyOutputData: acceptOutputDataMock, acceptSshPtyOutputExit: vi.fn().mockResolvedValue(undefined), allocateSshPtyProviderGeneration: vi.fn(() => 23), beginSshPtyOutputGenerationMigration: beginMigrationMock, closeSshPtyOutputGeneration: vi.fn(), getSshPtyAcceptedSourceCheckpoints: vi.fn(() => []), installSshPtySourceAckPublisher: vi.fn(() => () => {}), installSshPtySourceCancellationPublisher: vi.fn(() => () => {}), applySshPtySourceCancellationProof: vi.fn(), applySshPtySourceRecoveryCancellationProof: vi.fn() })) vi.mock('./ssh-channel-multiplexer', () => ({ SshChannelMultiplexer: class MockSshChannelMultiplexer { notify = vi.fn() notifyWithSettlement = notifyWithSettlementMock request = muxRequestMock onNotification = vi.fn().mockReturnValue(() => {}) onNotificationByMethod = onNotificationByMethodMock.mockImplementation(() => () => {}) onRequest = vi.fn().mockReturnValue(() => {}) onDispose = vi.fn().mockReturnValue(() => {}) dispose = muxDisposeMock isDisposed = vi.fn().mockReturnValue(false) } })) vi.mock('../agent-hooks/remote-managed-hook-installers', () => ({ installRemoteManagedAgentHooks: vi.fn().mockResolvedValue([]) })) vi.mock('../providers/ssh-pty-provider', () => ({ isSshPtyNotFoundError: vi.fn().mockReturnValue(false), isSshPtyIdentityMismatchError: vi.fn().mockReturnValue(false), SshPtyProvider: class MockSshPtyProvider { onData = vi.fn().mockImplementation((handler) => { ptyDataHandlerRef.current = handler return () => {} }) onReplay = vi.fn().mockReturnValue(() => {}) onExit = vi.fn().mockReturnValue(() => {}) attach = vi.fn().mockResolvedValue(undefined) attachForReconnect = attachForReconnectMock setPtyDeliveryPauseAdapter = pauseAdapterMock dispose = vi.fn() } })) vi.mock('../providers/ssh-filesystem-provider', () => ({ SshFilesystemProvider: class MockSshFilesystemProvider { dispose = vi.fn() } })) vi.mock('../providers/ssh-git-provider', () => ({ SshGitProvider: class MockSshGitProvider {} })) vi.mock('../ipc/pty', () => ({ registerSshPtyProvider: vi.fn(), unregisterSshPtyProvider: vi.fn(), getSshPtyProvider: vi.fn().mockReturnValue({ dispose: vi.fn() }), getPtyIdsForConnection: vi.fn().mockReturnValue([]), clearPtyOwnershipForConnection: vi.fn(), clearProviderPtyState: vi.fn(), deletePtyOwnership: vi.fn(), restorePtyIncarnation: vi.fn(), setPtyOwnership: vi.fn() })) vi.mock('../providers/ssh-filesystem-dispatch', () => ({ registerSshFilesystemProvider: vi.fn(), unregisterSshFilesystemProvider: vi.fn(), getSshFilesystemProvider: vi.fn().mockReturnValue({ dispose: vi.fn() }) })) vi.mock('../providers/ssh-git-dispatch', () => ({ registerSshGitProvider: vi.fn(), unregisterSshGitProvider: vi.fn() })) const { clearProviderPtyState, clearPtyOwnershipForConnection, deletePtyOwnership, getSshPtyProvider, getPtyIdsForConnection, registerSshPtyProvider, setPtyOwnership } = await import('../ipc/pty') const { closeSshPtyOutputGeneration } = await import('../ipc/ssh-pty-output-intake-registry') const { applySshPtySourceCancellationProof } = await import('../ipc/ssh-pty-output-intake-registry') const { applySshPtySourceRecoveryCancellationProof } = await import('../ipc/ssh-pty-output-intake-registry') const { getSshPtyAcceptedSourceCheckpoints } = await import('../ipc/ssh-pty-output-intake-registry') const { installSshPtySourceAckPublisher } = await import('../ipc/ssh-pty-output-intake-registry') const { deployAndLaunchRelay } = await import('./ssh-relay-deploy') describe('SshRelaySession data delivery', () => { beforeEach(() => { vi.clearAllMocks() ptyDataHandlerRef.current = undefined attachForReconnectMock.mockResolvedValue({}) vi.mocked(getPtyIdsForConnection).mockReturnValue([]) vi.mocked(getSshPtyAcceptedSourceCheckpoints).mockReturnValue([]) vi.mocked(applySshPtySourceCancellationProof).mockReturnValue(true) vi.mocked(applySshPtySourceRecoveryCancellationProof).mockReturnValue(true) openConsumerSessionMock.mockImplementation(async (_mux, options) => ({ state: { mode: 'negotiated', clientInstanceId: options.clientInstanceId, clientGeneration: 1, ownerGeneration: 1, ownerLease: 'test-owner-lease', ...(options.outputFlowControl ? { outputFlowControl: { version: 1, windowSu: options.outputFlowControl.requestedWindowSu } } : {}) }, resumed: options.resume !== undefined })) muxRequestMock.mockResolvedValue([]) mockDeploySuccess() }) async function runRecoverySequence(args: { targetId: string recoveryEndSu: number recoveryFrame?: readonly [startSu: number, endSu: number] liveFrame?: readonly [startSu: number, endSu: number] }) { muxRequestMock.mockImplementation(async (method) => method === 'pty.cancelDelivery' ? { canceled: true, sentEndSu: args.recoveryEndSu, creditedEndSu: 4 } : [] ) let generation = 0 openConsumerSessionMock.mockImplementation(async (_mux, options) => ({ state: { mode: 'negotiated', clientInstanceId: options.clientInstanceId, clientGeneration: ++generation, ownerGeneration: generation, ownerLease: `owner-lease-${generation}`, outputFlowControl: { version: 1, windowSu: 256 * 1024 } }, resumed: options.resume !== undefined })) vi.mocked(getSshPtyAcceptedSourceCheckpoints).mockReturnValue([ { id: `ssh:${args.targetId}@@pty-1`, providerGeneration: 23, clientGeneration: 1, ownerGeneration: 1, ptyIncarnation: 'incarnation-1', deliveryToken: 'old-token', acceptedSourceEndSu: 4 } ]) const deps = createMockDeps() const session = new SshRelaySession( args.targetId, deps.getMainWindow, deps.mockStore, deps.mockPortForward ) await session.establish(deps.mockConn) vi.mocked(getPtyIdsForConnection).mockReturnValue([`ssh:${args.targetId}@@pty-1`]) vi.mocked(getSshPtyProvider).mockImplementation( () => vi.mocked(registerSshPtyProvider).mock.calls.at(-1)?.[1] ) attachForReconnectMock.mockImplementation(async () => { queueMicrotask(() => { if (args.recoveryFrame) { const [sourceStartSu, sourceEndSu] = args.recoveryFrame ptyDataHandlerRef.current?.({ id: `ssh:${args.targetId}@@pty-1`, data: 'recovery', providerGeneration: 23, ptyIncarnation: 'incarnation-1', sequenceChars: sourceEndSu - sourceStartSu, source: { relayPtyId: 'pty-1', spanId: `new-token:${sourceStartSu}:${sourceEndSu}`, clientGeneration: 2, ownerGeneration: 2, deliveryToken: 'new-token', sourceStartSu, sourceEndSu } }) } const complete = onNotificationByMethodMock.mock.calls.findLast( ([method]) => method === 'pty.recoveryComplete' )?.[1] as ((params: Record) => void) | undefined complete?.({ id: 'pty-1', clientGeneration: 2, ownerGeneration: 2, ptyIncarnation: 'incarnation-1', deliveryToken: 'new-token', checkpointSourceEndSu: 4, recoveryEndSu: args.recoveryEndSu }) if (args.liveFrame) { const [sourceStartSu, sourceEndSu] = args.liveFrame ptyDataHandlerRef.current?.({ id: `ssh:${args.targetId}@@pty-1`, data: 'live', providerGeneration: 23, ptyIncarnation: 'incarnation-1', sequenceChars: sourceEndSu - sourceStartSu, source: { relayPtyId: 'pty-1', spanId: `new-token:${sourceStartSu}:${sourceEndSu}`, clientGeneration: 2, ownerGeneration: 2, deliveryToken: 'new-token', sourceStartSu, sourceEndSu } }) } }) return { incarnationId: 'incarnation-1', sourceRecovery: { status: 'pending', clientGeneration: 2, ownerGeneration: 2, ptyIncarnation: 'incarnation-1', deliveryToken: 'new-token', checkpointSourceEndSu: 4, recoveryEndSu: args.recoveryEndSu } } }) await session.reconnect(deps.mockConn) return { ...deps, session } } it('transfers negotiated owner recovery exactly once across an explicit detach', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() vi.mocked(deployAndLaunchRelay).mockResolvedValue({ transport: { write: vi.fn(), onData: vi.fn(), onClose: vi.fn() }, platform: 'linux-x64', serverBuildId: 'test-relay-build' }) const first = new SshRelaySession('recovery-target', getMainWindow, mockStore, mockPortForward) await first.establish(mockConn) first.detach() const second = new SshRelaySession('recovery-target', getMainWindow, mockStore, mockPortForward) await second.establish(mockConn) const firstOpen = openConsumerSessionMock.mock.calls[0]?.[1] const recoveredOpen = openConsumerSessionMock.mock.calls[1]?.[1] expect(recoveredOpen).toMatchObject({ clientInstanceId: firstOpen.clientInstanceId, resume: { ownerGeneration: 1, ownerLease: 'test-owner-lease' } }) second.dispose() const fresh = new SshRelaySession('recovery-target', getMainWindow, mockStore, mockPortForward) await fresh.establish(mockConn) const freshOpen = openConsumerSessionMock.mock.calls[2]?.[1] expect(freshOpen.clientInstanceId).not.toBe(firstOpen.clientInstanceId) expect(freshOpen).not.toHaveProperty('resume') fresh.dispose() }) it('resumes authenticated ownership from a persisted main-process recovery record', async () => { const targetId = 'persisted-recovery-target' const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() vi.mocked(mockStore.getSshPtyConsumerRecovery).mockReturnValue({ targetId, clientInstanceId: 'persisted-client', serverBuildId: 'test-relay-build', clientGeneration: 7, ownerGeneration: 11, ownerLease: 'persisted-owner-lease', outputFlowControl: { version: 1, windowSu: 256 * 1024 } }) vi.mocked(deployAndLaunchRelay).mockResolvedValue({ transport: { write: vi.fn(), onData: vi.fn(), onClose: vi.fn() }, platform: 'linux-x64', serverBuildId: 'test-relay-build' }) const session = new SshRelaySession(targetId, getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) expect(openConsumerSessionMock).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ clientInstanceId: 'persisted-client', resume: { ownerGeneration: 11, ownerLease: 'persisted-owner-lease' } }) ) expect(mockStore.upsertSshPtyConsumerRecovery).toHaveBeenCalledWith( expect.objectContaining({ targetId, clientInstanceId: 'persisted-client', ownerLease: 'test-owner-lease' }) ) session.dispose() expect(mockStore.removeSshPtyConsumerRecovery).toHaveBeenCalledWith(targetId) }) it('voids checkpoints for a fresh claim without a second owner request', async () => { const targetId = 'fresh-relay-retry' const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() vi.mocked(deployAndLaunchRelay).mockResolvedValue({ transport: { write: vi.fn(), onData: vi.fn(), onClose: vi.fn() }, platform: 'linux-x64', serverBuildId: 'test-relay-build' }) vi.mocked(getSshPtyAcceptedSourceCheckpoints).mockReturnValue([ { id: `ssh:${targetId}@@pty-1`, providerGeneration: 23, clientGeneration: 1, ownerGeneration: 1, ptyIncarnation: 'incarnation-1', deliveryToken: 'old-token', acceptedSourceEndSu: 4 } ]) const first = new SshRelaySession(targetId, getMainWindow, mockStore, mockPortForward) await first.establish(mockConn) first.detach() openConsumerSessionMock.mockImplementationOnce(async (_mux, options) => ({ state: { mode: 'negotiated', clientInstanceId: options.clientInstanceId, clientGeneration: 1, ownerGeneration: 1, ownerLease: 'fresh-owner-lease', outputFlowControl: { version: 1, windowSu: 256 * 1024 } }, resumed: false })) vi.mocked(getPtyIdsForConnection).mockReturnValue([`ssh:${targetId}@@pty-1`]) vi.mocked(getSshPtyProvider).mockImplementation( () => vi.mocked(registerSshPtyProvider).mock.calls.at(-1)?.[1] ) attachForReconnectMock.mockResolvedValue({ incarnationId: 'incarnation-1', sourceRecovery: { status: 'restoreRequired', reason: 'checkpointUnavailable' } }) const second = new SshRelaySession(targetId, getMainWindow, mockStore, mockPortForward) const openCallCountBeforeRetry = openConsumerSessionMock.mock.calls.length await second.establish(mockConn) const retryCalls = openConsumerSessionMock.mock.calls .slice(openCallCountBeforeRetry) .map(([, options]) => options) // Why one call: the relay answers a proof it cannot match with a fresh claim, so the client never // needs a second, resume-less request to get owner authority back. expect(retryCalls).toHaveLength(1) expect(retryCalls[0]).toHaveProperty('resume') expect(attachForReconnectMock).toHaveBeenCalledWith( 'pty-1', undefined, Object.freeze({ status: 'checkpointUnavailable' }) ) second.dispose() }) it('delivers empty transformed relay spans with raw sequence metadata', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow, mockWindow } = createMockDeps() const runtime = { onPtyData: vi.fn(() => 17), onPtyExit: vi.fn() } const session = new SshRelaySession( 'target-1', getMainWindow, mockStore, mockPortForward, runtime as never ) await session.establish(mockConn) const ptyProvider = vi.mocked(registerSshPtyProvider).mock.calls[0]?.[1] as unknown as { onData: ReturnType } const onData = ptyProvider.onData.mock.calls[0]?.[0] as (payload: { id: string data: string sequenceChars?: number transformed?: boolean providerGeneration: number ptyIncarnation: string source: { relayPtyId: string spanId: string clientGeneration: number ownerGeneration: number deliveryToken: string sourceStartSu: number sourceEndSu: number } }) => void const source = { relayPtyId: 'pty-1', spanId: 'token-1:0:9', clientGeneration: 1, ownerGeneration: 1, deliveryToken: 'token-1', sourceStartSu: 0, sourceEndSu: 9 } onData({ id: 'ssh-pty-1', data: '', sequenceChars: 9, transformed: true, providerGeneration: 23, ptyIncarnation: 'incarnation-1', source }) expect(acceptOutputDataMock).toHaveBeenCalledWith({ id: 'ssh-pty-1', data: '', providerGeneration: 23, ptyIncarnation: 'incarnation-1', rawLength: 9, transformed: true, source }) expect(runtime.onPtyData).not.toHaveBeenCalled() expect(mockWindow.webContents.send).not.toHaveBeenCalledWith('pty:data', expect.anything()) }) it('forwards negotiated source identity to the bounded intake exactly once', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) const ptyProvider = vi.mocked(registerSshPtyProvider).mock.calls[0]?.[1] as unknown as { onData: ReturnType } const onData = ptyProvider.onData.mock.calls[0]?.[0] as (payload: { id: string data: string providerGeneration: number ptyIncarnation: string source: { relayPtyId: string spanId: string clientGeneration: number ownerGeneration: number deliveryToken: string sourceStartSu: number sourceEndSu: number } }) => void const source = { relayPtyId: 'pty-1', spanId: 'token-1:0:4', clientGeneration: 1, ownerGeneration: 1, deliveryToken: 'token-1', sourceStartSu: 0, sourceEndSu: 4 } onData({ id: 'ssh-pty-1', data: 'data', providerGeneration: 23, ptyIncarnation: 'incarnation-1', source }) expect(acceptOutputDataMock).toHaveBeenCalledOnce() expect(acceptOutputDataMock).toHaveBeenCalledWith( expect.objectContaining({ id: 'ssh-pty-1', rawLength: 4, source }) ) }) it('quarantines missing negotiated source identity before main admission', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) const provider = vi.mocked(registerSshPtyProvider).mock.calls[0]?.[1] as unknown as { onData: ReturnType } const onData = provider.onData.mock.calls[0]?.[0] as (payload: Record) => void onData({ id: 'ssh-pty-1', data: 'data', providerGeneration: 23, ptyIncarnation: 'incarnation-1' }) expect(acceptOutputDataMock).not.toHaveBeenCalled() expect(closeSshPtyOutputGeneration).not.toHaveBeenCalled() expect(muxDisposeMock).not.toHaveBeenCalled() }) it('keeps unoffered source metadata out of legacy intake', async () => { openConsumerSessionMock.mockImplementationOnce(async (_mux, options) => ({ mode: 'legacy-fallback', clientInstanceId: options.clientInstanceId, serverBuildId: 'test-relay-build' })) const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) const provider = vi.mocked(registerSshPtyProvider).mock.calls[0]?.[1] as unknown as { onData: ReturnType } const onData = provider.onData.mock.calls[0]?.[0] as (payload: Record) => void onData({ id: 'ssh-pty-1', data: 'data', providerGeneration: 23, ptyIncarnation: 'incarnation-1', source: { relayPtyId: 'pty-1', spanId: 'token-1:0:4', clientGeneration: 1, ownerGeneration: 1, deliveryToken: 'token-1', sourceStartSu: 0, sourceEndSu: 4 } }) expect(acceptOutputDataMock).toHaveBeenCalledWith( expect.not.objectContaining({ source: expect.anything() }) ) }) it('keeps same-build method-not-found fallback token-free', async () => { openConsumerSessionMock.mockImplementationOnce(async (_mux, options) => ({ mode: 'legacy-fallback', clientInstanceId: options.clientInstanceId, serverBuildId: 'test-relay-build' })) const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) expect(session.getState()).toBe('ready') expect(pauseAdapterMock).not.toHaveBeenCalled() expect(openConsumerSessionMock.mock.calls[0][1]).toHaveProperty('outputFlowControl') expect(installSshPtySourceAckPublisher).not.toHaveBeenCalled() }) it('publishes negotiated ACK batches through mux settlement', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) const publish = vi.mocked(installSshPtySourceAckPublisher).mock.calls[0]?.[1] const settled = vi.fn() const batch = { acknowledgements: [ { id: 'pty-1', clientGeneration: 1, ownerGeneration: 1, deliveryToken: 'token-1', creditedEndSu: 4 } ] } publish?.(batch, settled) expect(openConsumerSessionMock.mock.calls[0][1]).toMatchObject({ outputFlowControl: { requestedWindowSu: 256 * 1024 } }) expect(deployAndLaunchRelay).toHaveBeenCalledWith(mockConn, undefined, undefined, 'target-1') expect(notifyWithSettlementMock).toHaveBeenCalledWith('pty.ackData', batch, settled) }) it('offers V1 through reconnect negotiation', async () => { const { mockConn, mockStore, mockPortForward, getMainWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) await session.reconnect(mockConn) expect(openConsumerSessionMock.mock.calls[0][1]).toHaveProperty('outputFlowControl') expect(openConsumerSessionMock.mock.calls[1][1]).toHaveProperty('outputFlowControl') expect(deployAndLaunchRelay).toHaveBeenNthCalledWith( 1, mockConn, undefined, undefined, 'target-1' ) expect(deployAndLaunchRelay).toHaveBeenNthCalledWith( 2, mockConn, undefined, undefined, 'target-1' ) }) it('reattaches V1 from an exact checkpoint and quarantines live data until recoveryComplete', async () => { let generation = 0 openConsumerSessionMock.mockImplementation(async (_mux, options) => { generation++ return { state: { mode: 'negotiated', clientInstanceId: options.clientInstanceId, clientGeneration: generation, ownerGeneration: generation, ownerLease: `owner-lease-${generation}`, outputFlowControl: { version: 1, windowSu: 256 * 1024 } }, resumed: options.resume !== undefined } }) vi.mocked(getSshPtyAcceptedSourceCheckpoints).mockReturnValue([ { id: 'ssh:target-1@@pty-1', providerGeneration: 23, clientGeneration: 1, ownerGeneration: 1, ptyIncarnation: 'incarnation-1', deliveryToken: 'old-token', acceptedSourceEndSu: 4 } ]) const { mockConn, mockStore, mockPortForward, getMainWindow, mockWindow } = createMockDeps() const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward) await session.establish(mockConn) vi.mocked(getPtyIdsForConnection).mockReturnValue(['ssh:target-1@@pty-1']) vi.mocked(getSshPtyProvider).mockImplementation( () => vi.mocked(registerSshPtyProvider).mock.calls.at(-1)?.[1] ) let transferDisposedMux = false const publishHeldRecovery = (sink: (payload: unknown) => void): void => { for (const [data, sourceStartSu, sourceEndSu] of [ ['re', 4, 6], ['co', 6, 8], ['live', 8, 12] ] as const) { sink({ id: 'ssh:target-1@@pty-1', data, providerGeneration: 23, ptyIncarnation: 'incarnation-1', sequenceChars: sourceEndSu - sourceStartSu, source: { relayPtyId: 'pty-1', spanId: `new-token:${sourceStartSu}:${sourceEndSu}`, clientGeneration: 2, ownerGeneration: 2, deliveryToken: 'new-token', sourceStartSu, sourceEndSu } }) } } const recoveryActivationLease = { commit: vi.fn(), retire: vi.fn() } const sourceActivationLease = { commit: vi.fn(), rollback: vi.fn(async () => true), transferToRecovery: vi.fn((sink: (payload: unknown) => void) => { publishHeldRecovery(sink) return recoveryActivationLease }) } attachForReconnectMock.mockImplementation(async () => { const canceled = onNotificationByMethodMock.mock.calls.findLast( ([method]) => method === 'pty.deliveryCanceled' )?.[1] as ((params: Record) => void) | undefined const disposeCount = muxDisposeMock.mock.calls.length canceled?.({ id: 'pty-1', clientGeneration: 1, ownerGeneration: 1, ptyIncarnation: 'incarnation-1', deliveryToken: 'old-token', replacementDeliveryToken: 'new-token' }) transferDisposedMux = muxDisposeMock.mock.calls.length !== disposeCount queueMicrotask(() => { const complete = onNotificationByMethodMock.mock.calls.findLast( ([method]) => method === 'pty.recoveryComplete' )?.[1] as ((params: Record) => void) | undefined complete?.({ id: 'pty-1', clientGeneration: 2, ownerGeneration: 2, ptyIncarnation: 'incarnation-1', deliveryToken: 'new-token', checkpointSourceEndSu: 4, recoveryEndSu: 8 }) }) return { incarnationId: 'incarnation-1', sourceRecovery: { status: 'pending', clientGeneration: 2, ownerGeneration: 2, ptyIncarnation: 'incarnation-1', deliveryToken: 'new-token', checkpointSourceEndSu: 4, recoveryEndSu: 8 }, sourceActivationLease } }) await session.reconnect(mockConn) expect(attachForReconnectMock).toHaveBeenCalledWith( 'pty-1', undefined, expect.objectContaining({ status: 'checkpoint', deliveryToken: 'old-token', acceptedSourceEndSu: 4 }) ) expect(acceptOutputDataMock.mock.calls.map(([payload]) => payload.data)).toEqual([ 're', 'co', 'live' ]) expect(transferDisposedMux).toBe(false) expect(sourceActivationLease.transferToRecovery).toHaveBeenCalledOnce() expect(sourceActivationLease.commit).not.toHaveBeenCalled() expect(sourceActivationLease.rollback).not.toHaveBeenCalled() expect(recoveryActivationLease.commit).toHaveBeenCalledOnce() expect(recoveryActivationLease.retire).not.toHaveBeenCalled() expect(mockWindow.webContents.send).not.toHaveBeenCalledWith('pty:replay', expect.anything()) const closeCount = vi.mocked(closeSshPtyOutputGeneration).mock.calls.length const canceled = onNotificationByMethodMock.mock.calls.findLast( ([method]) => method === 'pty.deliveryCanceled' )?.[1] as ((params: Record) => void) | undefined canceled?.({ id: 'pty-1', clientGeneration: 1, ownerGeneration: 1, ptyIncarnation: 'incarnation-1', deliveryToken: 'old-token' }) expect(closeSshPtyOutputGeneration).toHaveBeenCalledTimes(closeCount) }) it.each([ ['gap', [5, 8] as const], ['overlap', [3, 8] as const], ['incomplete suffix', [4, 6] as const], ['missing body', undefined] ])('rejects %s recovery without destroying the physical PTY or lease', async (label, frame) => { const targetId = `invalid-recovery-${label.replace(' ', '-')}` const { mockStore, mockWindow } = await runRecoverySequence({ targetId, recoveryEndSu: 8, ...(frame ? { recoveryFrame: frame } : {}) }) expect(acceptOutputDataMock).not.toHaveBeenCalled() expect(muxRequestMock).toHaveBeenCalledWith('pty.cancelDelivery', { id: 'pty-1', clientGeneration: 2, ownerGeneration: 2, deliveryToken: 'new-token' }) expect(applySshPtySourceRecoveryCancellationProof).toHaveBeenCalledWith( { id: `ssh:${targetId}@@pty-1`, code: -1, providerGeneration: 23, ptyIncarnation: 'incarnation-1' }, { sentEndSu: 8, creditedEndSu: 4 } ) expect(mockStore.markSshRemotePtyLease).toHaveBeenCalledWith(targetId, 'pty-1', 'detached') expect(mockStore.markSshRemotePtyLease).not.toHaveBeenCalledWith(targetId, 'pty-1', 'expired') expect(mockStore.markSshRemotePtyLeasesAsync).not.toHaveBeenCalled() expect(clearProviderPtyState).not.toHaveBeenCalled() expect(clearPtyOwnershipForConnection).not.toHaveBeenCalled() expect(deletePtyOwnership).not.toHaveBeenCalled() expect(setPtyOwnership).not.toHaveBeenCalled() expect(muxDisposeMock).not.toHaveBeenCalledWith('shutdown') expect(mockWindow.webContents.send).not.toHaveBeenCalledWith('pty:exit', expect.anything()) }) it('accepts empty recovery only when the checkpoint equals the recovery end', async () => { const { mockStore } = await runRecoverySequence({ targetId: 'empty-recovery', recoveryEndSu: 4, liveFrame: [4, 8] }) expect(acceptOutputDataMock.mock.calls.map(([payload]) => payload.data)).toEqual(['live']) expect(mockStore.markSshRemotePtyLeasesAttachedAsync).toHaveBeenCalledWith('empty-recovery', [ 'pty-1' ]) }) })