Verify that response chunks become readable on the client side before the handler has finished writing. This is the property SSE/NDJSON streaming depends on.
(t *testing.T)
| 137 | // handler has finished writing. This is the property SSE/NDJSON streaming |
| 138 | // depends on. |
| 139 | func TestInMemoryRoundTripper_Streams(t *testing.T) { |
| 140 | t.Parallel() |
| 141 | |
| 142 | const chunks = 4 |
| 143 | released := make([]chan struct{}, chunks) |
| 144 | for i := range released { |
| 145 | released[i] = make(chan struct{}) |
| 146 | } |
| 147 | |
| 148 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 149 | w.Header().Set("Content-Type", "text/event-stream") |
| 150 | w.WriteHeader(http.StatusOK) |
| 151 | flusher, ok := w.(http.Flusher) |
| 152 | if !assert.True(t, ok, "ResponseWriter must implement http.Flusher") { |
| 153 | return |
| 154 | } |
| 155 | for i := range chunks { |
| 156 | <-released[i] |
| 157 | _, err := fmt.Fprintf(w, "data: chunk-%d\n\n", i) |
| 158 | if !assert.NoError(t, err) { |
| 159 | return |
| 160 | } |
| 161 | flusher.Flush() |
| 162 | } |
| 163 | }) |
| 164 | |
| 165 | rt, err := aibridged.NewTransportFactory(handler).TransportFor("openai", aibridge.SourceAgents) |
| 166 | require.NoError(t, err) |
| 167 | |
| 168 | ctx := aibridge.WithDelegatedAPIKeyID(testutil.Context(t, testutil.WaitShort), "test-key-id") |
| 169 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://aibridge/stream", nil) |
| 170 | require.NoError(t, err) |
| 171 | |
| 172 | resp, err := rt.RoundTrip(req) |
| 173 | require.NoError(t, err) |
| 174 | defer resp.Body.Close() |
| 175 | |
| 176 | br := bufio.NewReader(resp.Body) |
| 177 | for i := range chunks { |
| 178 | close(released[i]) |
| 179 | dataLine, err := br.ReadString('\n') |
| 180 | require.NoError(t, err) |
| 181 | require.Equal(t, fmt.Sprintf("data: chunk-%d\n", i), dataLine) |
| 182 | // Consume blank-line separator. |
| 183 | _, err = br.ReadString('\n') |
| 184 | require.NoError(t, err) |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | // Canceling the request context must surface as a body-read error, matching |
| 189 | // real-network behavior, and the handler must observe the cancellation |
nothing calls this directly
no test coverage detected