@@ -1534,6 +1534,28 @@ function getGuardedFetchCall(fetchMock: typeof fetchWithSsrFGuardMock): GuardedF
|
1534 | 1534 | return (fetchMock.mock.calls.at(0)?.[0] as GuardedFetchCall | undefined) ?? { url: "" }; |
1535 | 1535 | } |
1536 | 1536 | |
| 1537 | +function cancelTrackedResponse( |
| 1538 | +text: string, |
| 1539 | +init: ResponseInit, |
| 1540 | +): { |
| 1541 | +response: Response; |
| 1542 | +wasCanceled: () => boolean; |
| 1543 | +} { |
| 1544 | +let canceled = false; |
| 1545 | +const stream = new ReadableStream<Uint8Array>({ |
| 1546 | +start(controller) { |
| 1547 | +controller.enqueue(new TextEncoder().encode(text)); |
| 1548 | +}, |
| 1549 | +cancel() { |
| 1550 | +canceled = true; |
| 1551 | +}, |
| 1552 | +}); |
| 1553 | +return { |
| 1554 | +response: new Response(stream, init), |
| 1555 | +wasCanceled: () => canceled, |
| 1556 | +}; |
| 1557 | +} |
| 1558 | + |
1537 | 1559 | async function createOllamaTestStream(params: { |
1538 | 1560 | baseUrl: string; |
1539 | 1561 | defaultHeaders?: Record<string, string>; |
@@ -2684,12 +2706,14 @@ describe("createOllamaStreamFn", () => {
|
2684 | 2706 | ); |
2685 | 2707 | }); |
2686 | 2708 | |
2687 | | -it("surfaces non-2xx HTTP response as status-prefixed error", async () => { |
| 2709 | +it("surfaces bounded non-2xx HTTP response text as a status-prefixed error", async () => { |
| 2710 | +const tracked = cancelTrackedResponse(`${"Service Unavailable ".repeat(1024)}tail`, { |
| 2711 | +status: 503, |
| 2712 | +statusText: "Service Unavailable", |
| 2713 | +}); |
| 2714 | +const textSpy = vi.spyOn(tracked.response, "text").mockRejectedValue(new Error("unbounded")); |
2688 | 2715 | fetchWithSsrFGuardMock.mockResolvedValue({ |
2689 | | -response: new Response("Service Unavailable", { |
2690 | | -status: 503, |
2691 | | -statusText: "Service Unavailable", |
2692 | | -}), |
| 2716 | +response: tracked.response, |
2693 | 2717 | release: vi.fn(async () => undefined), |
2694 | 2718 | }); |
2695 | 2719 | try { |
@@ -2705,6 +2729,10 @@ describe("createOllamaStreamFn", () => {
|
2705 | 2729 | // The error message must start with the HTTP status code so that |
2706 | 2730 | // extractLeadingHttpStatus can parse it for failover/retry logic. |
2707 | 2731 | expect(errorEvent.error.errorMessage).toMatch(/^503\b/); |
| 2732 | +expect(errorEvent.error.errorMessage).toContain("Service Unavailable"); |
| 2733 | +expect(errorEvent.error.errorMessage).not.toContain("tail"); |
| 2734 | +expect(tracked.wasCanceled()).toBe(true); |
| 2735 | +expect(textSpy).not.toHaveBeenCalled(); |
2708 | 2736 | } finally { |
2709 | 2737 | fetchWithSsrFGuardMock.mockReset(); |
2710 | 2738 | } |
|