diff --git a/tests/unit/error-classification.test.ts b/tests/unit/error-classification.test.ts index bc267a4050..90d18f7c4d 100644 --- a/tests/unit/error-classification.test.ts +++ b/tests/unit/error-classification.test.ts @@ -98,13 +98,21 @@ test("502 transient: exponential backoff doubles until the configured max backof assert.equal(result.newBackoffLevel, level + 1); assert.equal(result.reason, RateLimitReason.SERVER_ERROR); } + // #8396: the scaled cooldown is now clamped by capScaledCooldownMs + // (open-sse/services/accountFallback/cooldownCap.ts). With no provider the + // ceiling is BACKOFF_CONFIG.max, so the doubling stops there instead of + // running on to transientInitial * 32. + assert.ok( + COOLDOWN_MS.transientInitial * 32 > BACKOFF_CONFIG.max, + "precondition: the 6th step must exceed the cap, or this test proves nothing" + ); assert.deepEqual(cooldowns, [ COOLDOWN_MS.transientInitial, COOLDOWN_MS.transientInitial * 2, COOLDOWN_MS.transientInitial * 4, COOLDOWN_MS.transientInitial * 8, COOLDOWN_MS.transientInitial * 16, - COOLDOWN_MS.transientInitial * 32, + BACKOFF_CONFIG.max, ]); }); @@ -237,8 +245,14 @@ test("subscription quota uses long cooldown when upstream retry hints are disabl test("high transient backoff levels clamp to the configured maxBackoffSteps", () => { const result = checkFallbackError(502, "", BACKOFF_CONFIG.maxLevel + 5, null, null); assert.equal(result.newBackoffLevel, BACKOFF_CONFIG.maxLevel); + // #8396: the level still clamps at maxLevel, but the resulting duration is + // additionally capped — unclamped this would be ~45.5h, which is the blackout + // that PR removed. assert.equal( result.cooldownMs, - COOLDOWN_MS.transientInitial * Math.pow(2, BACKOFF_CONFIG.maxLevel) + Math.min( + COOLDOWN_MS.transientInitial * Math.pow(2, BACKOFF_CONFIG.maxLevel), + BACKOFF_CONFIG.max + ) ); }); diff --git a/tests/unit/thundering-herd.test.ts b/tests/unit/thundering-herd.test.ts index e3af4f81f1..140efa04a6 100644 --- a/tests/unit/thundering-herd.test.ts +++ b/tests/unit/thundering-herd.test.ts @@ -39,9 +39,15 @@ test("API profile has shorter transient cooldown", () => { test("Exponential backoff clamps to the configured maxBackoffLevel", () => { const result = checkFallbackError(502, "", 20, null, null); assert.equal(result.newBackoffLevel, BACKOFF_CONFIG.maxLevel); + // #8396: the level still clamps at maxLevel, but capScaledCooldownMs also + // bounds the duration — with no provider profile the ceiling is + // BACKOFF_CONFIG.max rather than the unbounded baseCooldownMs * 2^level. assert.equal( result.cooldownMs, - COOLDOWN_MS.transientInitial * Math.pow(2, BACKOFF_CONFIG.maxLevel) + Math.min( + COOLDOWN_MS.transientInitial * Math.pow(2, BACKOFF_CONFIG.maxLevel), + BACKOFF_CONFIG.max + ) ); });