@@ -376,6 +376,56 @@ class HTTP1ClientChannelHandlerTests: XCTestCase {
376
376
}
377
377
}
378
378
379
+ func testIdleWriteTimeoutRaceToEnd( ) {
380
+ let embedded = EmbeddedChannel ( )
381
+ var maybeTestUtils : HTTP1TestTools ?
382
+ XCTAssertNoThrow ( maybeTestUtils = try embedded. setupHTTP1Connection ( ) )
383
+ guard let testUtils = maybeTestUtils else { return XCTFail ( " Expected connection setup works " ) }
384
+
385
+ var maybeRequest : HTTPClient . Request ?
386
+ XCTAssertNoThrow ( maybeRequest = try HTTPClient . Request ( url: " http://localhost/ " , method: . POST, body: . stream { _ in
387
+ // Advance time by more than the idle write timeout (that's 1 millisecond) to trigger the timeout.
388
+ let scheduled = embedded. embeddedEventLoop. flatScheduleTask ( in: . milliseconds( 2 ) ) {
389
+ embedded. embeddedEventLoop. makeSucceededVoidFuture ( )
390
+ }
391
+ return scheduled. futureResult
392
+ } ) )
393
+
394
+ guard let request = maybeRequest else { return XCTFail ( " Expected to be able to create a request " ) }
395
+
396
+ let delegate = ResponseAccumulator ( request: request)
397
+ var maybeRequestBag : RequestBag < ResponseAccumulator > ?
398
+ XCTAssertNoThrow ( maybeRequestBag = try RequestBag (
399
+ request: request,
400
+ eventLoopPreference: . delegate( on: embedded. eventLoop) ,
401
+ task: . init( eventLoop: embedded. eventLoop, logger: testUtils. logger) ,
402
+ redirectHandler: nil ,
403
+ connectionDeadline: . now( ) + . seconds( 30 ) ,
404
+ requestOptions: . forTests( idleWriteTimeout: . milliseconds( 5 ) ) ,
405
+ delegate: delegate
406
+ ) )
407
+ guard let requestBag = maybeRequestBag else { return XCTFail ( " Expected to be able to create a request bag " ) }
408
+
409
+ embedded. isWritable = true
410
+ embedded. pipeline. fireChannelWritabilityChanged ( )
411
+ testUtils. connection. executeRequest ( requestBag)
412
+ let expectedHeaders : HTTPHeaders = [ " host " : " localhost " , " Transfer-Encoding " : " chunked " ]
413
+ XCTAssertEqual (
414
+ try embedded. readOutbound ( as: HTTPClientRequestPart . self) ,
415
+ . head( HTTPRequestHead ( version: . http1_1, method: . POST, uri: " / " , headers: expectedHeaders) )
416
+ )
417
+
418
+ // change the writability to false.
419
+ embedded. isWritable = false
420
+ embedded. pipeline. fireChannelWritabilityChanged ( )
421
+ embedded. embeddedEventLoop. run ( )
422
+
423
+ // let the writer, write an end (while writability is false)
424
+ embedded. embeddedEventLoop. advanceTime ( by: . milliseconds( 2 ) )
425
+
426
+ XCTAssertEqual ( try embedded. readOutbound ( as: HTTPClientRequestPart . self) , . end( nil ) )
427
+ }
428
+
379
429
func testIdleWriteTimeoutWritabilityChanged( ) {
380
430
let embedded = EmbeddedChannel ( )
381
431
let testWriter = TestBackpressureWriter ( eventLoop: embedded. eventLoop, parts: 5 )
0 commit comments