@@ -1244,4 +1244,59 @@ class HTTPClientTests: XCTestCase {
1244
1244
}
1245
1245
}
1246
1246
}
1247
+
1248
+ func testRaceNewRequestsVsShutdown( ) {
1249
+ let numberOfWorkers = 20
1250
+ let allWorkersReady = DispatchSemaphore ( value: 0 )
1251
+ let allWorkersGo = DispatchSemaphore ( value: 0 )
1252
+ let allDone = DispatchGroup ( )
1253
+
1254
+ let httpBin = HTTPBin ( )
1255
+ defer {
1256
+ XCTAssertNoThrow ( try httpBin. shutdown ( ) )
1257
+ }
1258
+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew)
1259
+ defer {
1260
+ XCTAssertThrowsError ( try httpClient. syncShutdown ( ) ) { error in
1261
+ XCTAssertEqual ( . alreadyShutdown, error as? HTTPClientError )
1262
+ }
1263
+ }
1264
+
1265
+ let url = " http://localhost: \( httpBin. port) /get "
1266
+ XCTAssertNoThrow ( XCTAssertEqual ( . ok, try httpClient. get ( url: url) . wait ( ) . status) )
1267
+
1268
+ for w in 0 ..< numberOfWorkers {
1269
+ let q = DispatchQueue ( label: " worker \( w) " )
1270
+ q. async ( group: allDone) {
1271
+ func go( ) {
1272
+ allWorkersReady. signal ( ) // tell the driver we're ready
1273
+ allWorkersGo. wait ( ) // wait for the driver to let us go
1274
+
1275
+ do {
1276
+ while true {
1277
+ let result = try httpClient. get ( url: url) . wait ( ) . status
1278
+ XCTAssertEqual ( . ok, result)
1279
+ }
1280
+ } catch {
1281
+ // ok, we failed, pool probably shutdown
1282
+ XCTAssertEqual ( . cancelled, error as? HTTPClientError )
1283
+ }
1284
+ }
1285
+ go ( )
1286
+ }
1287
+ }
1288
+
1289
+ for _ in 0 ..< numberOfWorkers {
1290
+ allWorkersReady. wait ( )
1291
+ }
1292
+ // now all workers should be waiting for the go signal
1293
+
1294
+ for _ in 0 ..< numberOfWorkers {
1295
+ allWorkersGo. signal ( )
1296
+ }
1297
+ Thread . sleep ( until: . init( timeIntervalSinceNow: 0.2 ) )
1298
+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
1299
+ // all workers should be running, let's wait for them to finish
1300
+ allDone. wait ( )
1301
+ }
1247
1302
}
0 commit comments