mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 00:03:59 +00:00
fix(ssh): fence reset transport opens during shutdown
This commit is contained in:
@@ -2520,6 +2520,51 @@ describe('SSH IPC handlers', () => {
|
||||
expect(mockConnectionManager.disconnect).toHaveBeenCalledWith('ssh-1')
|
||||
})
|
||||
|
||||
it('ssh:resetRelay does not open a transport when shutdown starts while it waits for a connect', async () => {
|
||||
const target: SshTarget = {
|
||||
id: 'ssh-1',
|
||||
label: 'Server',
|
||||
host: 'example.com',
|
||||
port: 22,
|
||||
username: 'deploy'
|
||||
}
|
||||
let failConnect!: (error: unknown) => void
|
||||
const connectResult = new Promise((_resolve, reject) => {
|
||||
failConnect = reject
|
||||
})
|
||||
mockSshStore.getTarget.mockReturnValue(target)
|
||||
mockConnectionManager.connect.mockReturnValue(connectResult)
|
||||
// Why undefined: reset must fall through to opening its own transport, which is the call under test.
|
||||
mockConnectionManager.getConnection.mockReturnValue(undefined)
|
||||
mockConnectionManager.getState.mockReturnValue({
|
||||
targetId: 'ssh-1',
|
||||
status: 'connected',
|
||||
error: null,
|
||||
reconnectAttempt: 0
|
||||
})
|
||||
|
||||
const connectPromise = handlers.get('ssh:connect')!(null, {
|
||||
targetId: 'ssh-1'
|
||||
}) as Promise<unknown>
|
||||
await vi.waitFor(() => expect(mockConnectionManager.connect).toHaveBeenCalledTimes(1))
|
||||
|
||||
// Why admitted first: the gate latches only after reset is already parked behind the connect, so
|
||||
// the entry fence cannot be what stops it.
|
||||
const resetPromise = handlers.get('ssh:resetRelay')!(null, {
|
||||
targetId: 'ssh-1'
|
||||
}) as Promise<void>
|
||||
await Promise.resolve()
|
||||
|
||||
quitTeardownStartGate.tryStart({ preventDefault() {} })
|
||||
failConnect(new Error('transport lost'))
|
||||
await expect(connectPromise).rejects.toThrow('transport lost')
|
||||
|
||||
await expect(resetPromise).rejects.toThrow('closed for app shutdown')
|
||||
// Why once: the resumed reset must not open a second transport that would outlive the drain.
|
||||
expect(mockConnectionManager.connect).toHaveBeenCalledTimes(1)
|
||||
expect(mockForceStopRelayForTarget).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('ssh:connect waits for an in-flight reset before starting a new connection', async () => {
|
||||
const target: SshTarget = {
|
||||
id: 'ssh-1',
|
||||
|
||||
+7
-1
@@ -1319,7 +1319,13 @@ export function registerSshHandlers(
|
||||
}
|
||||
|
||||
const existingConn = connectionManager!.getConnection(targetId)
|
||||
const conn = existingConn ?? (await connectionManager!.connect(target))
|
||||
let conn = existingConn
|
||||
if (!conn) {
|
||||
// Why re-check: admission fenced this reset before it parked on the in-flight connect, so shutdown
|
||||
// may have started (and drained) while we waited — opening a transport now would outlive the drain.
|
||||
assertSshConnectsNotFenced()
|
||||
conn = await connectionManager!.connect(target)
|
||||
}
|
||||
try {
|
||||
await forceStopRelayForTarget(conn, targetId)
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user