HTTP2ServerTransport+DebugTests.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * Copyright 2025, 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 GRPCCore
  17. import GRPCNIOTransportHTTP2
  18. import NIOCore
  19. import Synchronization
  20. import Testing
  21. @Suite("ChannelDebugCallbacks")
  22. struct ChannelDebugCallbackTests {
  23. @Test(arguments: TransportKind.supportsDebugCallbacks, TransportKind.supportsDebugCallbacks)
  24. @available(gRPCSwiftNIOTransport 2.0, *)
  25. func debugCallbacksAreCalled(serverKind: TransportKind, clientKind: TransportKind) async throws {
  26. // Validates the callbacks are called appropriately by setting up callbacks which increment
  27. // counters and then returning those stats from a gRPC service. The client's interactions with
  28. // the service drive the callbacks.
  29. let stats = DebugCallbackStats()
  30. let serverDebug = HTTP2ServerTransport.Config.ChannelDebuggingCallbacks(
  31. onBindTCPListener: { channel in
  32. stats.tcpListenersBound.add(1, ordering: .sequentiallyConsistent)
  33. return channel.eventLoop.makeSucceededVoidFuture()
  34. },
  35. onAcceptTCPConnection: { channel in
  36. stats.tcpConnectionsAccepted.add(1, ordering: .sequentiallyConsistent)
  37. return channel.eventLoop.makeSucceededVoidFuture()
  38. },
  39. onAcceptHTTP2Stream: { channel in
  40. stats.http2StreamsAccepted.add(1, ordering: .sequentiallyConsistent)
  41. return channel.eventLoop.makeSucceededVoidFuture()
  42. }
  43. )
  44. let clientDebug = HTTP2ClientTransport.Config.ChannelDebuggingCallbacks(
  45. onCreateTCPConnection: { channel in
  46. stats.tcpConnectionsCreated.add(1, ordering: .sequentiallyConsistent)
  47. return channel.eventLoop.makeSucceededVoidFuture()
  48. },
  49. onCreateHTTP2Stream: { channel in
  50. stats.http2StreamsCreated.add(1, ordering: .sequentiallyConsistent)
  51. return channel.eventLoop.makeSucceededVoidFuture()
  52. }
  53. )
  54. // For each server have the client create this many connections.
  55. let connectionsPerServer = 5
  56. // For each connection have the client create this many streams.
  57. let streamsPerConnection = 3
  58. try await withGRPCServer(
  59. transport: self.makeServerTransport(
  60. kind: serverKind,
  61. address: .ipv4(host: "127.0.0.1", port: 0),
  62. debug: serverDebug
  63. ),
  64. services: [StatsService(stats: stats)]
  65. ) { server in
  66. let address = try await server.listeningAddress!.ipv4!
  67. for connectionNumber in 1 ... connectionsPerServer {
  68. try await withGRPCClient(
  69. transport: self.makeClientTransport(
  70. kind: clientKind,
  71. target: .ipv4(address: address.host, port: address.port),
  72. debug: clientDebug
  73. )
  74. ) { client in
  75. let statsClient = StatsClient(wrapping: client)
  76. // Create a few streams per connection.
  77. for streamNumber in 1 ... streamsPerConnection {
  78. let streamCount = (connectionNumber - 1) * streamsPerConnection + streamNumber
  79. let stats = try await statsClient.getStats()
  80. #expect(stats.server.tcpListenersBound == 1)
  81. #expect(stats.server.tcpConnectionsAccepted == connectionNumber)
  82. #expect(stats.server.http2StreamsAccepted == streamCount)
  83. #expect(stats.client.tcpConnectionsCreated == connectionNumber)
  84. #expect(stats.client.http2StreamsCreated == streamCount)
  85. }
  86. }
  87. }
  88. }
  89. }
  90. @available(gRPCSwiftNIOTransport 2.0, *)
  91. private func makeServerTransport(
  92. kind: TransportKind,
  93. address: GRPCNIOTransportCore.SocketAddress,
  94. debug: HTTP2ServerTransport.Config.ChannelDebuggingCallbacks
  95. ) -> NIOServerTransport {
  96. switch kind {
  97. case .posix:
  98. return NIOServerTransport(
  99. .http2NIOPosix(
  100. address: address,
  101. transportSecurity: .plaintext,
  102. config: .defaults {
  103. $0.channelDebuggingCallbacks = debug
  104. }
  105. )
  106. )
  107. #if canImport(Network)
  108. case .transportServices:
  109. return NIOServerTransport(
  110. .http2NIOTS(
  111. address: address,
  112. transportSecurity: .plaintext,
  113. config: .defaults {
  114. $0.channelDebuggingCallbacks = debug
  115. }
  116. )
  117. )
  118. #endif
  119. case .wrappedChannel:
  120. fatalError("Unsupported")
  121. }
  122. }
  123. @available(gRPCSwiftNIOTransport 2.0, *)
  124. private func makeClientTransport(
  125. kind: TransportKind,
  126. target: any ResolvableTarget,
  127. debug: HTTP2ClientTransport.Config.ChannelDebuggingCallbacks
  128. ) throws -> NIOClientTransport {
  129. switch kind {
  130. case .posix:
  131. return NIOClientTransport(
  132. try .http2NIOPosix(
  133. target: target,
  134. transportSecurity: .plaintext,
  135. config: .defaults {
  136. $0.channelDebuggingCallbacks = debug
  137. }
  138. )
  139. )
  140. #if canImport(Network)
  141. case .transportServices:
  142. return NIOClientTransport(
  143. try .http2NIOTS(
  144. target: target,
  145. transportSecurity: .plaintext,
  146. config: .defaults {
  147. $0.channelDebuggingCallbacks = debug
  148. }
  149. )
  150. )
  151. #endif
  152. case .wrappedChannel:
  153. fatalError("Unsupported")
  154. }
  155. }
  156. }