ClientConnectionHandlerStateMachineTests.swift 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import NIOCore
  17. import NIOEmbedded
  18. import XCTest
  19. @testable import GRPCHTTP2Core
  20. final class ClientConnectionHandlerStateMachineTests: XCTestCase {
  21. private func makeStateMachine(
  22. keepaliveWithoutCalls: Bool = false
  23. ) -> ClientConnectionHandler.StateMachine {
  24. return ClientConnectionHandler.StateMachine(allowKeepaliveWithoutCalls: keepaliveWithoutCalls)
  25. }
  26. func testCloseSomeStreamsWhenActive() {
  27. var state = self.makeStateMachine()
  28. state.streamOpened(1)
  29. state.streamOpened(2)
  30. XCTAssertEqual(state.streamClosed(2), .none)
  31. XCTAssertEqual(state.streamClosed(1), .startIdleTimer(cancelKeepalive: true))
  32. }
  33. func testCloseSomeStreamsWhenClosing() {
  34. var state = self.makeStateMachine()
  35. state.streamOpened(1)
  36. state.streamOpened(2)
  37. XCTAssertTrue(state.beginClosing())
  38. XCTAssertEqual(state.streamClosed(2), .none)
  39. XCTAssertEqual(state.streamClosed(1), .close)
  40. }
  41. func testCloseWhenAlreadyClosingGracefully() {
  42. var state = self.makeStateMachine()
  43. state.streamOpened(1)
  44. XCTAssertEqual(state.beginGracefulShutdown(promise: nil), .sendGoAway(false))
  45. XCTAssertTrue(state.beginClosing())
  46. }
  47. func testOpenAndCloseStreamWhenClosed() {
  48. var state = self.makeStateMachine()
  49. _ = state.closed()
  50. state.streamOpened(1)
  51. XCTAssertEqual(state.streamClosed(1), .none)
  52. }
  53. func testSendKeepalivePing() {
  54. var state = self.makeStateMachine(keepaliveWithoutCalls: false)
  55. // No streams open so ping isn't allowed.
  56. XCTAssertFalse(state.sendKeepalivePing())
  57. // Stream open, ping allowed.
  58. state.streamOpened(1)
  59. XCTAssertTrue(state.sendKeepalivePing())
  60. // No stream, no ping.
  61. XCTAssertEqual(state.streamClosed(1), .startIdleTimer(cancelKeepalive: true))
  62. XCTAssertFalse(state.sendKeepalivePing())
  63. }
  64. func testSendKeepalivePingWhenAllowedWithoutCalls() {
  65. var state = self.makeStateMachine(keepaliveWithoutCalls: true)
  66. // Keep alive is allowed when no streams are open, so pings are allowed.
  67. XCTAssertTrue(state.sendKeepalivePing())
  68. state.streamOpened(1)
  69. XCTAssertTrue(state.sendKeepalivePing())
  70. XCTAssertEqual(state.streamClosed(1), .startIdleTimer(cancelKeepalive: false))
  71. XCTAssertTrue(state.sendKeepalivePing())
  72. }
  73. func testSendKeepalivePingWhenClosing() {
  74. var state = self.makeStateMachine(keepaliveWithoutCalls: false)
  75. state.streamOpened(1)
  76. XCTAssertTrue(state.beginClosing())
  77. // Stream is opened and state is closing, ping is allowed.
  78. XCTAssertTrue(state.sendKeepalivePing())
  79. }
  80. func testSendKeepalivePingWhenClosed() {
  81. var state = self.makeStateMachine(keepaliveWithoutCalls: true)
  82. _ = state.closed()
  83. XCTAssertFalse(state.sendKeepalivePing())
  84. }
  85. func testBeginGracefulShutdownWhenStreamsAreOpen() {
  86. var state = self.makeStateMachine()
  87. state.streamOpened(1)
  88. // Close is false as streams are still open.
  89. XCTAssertEqual(state.beginGracefulShutdown(promise: nil), .sendGoAway(false))
  90. }
  91. func testBeginGracefulShutdownWhenNoStreamsAreOpen() {
  92. var state = self.makeStateMachine()
  93. // Close immediately, not streams are open.
  94. XCTAssertEqual(state.beginGracefulShutdown(promise: nil), .sendGoAway(true))
  95. }
  96. }