@@ -34,6 +34,27 @@ private func makeDefaultHTTPClient(
34
34
}
35
35
36
36
final class AsyncAwaitEndToEndTests : XCTestCase {
37
+ var clientGroup : EventLoopGroup !
38
+ var serverGroup : EventLoopGroup !
39
+
40
+ override func setUp( ) {
41
+ XCTAssertNil ( self . clientGroup)
42
+ XCTAssertNil ( self . serverGroup)
43
+
44
+ self . clientGroup = getDefaultEventLoopGroup ( numberOfThreads: 1 )
45
+ self . serverGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
46
+ }
47
+
48
+ override func tearDown( ) {
49
+ XCTAssertNotNil ( self . clientGroup)
50
+ XCTAssertNoThrow ( try self . clientGroup. syncShutdownGracefully ( ) )
51
+ self . clientGroup = nil
52
+
53
+ XCTAssertNotNil ( self . serverGroup)
54
+ XCTAssertNoThrow ( try self . serverGroup. syncShutdownGracefully ( ) )
55
+ self . serverGroup = nil
56
+ }
57
+
37
58
func testSimpleGet( ) {
38
59
#if compiler(>=5.5.2) && canImport(_Concurrency)
39
60
guard #available( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * ) else { return }
@@ -394,6 +415,65 @@ final class AsyncAwaitEndToEndTests: XCTestCase {
394
415
#endif
395
416
}
396
417
418
+ func testConnectTimeout( ) {
419
+ #if compiler(>=5.5.2) && canImport(_Concurrency)
420
+ guard #available( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * ) else { return }
421
+ XCTAsyncTest ( timeout: 60 ) {
422
+ #if os(Linux)
423
+ // 198.51.100.254 is reserved for documentation only and therefore should not accept any TCP connection
424
+ let url = " http://198.51.100.254/get "
425
+ #else
426
+ // on macOS we can use the TCP backlog behaviour when the queue is full to simulate a non reachable server.
427
+ // this makes this test a bit more stable if `198.51.100.254` actually responds to connection attempt.
428
+ // The backlog behaviour on Linux can not be used to simulate a non-reachable server.
429
+ // Linux sends a `SYN/ACK` back even if the `backlog` queue is full as it has two queues.
430
+ // The second queue is not limit by `ChannelOptions.backlog` but by `/proc/sys/net/ipv4/tcp_max_syn_backlog`.
431
+
432
+ let group = MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
433
+ defer {
434
+ XCTAssertNoThrow ( try group. syncShutdownGracefully ( ) )
435
+ }
436
+
437
+ let serverChannel = try await ServerBootstrap ( group: self . serverGroup)
438
+ . serverChannelOption ( ChannelOptions . backlog, value: 1 )
439
+ . serverChannelOption ( ChannelOptions . autoRead, value: false )
440
+ . bind ( host: " 127.0.0.1 " , port: 0 )
441
+ . get ( )
442
+ defer {
443
+ XCTAssertNoThrow ( try serverChannel. close ( ) . wait ( ) )
444
+ }
445
+ let port = serverChannel. localAddress!. port!
446
+ let firstClientChannel = try ClientBootstrap ( group: self . serverGroup)
447
+ . connect ( host: " 127.0.0.1 " , port: port)
448
+ . wait ( )
449
+ defer {
450
+ XCTAssertNoThrow ( try firstClientChannel. close ( ) . wait ( ) )
451
+ }
452
+ let url = " http://localhost: \( port) /get "
453
+ #endif
454
+
455
+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . clientGroup) ,
456
+ configuration: . init( timeout: . init( connect: . milliseconds( 100 ) , read: . milliseconds( 150 ) ) ) )
457
+
458
+ defer {
459
+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
460
+ }
461
+
462
+ let request = HTTPClientRequest ( url: url)
463
+ let start = NIODeadline . now ( )
464
+ await XCTAssertThrowsError ( try await httpClient. execute ( request, deadline: . now( ) + . seconds( 30 ) ) ) {
465
+ XCTAssertEqualTypeAndValue ( $0, HTTPClientError . connectTimeout)
466
+ let end = NIODeadline . now ( )
467
+ let duration = end - start
468
+
469
+ // We give ourselves 10x slack in order to be confident that even on slow machines this assertion passes.
470
+ // It's 30x smaller than our other timeout though.
471
+ XCTAssertLessThan ( duration, . seconds( 1 ) )
472
+ }
473
+ }
474
+ #endif
475
+ }
476
+
397
477
func testSelfSignedCertificateIsRejectedWithCorrectErrorIfRequestDeadlineIsExceeded( ) {
398
478
#if compiler(>=5.5.2) && canImport(_Concurrency)
399
479
guard #available( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * ) else { return }
0 commit comments