|
| 1 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
1 | 2 | import { |
2 | 3 | SELF_HOSTED_DEFAULT_CONTEXT_WINDOW, |
3 | 4 | SELF_HOSTED_DEFAULT_MAX_TOKENS, |
@@ -90,6 +91,7 @@ describe("lmstudio-models", () => {
|
90 | 91 | |
91 | 92 | afterEach(() => { |
92 | 93 | fetchWithSsrFGuardMock.mockReset(); |
| 94 | +vi.restoreAllMocks(); |
93 | 95 | vi.unstubAllGlobals(); |
94 | 96 | }); |
95 | 97 | |
@@ -379,6 +381,45 @@ describe("lmstudio-models", () => {
|
379 | 381 | } |
380 | 382 | }); |
381 | 383 | |
| 384 | +it("caps oversized direct fetch timeouts before discovering models", async () => { |
| 385 | +const timeoutController = new AbortController(); |
| 386 | +const timeoutSpy = vi.spyOn(AbortSignal, "timeout").mockReturnValue(timeoutController.signal); |
| 387 | +const fetchMock = vi.fn(async (_url: string | URL, init?: RequestInit) => ({ |
| 388 | +ok: true, |
| 389 | +status: 200, |
| 390 | +requestInit: init, |
| 391 | +json: async () => ({ models: [] }), |
| 392 | +})); |
| 393 | + |
| 394 | +const result = await fetchLmstudioModels({ |
| 395 | +baseUrl: "http://localhost:1234/v1", |
| 396 | +timeoutMs: Number.MAX_SAFE_INTEGER, |
| 397 | +fetchImpl: asFetch(fetchMock), |
| 398 | +}); |
| 399 | + |
| 400 | +expect(result.reachable).toBe(true); |
| 401 | +expect(timeoutSpy).toHaveBeenCalledWith(MAX_TIMER_TIMEOUT_MS); |
| 402 | +expect(fetchMock.mock.calls[0]?.[1]?.signal).toBe(timeoutController.signal); |
| 403 | +}); |
| 404 | + |
| 405 | +it("caps oversized guarded-fetch timeouts before discovering models", async () => { |
| 406 | +fetchWithSsrFGuardMock.mockResolvedValue({ |
| 407 | +response: new Response(JSON.stringify({ models: [] }), { status: 200 }), |
| 408 | +release: vi.fn(async () => undefined), |
| 409 | +}); |
| 410 | + |
| 411 | +const result = await fetchLmstudioModels({ |
| 412 | +baseUrl: "http://localhost:1234/v1", |
| 413 | +timeoutMs: Number.MAX_SAFE_INTEGER, |
| 414 | +ssrfPolicy: {}, |
| 415 | +}); |
| 416 | + |
| 417 | +expect(result.reachable).toBe(true); |
| 418 | +expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]).toMatchObject({ |
| 419 | +timeoutMs: MAX_TIMER_TIMEOUT_MS, |
| 420 | +}); |
| 421 | +}); |
| 422 | + |
382 | 423 | it("skips model load when already loaded", async () => { |
383 | 424 | const fetchMock = createModelLoadFetchMock({ loadedContextLength: 64000 }); |
384 | 425 | vi.stubGlobal("fetch", asFetch(fetchMock)); |
|