@@ -495,21 +495,104 @@ class TestURLSession: LoopbackServerTest {
495
495
waitForExpectations ( timeout: 30 )
496
496
}
497
497
498
- func test_timeoutInterval ( ) {
498
+ func test_httpTimeout ( ) {
499
499
let config = URLSessionConfiguration . default
500
500
config. timeoutIntervalForRequest = 10
501
- let urlString = " http://127.0.0.1:-1 /Peru "
501
+ let urlString = " http://127.0.0.1: \( TestURLSession . serverPort ) /Peru "
502
502
let session = URLSession ( configuration: config, delegate: nil , delegateQueue: nil )
503
503
let expect = expectation ( description: " GET \( urlString) : will timeout " )
504
- var req = URLRequest ( url: URL ( string: " http://127.0.0.1:-1/Peru " ) !)
504
+ var req = URLRequest ( url: URL ( string: urlString) !)
505
+ req. setValue ( " 3 " , forHTTPHeaderField: " x-pause " )
505
506
req. timeoutInterval = 1
506
507
let task = session. dataTask ( with: req) { ( data, _, error) -> Void in
507
508
defer { expect. fulfill ( ) }
508
- XCTAssertNotNil ( error)
509
+ XCTAssertEqual ( ( error as? URLError ) ? . code , . timedOut , " Task should fail with URLError.timedOut error " )
509
510
}
510
511
task. resume ( )
512
+ waitForExpectations ( timeout: 30 )
513
+ }
514
+
515
+ func test_connectTimeout( ) {
516
+ // Reconfigure http server for this specific scenario:
517
+ // a slow request keeps web server busy, while other
518
+ // request times out on connection attempt.
519
+ Self . stopServer ( )
520
+ Self . options = Options ( serverBacklog: 1 , isAsynchronous: false )
521
+ Self . startServer ( )
522
+
523
+ let config = URLSessionConfiguration . default
524
+ let slowUrlString = " http://127.0.0.1: \( TestURLSession . serverPort) /Peru "
525
+ let fastUrlString = " http://127.0.0.1: \( TestURLSession . serverPort) /Italy "
526
+ let session = URLSession ( configuration: config, delegate: nil , delegateQueue: nil )
527
+ let slowReqExpect = expectation ( description: " GET \( slowUrlString) : will complete " )
528
+ let fastReqExpect = expectation ( description: " GET \( fastUrlString) : will timeout " )
529
+
530
+ var slowReq = URLRequest ( url: URL ( string: slowUrlString) !)
531
+ slowReq. setValue ( " 3 " , forHTTPHeaderField: " x-pause " )
532
+
533
+ var fastReq = URLRequest ( url: URL ( string: fastUrlString) !)
534
+ fastReq. timeoutInterval = 1
535
+
536
+ let slowTask = session. dataTask ( with: slowReq) { ( data, _, error) -> Void in
537
+ slowReqExpect. fulfill ( )
538
+ }
539
+ let fastTask = session. dataTask ( with: fastReq) { ( data, _, error) -> Void in
540
+ defer { fastReqExpect. fulfill ( ) }
541
+ XCTAssertEqual ( ( error as? URLError ) ? . code, . timedOut, " Task should fail with URLError.timedOut error " )
542
+ }
543
+ slowTask. resume ( )
544
+ Thread . sleep ( forTimeInterval: 0.1 ) // Give slow task some time to start
545
+ fastTask. resume ( )
511
546
512
547
waitForExpectations ( timeout: 30 )
548
+
549
+ // Reconfigure http server back to default settings
550
+ Self . stopServer ( )
551
+ Self . options = . default
552
+ Self . startServer ( )
553
+ }
554
+
555
+ func test_repeatedRequestsStress( ) throws {
556
+ // TODO: try disabling curl connection cache to force socket close early. Or create several url sessions (they have cleanup in deinit)
557
+
558
+ let config = URLSessionConfiguration . default
559
+ let urlString = " http://127.0.0.1: \( TestURLSession . serverPort) /Peru "
560
+ let session = URLSession ( configuration: config, delegate: nil , delegateQueue: nil )
561
+ let req = URLRequest ( url: URL ( string: urlString) !)
562
+
563
+ var requestsLeft = 3000
564
+ let expect = expectation ( description: " \( requestsLeft) x GET \( urlString) " )
565
+
566
+ func doRequests( completion: @escaping ( ) -> Void ) {
567
+ // We only care about completion of one of the tasks,
568
+ // so we could move to next cycle.
569
+ // Some overlapping would happen and that's what we
570
+ // want actually to provoke issue with socket reuse
571
+ // on Windows.
572
+ let task = session. dataTask ( with: req) { ( _, _, _) -> Void in
573
+ }
574
+ task. resume ( )
575
+ let task2 = session. dataTask ( with: req) { ( _, _, _) -> Void in
576
+ }
577
+ task2. resume ( )
578
+ let task3 = session. dataTask ( with: req) { ( _, _, _) -> Void in
579
+ completion ( )
580
+ }
581
+ task3. resume ( )
582
+ }
583
+
584
+ func checkCountAndRunNext( ) {
585
+ guard requestsLeft > 0 else {
586
+ expect. fulfill ( )
587
+ return
588
+ }
589
+ requestsLeft -= 1
590
+ doRequests ( completion: checkCountAndRunNext)
591
+ }
592
+
593
+ checkCountAndRunNext ( )
594
+
595
+ waitForExpectations ( timeout: 30 )
513
596
}
514
597
515
598
func test_httpRedirectionWithCode300( ) throws {
@@ -2049,7 +2132,6 @@ class TestURLSession: LoopbackServerTest {
2049
2132
( " test_taskTimeout " , test_taskTimeout) ,
2050
2133
( " test_verifyRequestHeaders " , test_verifyRequestHeaders) ,
2051
2134
( " test_verifyHttpAdditionalHeaders " , test_verifyHttpAdditionalHeaders) ,
2052
- ( " test_timeoutInterval " , test_timeoutInterval) ,
2053
2135
( " test_httpRedirectionWithCode300 " , test_httpRedirectionWithCode300) ,
2054
2136
( " test_httpRedirectionWithCode301_302 " , test_httpRedirectionWithCode301_302) ,
2055
2137
( " test_httpRedirectionWithCode303 " , test_httpRedirectionWithCode303) ,
@@ -2098,6 +2180,7 @@ class TestURLSession: LoopbackServerTest {
2098
2180
/* ⚠️ */ testExpectedToFail ( test_noDoubleCallbackWhenCancellingAndProtocolFailsFast, " This test crashes nondeterministically: https://bugs.swift.org/browse/SR-11310 " ) ) ,
2099
2181
/* ⚠️ */ ( " test_cancelledTasksCannotBeResumed " , testExpectedToFail ( test_cancelledTasksCannotBeResumed, " Breaks on Ubuntu 18.04 " ) ) ,
2100
2182
]
2183
+ #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT
2101
2184
if #available( macOS 12 . 0 , * ) {
2102
2185
retVal. append ( contentsOf: [
2103
2186
( " test_webSocket " , asyncTest ( test_webSocket) ) ,
@@ -2106,6 +2189,19 @@ class TestURLSession: LoopbackServerTest {
2106
2189
( " test_webSocketSemiAbruptClose " , asyncTest ( test_webSocketSemiAbruptClose) ) ,
2107
2190
] )
2108
2191
}
2192
+ #endif
2193
+ #if os(Windows)
2194
+ retVal. append ( contentsOf: [
2195
+ ( " test_httpTimeout " , test_httpTimeout) ,
2196
+ ( " test_connectTimeout " , test_connectTimeout) ,
2197
+ ( " test_repeatedRequestsStress " , test_repeatedRequestsStress) ,
2198
+ ] )
2199
+ #else
2200
+ retVal. append ( contentsOf: [
2201
+ ( " test_httpTimeout " , test_httpTimeout) ,
2202
+ ( " test_connectTimeout " , test_connectTimeout) ,
2203
+ ] )
2204
+ #endif
2109
2205
return retVal
2110
2206
}
2111
2207
0 commit comments