Files
openchamber/packages/ui/src/stores/useQuotaStore.test.ts
T
Bohdan Triapitsyn f0ced9d361 fix: reject instance-served responses that outlive their instance
MCP status and skills were cleared on a switch but their in-flight requests
were not, so a response for the previous instance could still write itself over
the new one's — the same race the quota store already guards. Both now carry a
generation.

Usage also claimed an instance as loaded before it had answered, so a load that
failed on a cold or briefly unreachable instance was never attempted again, and
the previous instance's display mode and provider selection survived a switch —
which decided what the new instance was even asked for.
2026-09-03 11:49:34 +03:00

140 lines
5.3 KiB
TypeScript

import { beforeEach, describe, expect, mock, test } from "bun:test"
import type { ProviderResult } from "@/types"
let runtimeKey = "url:https://instance-a"
let isInitialized = true
const fetched: string[] = []
type StubPayload = { usageDropdownProviders: string[] } | ProviderResult
let quotaRequestsFail = false;
const json = (body: StubPayload) => new Response(
JSON.stringify(body),
{ status: 200, headers: { "content-type": "application/json" } },
)
// Spread the real modules so the overrides stay a patch: `mock.module` is
// process-global, and a partial replacement would break every other module
// that imports something else from these files.
const runtimeSwitch = await import("@/lib/runtime-switch")
mock.module("@/lib/runtime-switch", () => ({ ...runtimeSwitch, getRuntimeKey: () => runtimeKey }))
const runtimeFetchModule = await import("@/lib/runtime-fetch")
mock.module("@/lib/runtime-fetch", () => ({
...runtimeFetchModule,
runtimeFetch: async (path: string) => {
fetched.push(path)
if (quotaRequestsFail) throw new Error("network down")
if (path.startsWith("/api/config/settings")) return json({ usageDropdownProviders: ["claude"] })
return json({ providerId: "claude", providerName: "Claude", ok: true, configured: true, usage: null, fetchedAt: 1 })
},
}))
const configStoreModule = await import("@/stores/useConfigStore")
mock.module("@/stores/useConfigStore", () => ({
...configStoreModule,
useConfigStore: { ...configStoreModule.useConfigStore, getState: () => ({ isInitialized }) },
}))
const { useQuotaStore } = await import("./useQuotaStore")
describe("Usage quotas are loaded once per ready instance", () => {
beforeEach(() => {
runtimeKey = "url:https://instance-a"
isInitialized = true
fetched.length = 0
quotaRequestsFail = false
useQuotaStore.getState().resetForRuntimeSwitch()
})
test("nothing is fetched while the instance has not reported itself initialised", async () => {
isInitialized = false
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched).toHaveLength(0)
expect(useQuotaStore.getState().loadedRuntimeKey).toBeNull()
// The instance finishes starting up: the same call now performs the load
// that a mount-time fetch would have answered "nothing configured".
isInitialized = true
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched.length).toBeGreaterThan(0)
expect(useQuotaStore.getState().results.length).toBeGreaterThan(0)
})
test("a second ask for the same instance does not refetch", async () => {
await useQuotaStore.getState().ensureLoadedForRuntime()
const afterFirst = fetched.length
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched.length).toBe(afterFirst)
})
test("a switch drops the previous instance's quotas and reloads for the new one", async () => {
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(useQuotaStore.getState().results.length).toBeGreaterThan(0)
useQuotaStore.getState().resetForRuntimeSwitch()
expect(useQuotaStore.getState().results).toEqual([])
expect(useQuotaStore.getState().lastUpdated).toBeNull()
runtimeKey = "url:https://instance-b"
fetched.length = 0
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched.length).toBeGreaterThan(0)
expect(useQuotaStore.getState().loadedRuntimeKey).toBe("url:https://instance-b")
})
test("a quota still in flight for the previous instance cannot land in the new one", async () => {
const pending = useQuotaStore.getState().fetchProviderQuota("claude")
useQuotaStore.getState().resetForRuntimeSwitch()
await pending
expect(useQuotaStore.getState().results).toEqual([])
})
test("a transient runtime key loads nothing", async () => {
runtimeKey = "mobile-disconnected"
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched).toHaveLength(0)
})
test("a failed load is not recorded as loaded, so the next ask retries it", async () => {
quotaRequestsFail = true
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(useQuotaStore.getState().loadedRuntimeKey).toBeNull()
quotaRequestsFail = false
fetched.length = 0
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(fetched.length).toBeGreaterThan(0)
expect(useQuotaStore.getState().loadedRuntimeKey).toBe("url:https://instance-a")
})
test("concurrent asks share one load", async () => {
await Promise.all([
useQuotaStore.getState().ensureLoadedForRuntime(),
useQuotaStore.getState().ensureLoadedForRuntime(),
])
expect(fetched.filter((path) => path.startsWith("/api/quota/"))).toHaveLength(1)
})
test("a switch drops the previous instance's display settings", async () => {
await useQuotaStore.getState().ensureLoadedForRuntime()
expect(useQuotaStore.getState().dropdownProviderIds).toEqual(["claude"])
useQuotaStore.getState().setDisplayMode("remaining")
useQuotaStore.getState().resetForRuntimeSwitch()
// `dropdownProviderIds` decides which providers get queried, so carrying it
// over would ask the new instance through the old one's selection.
expect(useQuotaStore.getState().dropdownProviderIds.length).toBeGreaterThan(1)
expect(useQuotaStore.getState().displayMode).toBe("usage")
})
})