Download src/api/llm-balance-service.test.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 3.79 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/api/llm-balance-service.test.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/api/llm-balance-service.test.ts
-
curl -L -o llm-balance-service.test.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/api/llm-balance-service.test.ts
3.79 kB
| import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; | |
| import { | |
| setActiveSelection, | |
| setRegisteredBackends, | |
| } from "#/api/backend-registry/active-store"; | |
| import type { Backend } from "#/api/backend-registry/types"; | |
| import { | |
| LLM_BALANCE_PATH, | |
| LLM_BALANCE_TIMEOUT_MS, | |
| } from "#/constants/llm-balance"; | |
| import LLMBalanceService from "./llm-balance-service"; | |
| import { AgentServerClient } from "@openhands/typescript-client/clients"; | |
| const getMock = vi.hoisted(() => vi.fn()); | |
| vi.mock("@openhands/typescript-client/clients", () => ({ | |
| AgentServerClient: vi.fn(function AgentServerClientMock() { | |
| return { get: getMock, close: vi.fn() }; | |
| }), | |
| })); | |
| const localBackend: Backend = { | |
| id: "local-test", | |
| name: "Local test backend", | |
| host: "http://localhost:3000", | |
| apiKey: "test-session-key", | |
| kind: "local", | |
| }; | |
| const balancePayload = { | |
| provider: "openrouter", | |
| limit: 20, | |
| limit_remaining: 14.96, | |
| usage: 5.04, | |
| usage_daily: 1.2, | |
| usage_weekly: 3.4, | |
| usage_monthly: 5.04, | |
| is_free_tier: false, | |
| }; | |
| function httpError(status: number): Error & { status: number } { | |
| return Object.assign(new Error(`HTTP ${status}`), { status }); | |
| } | |
| function mockedClient(): AgentServerClient { | |
| return vi.mocked(AgentServerClient).mock.results[0] | |
| ?.value as AgentServerClient; | |
| } | |
| describe("LLMBalanceService.getBalance", () => { | |
| beforeEach(() => { | |
| getMock.mockReset(); | |
| vi.mocked(AgentServerClient).mockClear(); | |
| setRegisteredBackends([localBackend]); | |
| setActiveSelection({ backendId: localBackend.id }); | |
| }); | |
| afterEach(() => { | |
| setActiveSelection(null); | |
| setRegisteredBackends([]); | |
| }); | |
| it("normalizes a successful balance response via the typed client", async () => { | |
| getMock.mockResolvedValue(balancePayload); | |
| const balance = await LLMBalanceService.getBalance(); | |
| expect(balance).toEqual({ | |
| provider: "openrouter", | |
| limit: 20, | |
| limitRemaining: 14.96, | |
| usage: 5.04, | |
| usageDaily: 1.2, | |
| usageWeekly: 3.4, | |
| usageMonthly: 5.04, | |
| isFreeTier: false, | |
| }); | |
| expect(vi.mocked(AgentServerClient)).toHaveBeenCalledWith({ | |
| host: "http://localhost:3000", | |
| apiKey: "test-session-key", | |
| timeout: LLM_BALANCE_TIMEOUT_MS, | |
| }); | |
| expect(getMock).toHaveBeenCalledWith(LLM_BALANCE_PATH, { | |
| acceptableStatusCodes: new Set([200]), | |
| responseType: "json", | |
| timeoutSeconds: Math.floor(LLM_BALANCE_TIMEOUT_MS / 1000), | |
| }); | |
| expect(mockedClient().close).toHaveBeenCalled(); | |
| }); | |
| it("treats null caps as an uncapped key", async () => { | |
| getMock.mockResolvedValue({ | |
| ...balancePayload, | |
| limit: null, | |
| limit_remaining: null, | |
| }); | |
| const balance = await LLMBalanceService.getBalance(); | |
| expect(balance?.limit).toBeNull(); | |
| expect(balance?.limitRemaining).toBeNull(); | |
| expect(balance?.usage).toBe(5.04); | |
| }); | |
| it("returns null when the endpoint is missing (404)", async () => { | |
| getMock.mockRejectedValue(httpError(404)); | |
| await expect(LLMBalanceService.getBalance()).resolves.toBeNull(); | |
| }); | |
| it("returns null for a malformed response body", async () => { | |
| getMock.mockResolvedValue({ unexpected: true }); | |
| await expect(LLMBalanceService.getBalance()).resolves.toBeNull(); | |
| }); | |
| it("throws on non-404 HTTP failures", async () => { | |
| getMock.mockRejectedValue(httpError(500)); | |
| await expect(LLMBalanceService.getBalance()).rejects.toThrow( | |
| "Balance request failed with 500", | |
| ); | |
| }); | |
| it("throws a named error when the request times out", async () => { | |
| getMock.mockRejectedValue( | |
| new DOMException("The operation was aborted.", "TimeoutError"), | |
| ); | |
| await expect(LLMBalanceService.getBalance()).rejects.toThrow( | |
| "Balance request timed out", | |
| ); | |
| }); | |
| }); | |