@@ -10,17 +10,16 @@ const labelItem = {
|
10 | 10 | |
11 | 11 | describe("label-open-issues helpers", () => { |
12 | 12 | it("classifies items from OpenAI structured response text", async () => { |
13 | | -const response = { |
14 | | -ok: true, |
15 | | -status: 200, |
16 | | -json: async () => ({ |
| 13 | +const response = new Response( |
| 14 | +JSON.stringify({ |
17 | 15 | output_text: JSON.stringify({ |
18 | 16 | category: "bug", |
19 | 17 | isSupport: true, |
20 | 18 | isSkillOnly: false, |
21 | 19 | }), |
22 | 20 | }), |
23 | | -} as Response; |
| 21 | +{ status: 200 }, |
| 22 | +); |
24 | 23 | |
25 | 24 | await expect( |
26 | 25 | testing.classifyItem(labelItem, "issue", { |
@@ -55,11 +54,7 @@ describe("label-open-issues helpers", () => {
|
55 | 54 | }); |
56 | 55 | |
57 | 56 | it("times out stalled OpenAI classification body reads", async () => { |
58 | | -const response = { |
59 | | -ok: true, |
60 | | -status: 200, |
61 | | -json: () => new Promise(() => {}), |
62 | | -} as Response; |
| 57 | +const response = new Response(new ReadableStream({}), { status: 200 }); |
63 | 58 | const request = testing.classifyItem(labelItem, "issue", { |
64 | 59 | apiKey: "test-key", |
65 | 60 | model: "test-model", |
@@ -96,6 +91,53 @@ describe("label-open-issues helpers", () => {
|
96 | 91 | expect(message.length).toBeLessThan(4300); |
97 | 92 | }); |
98 | 93 | |
| 94 | +it("reads bounded OpenAI classification JSON responses", async () => { |
| 95 | +await expect( |
| 96 | +testing.readBoundedOpenAIJson(new Response('{"output_text":"{}"}'), 1024), |
| 97 | +).resolves.toEqual({ output_text: "{}" }); |
| 98 | +}); |
| 99 | + |
| 100 | +it("rejects oversized OpenAI classification JSON responses by content length", async () => { |
| 101 | +let canceled = false; |
| 102 | +const response = new Response( |
| 103 | +new ReadableStream({ |
| 104 | +cancel() { |
| 105 | +canceled = true; |
| 106 | +}, |
| 107 | +}), |
| 108 | +{ |
| 109 | +headers: { |
| 110 | +"content-length": "1025", |
| 111 | +}, |
| 112 | +}, |
| 113 | +); |
| 114 | + |
| 115 | +await expect(testing.readBoundedOpenAIJson(response, 1024)).rejects.toMatchObject({ |
| 116 | +code: "ETOOBIG", |
| 117 | +message: "OpenAI classification response body exceeded 1024 bytes", |
| 118 | +}); |
| 119 | +expect(canceled).toBe(true); |
| 120 | +}); |
| 121 | + |
| 122 | +it("rejects oversized streamed OpenAI classification JSON responses", async () => { |
| 123 | +const encoder = new TextEncoder(); |
| 124 | +const response = new Response( |
| 125 | +new ReadableStream({ |
| 126 | +start(controller) { |
| 127 | +controller.enqueue(encoder.encode('{"output_text":"')); |
| 128 | +controller.enqueue(encoder.encode("x".repeat(1024))); |
| 129 | +controller.enqueue(encoder.encode('"}')); |
| 130 | +controller.close(); |
| 131 | +}, |
| 132 | +}), |
| 133 | +); |
| 134 | + |
| 135 | +await expect(testing.readBoundedOpenAIJson(response, 1024)).rejects.toMatchObject({ |
| 136 | +code: "ETOOBIG", |
| 137 | +message: "OpenAI classification response body exceeded 1024 bytes", |
| 138 | +}); |
| 139 | +}); |
| 140 | + |
99 | 141 | it("rejects invalid OpenAI classification timeout values", () => { |
100 | 142 | expect(testing.resolveOpenAITimeoutMs("250")).toBe(250); |
101 | 143 | expect(() => testing.resolveOpenAITimeoutMs("slow")).toThrow( |
|