mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 00:03:59 +00:00
fix(mobile): keep an unhealthy Force Reconnect replacement
This commit is contained in:
@@ -739,6 +739,32 @@ describe('useHostClient', () => {
|
||||
harness.unmount()
|
||||
})
|
||||
|
||||
it('keeps a live replacement bound when Force Reconnect reports it unhealthy', async () => {
|
||||
const stale = makeFakeClient('connected')
|
||||
const fresh = makeFakeClient('connected')
|
||||
fresh.sendRequest = vi.fn(async () => {
|
||||
throw new Error('Application RPC channel is still not responding')
|
||||
})
|
||||
connectMock.mockReturnValueOnce(stale).mockReturnValueOnce(fresh)
|
||||
loadHostsMock.mockResolvedValue([HOST])
|
||||
|
||||
const harness = await renderHarness(HOST.id)
|
||||
await act(async () => {
|
||||
await expect(harness.forceReconnect(HOST.id)).rejects.toThrow(
|
||||
'Application RPC channel is still not responding'
|
||||
)
|
||||
})
|
||||
|
||||
// Regression: a rejected health check used to close and drop the
|
||||
// replacement, leaving a 'Disconnected' host with no retry loop and no
|
||||
// Reconnect affordance — the failure had to stay recoverable in-app.
|
||||
expect(fresh.closeMock).not.toHaveBeenCalled()
|
||||
expect(harness.hook.client).toBe(fresh)
|
||||
expect(harness.hook.state).toBe('connected')
|
||||
|
||||
harness.unmount()
|
||||
})
|
||||
|
||||
it('reports disconnected instead of hanging when the host id is unknown', async () => {
|
||||
loadHostsMock.mockResolvedValue([])
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('HostForceReconnectCoordinator', () => {
|
||||
await expect(reconnect).resolves.toBeUndefined()
|
||||
})
|
||||
|
||||
it('retires a replacement that fails RPC health verification', async () => {
|
||||
it('keeps a replacement that fails RPC health verification', async () => {
|
||||
const close = vi.fn()
|
||||
const unsubState = vi.fn()
|
||||
const client = {
|
||||
@@ -85,9 +85,11 @@ describe('HostForceReconnectCoordinator', () => {
|
||||
})
|
||||
).rejects.toThrow('health failed')
|
||||
|
||||
expect(unsubState).toHaveBeenCalledOnce()
|
||||
expect(close).toHaveBeenCalledOnce()
|
||||
expect(removeEntry).toHaveBeenCalledWith(fresh)
|
||||
expect(current).toBeUndefined()
|
||||
// Regression: retiring the replacement left the host with no client and no
|
||||
// retry loop, so a failed Force Reconnect was unrecoverable in-app.
|
||||
expect(unsubState).not.toHaveBeenCalled()
|
||||
expect(close).not.toHaveBeenCalled()
|
||||
expect(removeEntry).not.toHaveBeenCalledWith(fresh)
|
||||
expect(current).toBe(fresh)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -109,8 +109,10 @@ export class HostForceReconnectCoordinator {
|
||||
try {
|
||||
await verifyForceReconnectRpcHealth(fresh.client, deadline)
|
||||
} catch (error) {
|
||||
// Why: report the unhealthy verdict but keep the replacement — retiring it
|
||||
// strands the host with no client, no retry loop, and a 'Disconnected'
|
||||
// verdict that hides the Reconnect button the user needs to try again.
|
||||
if (!this.wasCancelled(operation.hostId, generation)) {
|
||||
this.retireCurrentEntry(operation, fresh)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user