Files
orca/src/main/ipc/runtime-environment-recovery-handler.test.ts
T
NeilandClaude bd6f586f5b fix(ssh): retry a stalled SSH reconnect when the machine wakes or the network returns (#29237)
* fix(ssh): retry a stalled SSH reconnect when the machine wakes or the network returns

After sleep, an SSH host could sit in reconnection-failed forever: the retry
ladder spent its nine attempts while the Mac was asleep or in dark wakes, and
nothing restarted it. Resume only re-probed managed tunnels, and the window's
online signal never reached SSH at all.

- SshConnection.retryAfterNetworkReturn restarts a spent ladder, a pending
  backoff, or a background handshake older than 5s with a fresh budget.
- Resume, unlock-screen and the window's resume/online signal
  (runtimeEnvironments:retryConnectionsNow) all call it via the manager and
  re-probe managed tunnels, so a transport that still looks connected after a
  network change is caught by the probe instead of keepalive.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): keep a superseded system-SSH probe from clearing its replacement's transport

A wake retry can now replace an in-flight handshake. Closing a system-SSH
probe only signals the process, so its late close used to reset the
transport state the replacement had just set up, leaving a connected host
whose exec failed with 'Not connected'.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): keep a superseded handshake from killing its replacement's proxy process

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-15 17:38:37 -07:00

30 lines
1.1 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
const handlers = vi.hoisted(() => new Map<string, () => unknown>())
const retrySharedControl = vi.hoisted(() => vi.fn())
const retrySsh = vi.hoisted(() => vi.fn())
vi.mock('electron', () => ({
ipcMain: {
removeHandler: (channel: string) => handlers.delete(channel),
handle: (channel: string, handler: () => unknown) => handlers.set(channel, handler)
}
}))
vi.mock('./runtime-environment-request-connections', () => ({
retryRemoteRuntimeSharedControlConnectionsNow: retrySharedControl
}))
vi.mock('./ssh-host-sleep-reconnect', () => ({
retrySshConnectionsAfterNetworkReturn: retrySsh
}))
import { registerRuntimeEnvironmentRecoveryHandler } from './runtime-environment-recovery-handler'
describe('runtimeEnvironments:retryConnectionsNow', () => {
it('retries SSH transports as well as shared control when the window reports the network back', () => {
registerRuntimeEnvironmentRecoveryHandler()
handlers.get('runtimeEnvironments:retryConnectionsNow')?.()
expect(retrySharedControl).toHaveBeenCalledTimes(1)
expect(retrySsh).toHaveBeenCalledTimes(1)
})
})