@@ -5,6 +5,7 @@ package openai_test
5
5
import (
6
6
"context"
7
7
"fmt"
8
+ "io"
8
9
"net/http"
9
10
"reflect"
10
11
"testing"
@@ -281,3 +282,115 @@ func TestContextDeadline(t *testing.T) {
281
282
}
282
283
}
283
284
}
285
+
286
+ func TestContextDeadlineStreaming (t * testing.T ) {
287
+ testTimeout := time .After (3 * time .Second )
288
+ testDone := make (chan struct {})
289
+
290
+ deadline := time .Now ().Add (100 * time .Millisecond )
291
+ deadlineCtx , cancel := context .WithDeadline (context .Background (), deadline )
292
+ defer cancel ()
293
+
294
+ go func () {
295
+ client := openai .NewClient (
296
+ option .WithHTTPClient (& http.Client {
297
+ Transport : & closureTransport {
298
+ fn : func (req * http.Request ) (* http.Response , error ) {
299
+ return & http.Response {
300
+ StatusCode : 200 ,
301
+ Status : "200 OK" ,
302
+ Body : io .NopCloser (
303
+ io .Reader (readerFunc (func ([]byte ) (int , error ) {
304
+ <- req .Context ().Done ()
305
+ return 0 , req .Context ().Err ()
306
+ })),
307
+ ),
308
+ }, nil
309
+ },
310
+ },
311
+ }),
312
+ )
313
+ stream := client .Chat .Completions .NewStreaming (deadlineCtx , openai.ChatCompletionNewParams {
314
+ Messages : openai .F ([]openai.ChatCompletionMessageParamUnion {openai.ChatCompletionDeveloperMessageParam {
315
+ Content : openai .F ([]openai.ChatCompletionContentPartTextParam {{Text : openai .F ("text" ), Type : openai .F (openai .ChatCompletionContentPartTextTypeText )}}),
316
+ Role : openai .F (openai .ChatCompletionDeveloperMessageParamRoleDeveloper ),
317
+ }}),
318
+ Model : openai .F (openai .ChatModelO3Mini ),
319
+ })
320
+ for stream .Next () {
321
+ _ = stream .Current ()
322
+ }
323
+ if stream .Err () == nil {
324
+ t .Error ("expected there to be a deadline error" )
325
+ }
326
+ close (testDone )
327
+ }()
328
+
329
+ select {
330
+ case <- testTimeout :
331
+ t .Fatal ("client didn't finish in time" )
332
+ case <- testDone :
333
+ if diff := time .Since (deadline ); diff < - 30 * time .Millisecond || 30 * time .Millisecond < diff {
334
+ t .Fatalf ("client did not return within 30ms of context deadline, got %s" , diff )
335
+ }
336
+ }
337
+ }
338
+
339
+ func TestContextDeadlineStreamingWithRequestTimeout (t * testing.T ) {
340
+ testTimeout := time .After (3 * time .Second )
341
+ testDone := make (chan struct {})
342
+ deadline := time .Now ().Add (100 * time .Millisecond )
343
+
344
+ go func () {
345
+ client := openai .NewClient (
346
+ option .WithHTTPClient (& http.Client {
347
+ Transport : & closureTransport {
348
+ fn : func (req * http.Request ) (* http.Response , error ) {
349
+ return & http.Response {
350
+ StatusCode : 200 ,
351
+ Status : "200 OK" ,
352
+ Body : io .NopCloser (
353
+ io .Reader (readerFunc (func ([]byte ) (int , error ) {
354
+ <- req .Context ().Done ()
355
+ return 0 , req .Context ().Err ()
356
+ })),
357
+ ),
358
+ }, nil
359
+ },
360
+ },
361
+ }),
362
+ )
363
+ stream := client .Chat .Completions .NewStreaming (
364
+ context .Background (),
365
+ openai.ChatCompletionNewParams {
366
+ Messages : openai .F ([]openai.ChatCompletionMessageParamUnion {openai.ChatCompletionDeveloperMessageParam {
367
+ Content : openai .F ([]openai.ChatCompletionContentPartTextParam {{Text : openai .F ("text" ), Type : openai .F (openai .ChatCompletionContentPartTextTypeText )}}),
368
+ Role : openai .F (openai .ChatCompletionDeveloperMessageParamRoleDeveloper ),
369
+ }}),
370
+ Model : openai .F (openai .ChatModelO3Mini ),
371
+ },
372
+ option .WithRequestTimeout ((100 * time .Millisecond )),
373
+ )
374
+ for stream .Next () {
375
+ _ = stream .Current ()
376
+ }
377
+ if stream .Err () == nil {
378
+ t .Error ("expected there to be a deadline error" )
379
+ }
380
+ close (testDone )
381
+ }()
382
+
383
+ select {
384
+ case <- testTimeout :
385
+ t .Fatal ("client didn't finish in time" )
386
+ case <- testDone :
387
+ if diff := time .Since (deadline ); diff < - 30 * time .Millisecond || 30 * time .Millisecond < diff {
388
+ t .Fatalf ("client did not return within 30ms of context deadline, got %s" , diff )
389
+ }
390
+ }
391
+ }
392
+
393
+ type readerFunc func ([]byte ) (int , error )
394
+
395
+ func (f readerFunc ) Read (p []byte ) (int , error ) { return f (p ) }
396
+ func (f readerFunc ) Close () error { return nil }
0 commit comments