diff --git a/scripts/check/check-test-discovery.mjs b/scripts/check/check-test-discovery.mjs index 6537b31e62..09ce751efe 100644 --- a/scripts/check/check-test-discovery.mjs +++ b/scripts/check/check-test-discovery.mjs @@ -107,6 +107,11 @@ export const COLLECTORS = [ glob: "open-sse/services/__tests__/antigravity-quota-family.test.ts", sources: ["vitest.mcp.config.ts"], }, + // #8890 landed this suite here without wiring a runner, so it had never run once. + { + glob: "open-sse/services/__tests__/fail-fast-concurrency-gate.test.ts", + sources: ["vitest.mcp.config.ts"], + }, { glob: "tests/unit/autoCombo/**/*.test.ts", sources: ["vitest.mcp.config.ts"] }, { glob: "src/lib/memory/__tests__/generic-backend.test.ts", sources: ["vitest.mcp.config.ts"] }, { glob: "tests/unit/encryption.spec.ts", sources: ["vitest.mcp.config.ts"] }, diff --git a/tests/unit/check-db-rules-classification.test.ts b/tests/unit/check-db-rules-classification.test.ts index 3c22485d1c..7ccee8987e 100644 --- a/tests/unit/check-db-rules-classification.test.ts +++ b/tests/unit/check-db-rules-classification.test.ts @@ -121,7 +121,7 @@ test("INTENTIONALLY_INTERNAL is exported from check-db-rules.mjs", () => { assert.ok(INTENTIONALLY_INTERNAL.size > 0, "INTENTIONALLY_INTERNAL must not be empty"); }); -test("INTENTIONALLY_INTERNAL contains the expected 37 audited modules", () => { +test("INTENTIONALLY_INTERNAL contains the expected 38 audited modules", () => { const expected = [ "_rowTypes", "accessTokens", @@ -147,6 +147,7 @@ test("INTENTIONALLY_INTERNAL contains the expected 37 audited modules", () => { "optimizationSettings", "pluginMetrics", "prompts", + "probeUtils", "providerNodeSelect", "providerStats", "proxyLatency", diff --git a/tests/unit/ratelimit-reservoir-refresh.test.ts b/tests/unit/ratelimit-reservoir-refresh.test.ts index 7d218d31a6..3903f55319 100644 --- a/tests/unit/ratelimit-reservoir-refresh.test.ts +++ b/tests/unit/ratelimit-reservoir-refresh.test.ts @@ -85,15 +85,20 @@ test("reservoir keeps refreshing after updateSettings() touches an already-heart // number of event-loop ticks: Bottleneck's own updateSettings() goes through // at least one real setTimeout(0) (yieldLoop) before storeOptions reflects the // new value. + // #9604 replaced Bottleneck's fixed-window reservoir with the rolling lease gate + // (open-sse/services/rollingRpmGate.ts), so `reservoir` is null now and pinning it + // would assert a mechanism that no longer exists. What must still hold — and what + // the Bottleneck heartbeat bug actually broke — is that the limiter SURVIVES the + // header-learned updateSettings() and keeps admitting work (steps 3 and 4 below). const pollDeadline = Date.now() + 2000; let state = await rateLimitManager.__getLimiterStateForTests(PROVIDER, CONNECTION_ID, null); - while (state?.reservoir !== 2 && Date.now() < pollDeadline) { + while (!state && Date.now() < pollDeadline) { await wait(10); state = await rateLimitManager.__getLimiterStateForTests(PROVIDER, CONNECTION_ID, null); } - assert.equal(state?.reservoir, 2, "reservoir must land at 2 before the slots below are consumed"); + assert.ok(state, "the limiter must still exist after the header-learned update"); - // 3. Consume both reservoir slots. + // 3. Consume the learned capacity. assert.equal( await rateLimitManager.withRateLimit(PROVIDER, CONNECTION_ID, null, async () => "slot-1"), "slot-1" @@ -103,10 +108,9 @@ test("reservoir keeps refreshing after updateSettings() touches an already-heart "slot-2" ); - // 4. Reservoir is now 0. A healthy Bottleneck heartbeat refills it ~1s later - // from the reservoirRefreshInterval/reservoirRefreshAmount configured above. - // Race a 3rd request against a 5s timer: if the heartbeat died (unfixed bug), - // the request stays QUEUED forever and the timer wins instead. + // 4. Capacity is spent. Race a 3rd request against a 5s timer: if the limiter + // stopped pacing after updateSettings() (the original bug) the request stays + // queued forever and the timer wins instead. const RACE_TIMEOUT_MS = 5000; let timeoutHandle: ReturnType | undefined; const timeout = new Promise<"timed-out">((resolve) => { @@ -125,8 +129,8 @@ test("reservoir keeps refreshing after updateSettings() touches an already-heart assert.equal( result, "slot-3", - 'reservoir must refresh ~1s after being exhausted; "timed-out" means the Bottleneck ' + - "heartbeat died after updateSettings() and the reservoir never refilled " + - "(node_modules/bottleneck/lib/LocalDatastore.js _startHeartbeat clearInterval-without-null bug)" + 'capacity must recover after being exhausted; "timed-out" means the limiter stopped ' + + "admitting work after the header-learned updateSettings() — the failure shape of the " + + "original Bottleneck heartbeat bug (LocalDatastore _startHeartbeat clearInterval-without-null)" ); }); diff --git a/tests/unit/translator-openai-to-gemini.test.ts b/tests/unit/translator-openai-to-gemini.test.ts index 4b0f0a21fa..2b4affc2cc 100644 --- a/tests/unit/translator-openai-to-gemini.test.ts +++ b/tests/unit/translator-openai-to-gemini.test.ts @@ -582,7 +582,16 @@ test("OpenAI -> Antigravity wraps Gemini requests in a Cloud Code envelope", () "model", "userAgent", "requestType", + // #9568 (c9a3361e5a): buildChangedToolNameMap now emits IDENTITY entries too, + // because Gemini lowercases tool names in functionCall responses and the + // response translator needs a key to map them back. So any request carrying + // tools now carries `_toolNameMap` in the envelope. + "_toolNameMap", ]); + assert.deepEqual( + [...(result._toolNameMap as Map).entries()], + [["weather", "weather"]] + ); assert.equal(result.userAgent, "antigravity"); assert.equal(result.requestType, "agent"); assert.match(result.requestId, /^agent\/\d+\/[0-9a-f]{8}$/); diff --git a/vitest.mcp.config.ts b/vitest.mcp.config.ts index eef7897eac..5ca17b232d 100644 --- a/vitest.mcp.config.ts +++ b/vitest.mcp.config.ts @@ -14,6 +14,9 @@ export default defineConfig({ "open-sse/services/autoCombo/__tests__/**/*.test.ts", "open-sse/services/combo/__tests__/**/*.test.ts", "open-sse/services/__tests__/antigravity-quota-family.test.ts", + // #8890 shipped this suite into a directory no runner collects, so it had + // never executed once (check:test-discovery flags it as a NEW orphan). + "open-sse/services/__tests__/fail-fast-concurrency-gate.test.ts", "src/lib/memory/__tests__/generic-backend.test.ts", "tests/unit/autoCombo/**/*.test.ts", "tests/unit/encryption.spec.ts",