@@ -17,6 +17,7 @@ import NIO
17
17
import NIOConcurrencyHelpers
18
18
import NIOHTTP1
19
19
import NIOTestUtils
20
+ import Logging
20
21
import XCTest
21
22
22
23
class HTTPClientInternalTests : XCTestCase {
@@ -323,21 +324,25 @@ class HTTPClientInternalTests: XCTestCase {
323
324
// of 4 bytes. This will guarantee that if we see first byte of the message, other
324
325
// bytes a ready to be read as well. This will allow us to test if subsequent reads
325
326
// are waiting for backpressure promise.
326
- func testUploadStreamingBackpressure ( ) throws {
327
+ func testDownloadStreamingBackpressure ( ) throws {
327
328
class BackpressureTestDelegate : HTTPClientResponseDelegate {
328
329
typealias Response = Void
329
330
330
331
var _reads = 0
331
332
let lock : Lock
332
- let backpressurePromise : EventLoopPromise < Void >
333
+ let channel : Channel
334
+
333
335
let optionsApplied : EventLoopPromise < Void >
334
- let messageReceived : EventLoopPromise < Void >
336
+ let backpressureFuture : EventLoopFuture < Void >
337
+ let firstBodyPartReceived : EventLoopPromise < Void >
335
338
336
- init ( eventLoop : EventLoop ) {
339
+ init ( channel : Channel , writeBodyPromise : EventLoopPromise < Void > , writeEndFuture : EventLoopFuture < Void > ) {
337
340
self . lock = Lock ( )
338
- self . backpressurePromise = eventLoop. makePromise ( )
339
- self . optionsApplied = eventLoop. makePromise ( )
340
- self . messageReceived = eventLoop. makePromise ( )
341
+
342
+ self . channel = channel
343
+ self . optionsApplied = writeBodyPromise
344
+ self . backpressureFuture = writeEndFuture
345
+ self . firstBodyPartReceived = channel. eventLoop. makePromise ( )
341
346
}
342
347
343
348
var reads : Int {
@@ -348,8 +353,8 @@ class HTTPClientInternalTests: XCTestCase {
348
353
349
354
func didReceiveHead( task: HTTPClient . Task < Void > , _ head: HTTPResponseHead ) -> EventLoopFuture < Void > {
350
355
// This is to force NIO to send only 1 byte at a time.
351
- let future = task . connection! . channel. setOption ( ChannelOptions . maxMessagesPerRead, value: 1 ) . flatMap {
352
- task . connection! . channel. setOption ( ChannelOptions . recvAllocator, value: FixedSizeRecvByteBufferAllocator ( capacity: 1 ) )
356
+ let future = self . channel. setOption ( ChannelOptions . maxMessagesPerRead, value: 1 ) . flatMap {
357
+ self . channel. setOption ( ChannelOptions . recvAllocator, value: FixedSizeRecvByteBufferAllocator ( capacity: 1 ) )
353
358
}
354
359
future. cascade ( to: self . optionsApplied)
355
360
return future
@@ -361,8 +366,8 @@ class HTTPClientInternalTests: XCTestCase {
361
366
self . _reads += 1
362
367
}
363
368
// We need to notify the test when first byte of the message is arrived.
364
- self . messageReceived . succeed ( ( ) )
365
- return self . backpressurePromise . futureResult
369
+ self . firstBodyPartReceived . succeed ( ( ) )
370
+ return self . self . backpressureFuture
366
371
}
367
372
368
373
func didFinishRequest( task: HTTPClient . Task < Response > ) throws { }
@@ -403,37 +408,67 @@ class HTTPClientInternalTests: XCTestCase {
403
408
404
409
// cannot test with NIOTS as `maxMessagesPerRead` is not supported
405
410
let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
406
- let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( eventLoopGroup) )
407
- let delegate = BackpressureTestDelegate ( eventLoop: httpClient. eventLoopGroup. next ( ) )
411
+ let eventLoop = eventLoopGroup. next ( )
412
+ let writeBodyPromise = eventLoop. makePromise ( of: Void . self)
413
+ let writeEndPromise = eventLoop. makePromise ( of: Void . self)
408
414
let httpBin = HTTPBin { _ in
409
415
WriteAfterFutureSucceedsHandler (
410
- bodyFuture: delegate . optionsApplied . futureResult,
411
- endFuture: delegate . backpressurePromise . futureResult
416
+ bodyFuture: writeBodyPromise . futureResult,
417
+ endFuture: writeEndPromise . futureResult
412
418
)
413
419
}
414
-
415
420
defer {
416
- XCTAssertNoThrow ( try httpClient. syncShutdown ( requiresCleanClose: true ) )
417
421
XCTAssertNoThrow ( try httpBin. shutdown ( ) )
418
422
XCTAssertNoThrow ( try eventLoopGroup. syncShutdownGracefully ( ) )
419
423
}
420
-
424
+
425
+
421
426
let request = try Request ( url: " http://localhost: \( httpBin. port) /custom " )
422
-
423
- let requestFuture = httpClient. execute ( request: request, delegate: delegate) . futureResult
427
+ let logger = Logger ( label: " test-connection " )
428
+
429
+ let clientFactory = HTTPConnectionPool . ConnectionFactory (
430
+ key: . init( request) ,
431
+ tlsConfiguration: nil ,
432
+ clientConfiguration: . init( ) ,
433
+ sslContextCache: . init( ) )
434
+ var maybeChannel : Channel ?
435
+ XCTAssertNoThrow ( maybeChannel = try clientFactory. makeHTTP1Channel (
436
+ connectionID: 1 ,
437
+ deadline: . now( ) + . seconds( 10 ) ,
438
+ eventLoop: eventLoopGroup. next ( ) ,
439
+ logger: logger) . wait ( ) )
440
+
441
+ guard let channel = maybeChannel else { return XCTFail ( " Expected to have a channel at this point " ) }
442
+
443
+ let delegate = BackpressureTestDelegate (
444
+ channel: channel,
445
+ writeBodyPromise: writeBodyPromise,
446
+ writeEndFuture: writeEndPromise. futureResult)
447
+ let task = HTTPClient . Task< BackpressureTestDelegate . Response> ( eventLoop: eventLoop, logger: logger)
448
+
449
+
450
+ let taskHandler = TaskHandler ( task: task,
451
+ kind: request. kind,
452
+ delegate: delegate,
453
+ redirectHandler: nil ,
454
+ ignoreUncleanSSLShutdown: true ,
455
+ logger: logger)
456
+
457
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( taskHandler) . wait ( ) )
458
+ XCTAssertNoThrow ( try channel. writeAndFlush ( request) . wait ( ) )
424
459
425
460
// We need to wait for channel options that limit NIO to sending only one byte at a time.
426
- try delegate. optionsApplied. futureResult. wait ( )
461
+ XCTAssertNoThrow ( try delegate. optionsApplied. futureResult. wait ( ) )
427
462
428
463
// Send 4 bytes, but only one should be received until the backpressure promise is succeeded.
429
464
430
465
// Now we wait until message is delivered to client channel pipeline
431
- try delegate. messageReceived . futureResult. wait ( )
466
+ XCTAssertNoThrow ( try delegate. firstBodyPartReceived . futureResult. wait ( ) )
432
467
XCTAssertEqual ( delegate. reads, 1 )
433
468
434
469
// Succeed the backpressure promise.
435
- delegate . backpressurePromise . succeed ( ( ) )
436
- try requestFuture . wait ( )
470
+ writeEndPromise . succeed ( ( ) )
471
+ XCTAssertNoThrow ( try task . futureResult . wait ( ) )
437
472
438
473
// At this point all other bytes should be delivered.
439
474
XCTAssertEqual ( delegate. reads, 4 )
0 commit comments