import { describe, expect, it, vi } from 'vitest'; import { PiManagedInputRevisionCoordinator } from '@electron/coding-runtime/pi/managed-input-revision'; import { PiProviderRefreshCoordinator } from '@electron/coding-runtime/pi/provider-refresh'; describe('Pi Provider refresh coordination', () => { it('coalesces concurrent refreshes for one account but not different accounts', async () => { const coordinator = new PiProviderRefreshCoordinator(); let releaseFirst!: () => void; const firstWait = new Promise((resolve) => { releaseFirst = resolve; }); const sameAccountRefresh = vi.fn(async () => { await firstWait; }); const otherAccountRefresh = vi.fn(async () => undefined); const first = coordinator.refreshAccount('account-a', sameAccountRefresh); const second = coordinator.refreshAccount('account-a', sameAccountRefresh); const other = coordinator.refreshAccount('account-b', otherAccountRefresh); await other; expect(coordinator.pendingAccountCount).toBe(1); releaseFirst(); await Promise.all([first, second]); expect(sameAccountRefresh).toHaveBeenCalledTimes(1); expect(otherAccountRefresh).toHaveBeenCalledTimes(1); expect(coordinator.pendingAccountCount).toBe(0); }); it('refreshes and reopens at most once for one failed operation', async () => { const coordinator = new PiProviderRefreshCoordinator(); const authError = new Error('401'); const operation = vi.fn(async () => { throw authError; }); const refreshCredential = vi.fn(async () => undefined); const reopenWorker = vi.fn(async () => undefined); await expect(coordinator.withSingleAuthRecovery({ accountId: 'account-a', operation, isAuthenticationError: (error) => error === authError, refreshCredential, reopenWorker, })).rejects.toBe(authError); expect(operation).toHaveBeenCalledTimes(2); expect(operation.mock.calls.map(([attempt]) => attempt)).toEqual([0, 1]); expect(refreshCredential).toHaveBeenCalledTimes(1); expect(reopenWorker).toHaveBeenCalledTimes(1); }); it('does not refresh for a non-authentication failure', async () => { const coordinator = new PiProviderRefreshCoordinator(); const failure = new Error('timeout'); const refreshCredential = vi.fn(async () => undefined); const reopenWorker = vi.fn(async () => undefined); await expect(coordinator.withSingleAuthRecovery({ accountId: 'account-a', operation: async () => { throw failure; }, isAuthenticationError: () => false, refreshCredential, reopenWorker, })).rejects.toBe(failure); expect(refreshCredential).not.toHaveBeenCalled(); expect(reopenWorker).not.toHaveBeenCalled(); }); }); describe('Pi managed input revision coordination', () => { it('rebuilds an idle stale worker before its next prompt', () => { const coordinator = new PiManagedInputRevisionCoordinator(); coordinator.registerWorker('worker'); coordinator.markProviderStale(); expect(coordinator.beforePrompt('worker')).toEqual({ action: 'rebuild-before-prompt', revision: { provider: 2, resources: 1 }, }); coordinator.applyCurrentRevision('worker'); expect(coordinator.beforePrompt('worker').action).toBe('reuse'); }); it('keeps a running snapshot and schedules rebuild only after settlement', () => { const coordinator = new PiManagedInputRevisionCoordinator(); coordinator.registerWorker('worker'); const runRevision = coordinator.beginRun('worker'); coordinator.markResourcesStale(); expect(runRevision).toEqual({ provider: 1, resources: 1 }); expect(coordinator.beforePrompt('worker')).toEqual({ action: 'defer-until-settled', revision: { provider: 1, resources: 1 }, }); expect(() => coordinator.applyCurrentRevision('worker')).toThrow('run is active'); expect(coordinator.settleRun('worker')).toEqual({ action: 'rebuild-after-settled', revision: { provider: 1, resources: 2 }, }); }); });