@@ -341,4 +341,99 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase {
341
341
XCTAssertEqual ( releaseAction. request, . none)
342
342
XCTAssertEqual ( releaseAction. connection, . closeConnection( conn1, isShutdown: . yes( unclean: true ) ) )
343
343
}
344
+
345
+ func testSchedulingAndCancelingOfIdleTimeout( ) {
346
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
347
+ let el1 = elg. next ( )
348
+
349
+ // establish one idle http2 connection
350
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
351
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
352
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
353
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
354
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
355
+ connections: http1Conns,
356
+ requests: HTTPConnectionPool . RequestQueue ( )
357
+ )
358
+ XCTAssertEqual ( migrationAction, . none)
359
+ let conn1 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn1ID, eventLoop: el1)
360
+ let connectAction = state. newHTTP2ConnectionEstablished ( conn1, maxConcurrentStreams: 100 )
361
+ XCTAssertEqual ( connectAction. request, . none)
362
+ XCTAssertEqual ( connectAction. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
363
+
364
+ // execute request on idle connection
365
+ let mockRequest1 = MockHTTPRequest ( eventLoop: el1)
366
+ let request1 = HTTPConnectionPool . Request ( mockRequest1)
367
+ let request1Action = state. executeRequest ( request1)
368
+ XCTAssertEqual ( request1Action. request, . executeRequest( request1, conn1, cancelTimeout: false ) )
369
+ XCTAssertEqual ( request1Action. connection, . cancelTimeoutTimer( conn1ID) )
370
+
371
+ // close stream
372
+ let closeStream1Action = state. http2ConnectionStreamClosed ( conn1ID)
373
+ XCTAssertEqual ( closeStream1Action. request, . none)
374
+ XCTAssertEqual ( closeStream1Action. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
375
+
376
+ // execute request on idle connection with required event loop
377
+ let mockRequest2 = MockHTTPRequest ( eventLoop: el1, requiresEventLoopForChannel: true )
378
+ let request2 = HTTPConnectionPool . Request ( mockRequest2)
379
+ let request2Action = state. executeRequest ( request2)
380
+ XCTAssertEqual ( request2Action. request, . executeRequest( request2, conn1, cancelTimeout: false ) )
381
+ XCTAssertEqual ( request2Action. connection, . cancelTimeoutTimer( conn1ID) )
382
+
383
+ // close stream
384
+ let closeStream2Action = state. http2ConnectionStreamClosed ( conn1ID)
385
+ XCTAssertEqual ( closeStream2Action. request, . none)
386
+ XCTAssertEqual ( closeStream2Action. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
387
+ }
388
+
389
+ func testConnectionTimeout( ) {
390
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
391
+ let el1 = elg. next ( )
392
+
393
+ // establish one idle http2 connection
394
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
395
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
396
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
397
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
398
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
399
+ connections: http1Conns,
400
+ requests: HTTPConnectionPool . RequestQueue ( )
401
+ )
402
+ XCTAssertEqual ( migrationAction, . none)
403
+ let conn1 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn1ID, eventLoop: el1)
404
+ let connectAction = state. newHTTP2ConnectionEstablished ( conn1, maxConcurrentStreams: 100 )
405
+ XCTAssertEqual ( connectAction. request, . none)
406
+ XCTAssertEqual ( connectAction. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
407
+
408
+
409
+ // let the connection timeout
410
+ let timeoutAction = state. connectionIdleTimeout ( conn1ID)
411
+ XCTAssertEqual ( timeoutAction. request, . none)
412
+ XCTAssertEqual ( timeoutAction. connection, . closeConnection( conn1, isShutdown: . no) )
413
+ }
414
+
415
+ func testConnectionEstablishmentFailure( ) {
416
+ struct SomeError : Error , Equatable { }
417
+
418
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
419
+ let el1 = elg. next ( )
420
+
421
+ // establish one idle http2 connection
422
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
423
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
424
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
425
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
426
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
427
+ connections: http1Conns,
428
+ requests: HTTPConnectionPool . RequestQueue ( )
429
+ )
430
+ XCTAssertEqual ( migrationAction, . none)
431
+
432
+ let action = state. failedToCreateNewConnection ( SomeError ( ) , connectionID: conn1ID)
433
+ XCTAssertEqual ( action. request, . none)
434
+ guard case . scheduleBackoffTimer( conn1ID, _, let eventLoop) = action. connection else {
435
+ return XCTFail ( " unexpected connection action \( action. connection) " )
436
+ }
437
+ XCTAssertEqual ( eventLoop. id, el1. id)
438
+ }
344
439
}
0 commit comments