@@ -435,4 +435,122 @@ class HTTPConnectionPool_HTTP2StateMachineTests: XCTestCase {
435
435
}
436
436
XCTAssertEqual ( eventLoop. id, el1. id)
437
437
}
438
+
439
+ func testGoAwayOnIdleConnection( ) {
440
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
441
+ let el1 = elg. next ( )
442
+
443
+ // establish one idle http2 connection
444
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
445
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
446
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
447
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
448
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
449
+ connections: http1Conns,
450
+ requests: HTTPConnectionPool . RequestQueue ( )
451
+ )
452
+ XCTAssertEqual ( migrationAction, . none)
453
+ let conn1 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn1ID, eventLoop: el1)
454
+ let connectAction = state. newHTTP2ConnectionEstablished ( conn1, maxConcurrentStreams: 100 )
455
+ XCTAssertEqual ( connectAction. request, . none)
456
+ XCTAssertEqual ( connectAction. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
457
+
458
+ let goAwayAction = state. http2ConnectionGoAwayReceived ( conn1ID)
459
+ XCTAssertEqual ( goAwayAction. request, . none)
460
+ XCTAssertEqual ( goAwayAction. connection, . none, " Connection is automatically closed by HTTP2IdleHandler " )
461
+ }
462
+
463
+ func testGoAwayWithLeasedStream( ) {
464
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
465
+ let el1 = elg. next ( )
466
+
467
+ // establish one idle http2 connection
468
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
469
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
470
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
471
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
472
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
473
+ connections: http1Conns,
474
+ requests: HTTPConnectionPool . RequestQueue ( )
475
+ )
476
+ XCTAssertEqual ( migrationAction, . none)
477
+ let conn1 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn1ID, eventLoop: el1)
478
+ let connectAction = state. newHTTP2ConnectionEstablished ( conn1, maxConcurrentStreams: 100 )
479
+ XCTAssertEqual ( connectAction. request, . none)
480
+ XCTAssertEqual ( connectAction. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
481
+
482
+ // execute request on idle connection
483
+ let mockRequest1 = MockHTTPRequest ( eventLoop: el1)
484
+ let request1 = HTTPConnectionPool . Request ( mockRequest1)
485
+ let request1Action = state. executeRequest ( request1)
486
+ XCTAssertEqual ( request1Action. request, . executeRequest( request1, conn1, cancelTimeout: false ) )
487
+ XCTAssertEqual ( request1Action. connection, . cancelTimeoutTimer( conn1ID) )
488
+
489
+ let goAwayAction = state. http2ConnectionGoAwayReceived ( conn1ID)
490
+ XCTAssertEqual ( goAwayAction. request, . none)
491
+ XCTAssertEqual ( goAwayAction. connection, . none)
492
+
493
+ // close stream
494
+ let closeStream1Action = state. http2ConnectionStreamClosed ( conn1ID)
495
+ XCTAssertEqual ( closeStream1Action. request, . none)
496
+ XCTAssertEqual ( closeStream1Action. connection, . none, " Connection is automatically closed by HTTP2IdleHandler " )
497
+ }
498
+
499
+ func testGoAwayWithPendingRequestsStartsNewConnection( ) {
500
+ let elg = EmbeddedEventLoopGroup ( loops: 1 )
501
+ let el1 = elg. next ( )
502
+
503
+ // establish one idle http2 connection
504
+ let idGenerator = HTTPConnectionPool . Connection. ID. Generator ( )
505
+ var http1Conns = HTTPConnectionPool . HTTP1Connections ( maximumConcurrentConnections: 8 , generator: idGenerator)
506
+ let conn1ID = http1Conns. createNewConnection ( on: el1)
507
+ var state = HTTPConnectionPool . HTTP2StateMachine ( idGenerator: idGenerator)
508
+ let migrationAction = state. migrateConnectionsFromHTTP1 (
509
+ connections: http1Conns,
510
+ requests: HTTPConnectionPool . RequestQueue ( )
511
+ )
512
+ XCTAssertEqual ( migrationAction, . none)
513
+ let conn1 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn1ID, eventLoop: el1)
514
+ let connectAction1 = state. newHTTP2ConnectionEstablished ( conn1, maxConcurrentStreams: 1 )
515
+ XCTAssertEqual ( connectAction1. request, . none)
516
+ XCTAssertEqual ( connectAction1. connection, . scheduleTimeoutTimer( conn1ID, on: el1) )
517
+
518
+ // execute request
519
+ let mockRequest1 = MockHTTPRequest ( eventLoop: el1)
520
+ let request1 = HTTPConnectionPool . Request ( mockRequest1)
521
+ let request1Action = state. executeRequest ( request1)
522
+ XCTAssertEqual ( request1Action. request, . executeRequest( request1, conn1, cancelTimeout: false ) )
523
+ XCTAssertEqual ( request1Action. connection, . cancelTimeoutTimer( conn1ID) )
524
+
525
+ // queue request
526
+ let mockRequest2 = MockHTTPRequest ( eventLoop: el1)
527
+ let request2 = HTTPConnectionPool . Request ( mockRequest2)
528
+ let request2Action = state. executeRequest ( request2)
529
+ XCTAssertEqual ( request2Action. request, . scheduleRequestTimeout( for: request2, on: el1) )
530
+ XCTAssertEqual ( request2Action. connection, . none)
531
+
532
+ // go away should create a new connection
533
+ let goAwayAction = state. http2ConnectionGoAwayReceived ( conn1ID)
534
+ XCTAssertEqual ( goAwayAction. request, . none)
535
+ guard case . createConnection( let conn2ID, let eventLoop) = goAwayAction. connection else {
536
+ return XCTFail ( " unexpected connection action \( goAwayAction. connection) " )
537
+ }
538
+ XCTAssertEqual ( el1. id, eventLoop. id)
539
+
540
+ // new connection should execute pending request
541
+ let conn2 = HTTPConnectionPool . Connection. __testOnly_connection ( id: conn2ID, eventLoop: el1)
542
+ let connectAction2 = state. newHTTP2ConnectionEstablished ( conn2, maxConcurrentStreams: 1 )
543
+ XCTAssertEqual ( connectAction2. request, . executeRequestsAndCancelTimeouts( [ request2] , conn2) )
544
+ XCTAssertEqual ( connectAction2. connection, . none)
545
+
546
+ // close stream from conn1
547
+ let closeStream1Action = state. http2ConnectionStreamClosed ( conn1ID)
548
+ XCTAssertEqual ( closeStream1Action. request, . none)
549
+ XCTAssertEqual ( closeStream1Action. connection, . none, " Connection is automatically closed by HTTP2IdleHandler " )
550
+
551
+ // close stream from conn2
552
+ let closeStream2Action = state. http2ConnectionStreamClosed ( conn2ID)
553
+ XCTAssertEqual ( closeStream2Action. request, . none)
554
+ XCTAssertEqual ( closeStream2Action. connection, . scheduleTimeoutTimer( conn2ID, on: el1) )
555
+ }
438
556
}
0 commit comments