feat: add Pi provider managed resources
This commit is contained in:
95
tests/unit/pi-provider-state.test.ts
Normal file
95
tests/unit/pi-provider-state.test.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
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<void>((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 },
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user