Files
makelore/tests/unit/pi-provider-state.test.ts

96 lines
4.0 KiB
TypeScript

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 },
});
});
});