44 lines
1.5 KiB
JavaScript
44 lines
1.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert';
|
|
import { safeImport } from '../_helpers/path.js';
|
|
import { FakeLLMClient } from '../_helpers/fakeLLMClient.js';
|
|
|
|
function skip(msg){ console.warn('[SKIP]', msg); }
|
|
|
|
test('LLMManager: circuit breaker opens after consecutive failures (optional)', async () => {
|
|
const res = await safeImport('LLMManager');
|
|
if (!res.ok) { skip(res.reason); return; }
|
|
const L = res.mod;
|
|
if (typeof L.__setClient !== 'function' || typeof L.__setRetryPolicy !== 'function') {
|
|
skip('Missing __setClient/__setRetryPolicy hooks');
|
|
return;
|
|
}
|
|
|
|
// Simule toujours 500
|
|
const fakeFail = new FakeLLMClient({ plan: [{err:{statusCode:500}}] });
|
|
fakeFail.invoke = async () => { throw Object.assign(new Error('500'), {statusCode:500}); };
|
|
L.__setClient('mock', fakeFail);
|
|
|
|
L.__setRetryPolicy({
|
|
retries: 0,
|
|
baseMs: 1,
|
|
isTransient: (code) => [500].includes(code),
|
|
openAfter: 3, // <-- si ton impl gère ce champ
|
|
cooldownMs: 100 // <-- idem
|
|
});
|
|
|
|
let fails = 0;
|
|
for (let i=0; i<3; i++) {
|
|
try { await L.callModel({ provider:'mock', model:'fake-1', input:`try-${i}` }); }
|
|
catch(e){ fails++; }
|
|
}
|
|
assert.equal(fails, 3);
|
|
|
|
// Après 3, le breaker devrait s'ouvrir (si implémenté)
|
|
let breakerThrew = false;
|
|
try { await L.callModel({ provider:'mock', model:'fake-1', input:'blocked' }); }
|
|
catch(e){ breakerThrew = true; }
|
|
// On accepte SKIP si non implémenté dans ta lib
|
|
if (!breakerThrew) skip('Circuit breaker not implemented; test informational only');
|
|
});
|