| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /*
- * Copyright 2025, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import GRPCCore
- import GRPCNIOTransportHTTP2
- import NIOCore
- import Synchronization
- import Testing
- @Suite("ChannelDebugCallbacks")
- struct ChannelDebugCallbackTests {
- @Test(arguments: TransportKind.supportsDebugCallbacks, TransportKind.supportsDebugCallbacks)
- @available(gRPCSwiftNIOTransport 2.0, *)
- func debugCallbacksAreCalled(serverKind: TransportKind, clientKind: TransportKind) async throws {
- // Validates the callbacks are called appropriately by setting up callbacks which increment
- // counters and then returning those stats from a gRPC service. The client's interactions with
- // the service drive the callbacks.
- let stats = DebugCallbackStats()
- let serverDebug = HTTP2ServerTransport.Config.ChannelDebuggingCallbacks(
- onBindTCPListener: { channel in
- stats.tcpListenersBound.add(1, ordering: .sequentiallyConsistent)
- return channel.eventLoop.makeSucceededVoidFuture()
- },
- onAcceptTCPConnection: { channel in
- stats.tcpConnectionsAccepted.add(1, ordering: .sequentiallyConsistent)
- return channel.eventLoop.makeSucceededVoidFuture()
- },
- onAcceptHTTP2Stream: { channel in
- stats.http2StreamsAccepted.add(1, ordering: .sequentiallyConsistent)
- return channel.eventLoop.makeSucceededVoidFuture()
- }
- )
- let clientDebug = HTTP2ClientTransport.Config.ChannelDebuggingCallbacks(
- onCreateTCPConnection: { channel in
- stats.tcpConnectionsCreated.add(1, ordering: .sequentiallyConsistent)
- return channel.eventLoop.makeSucceededVoidFuture()
- },
- onCreateHTTP2Stream: { channel in
- stats.http2StreamsCreated.add(1, ordering: .sequentiallyConsistent)
- return channel.eventLoop.makeSucceededVoidFuture()
- }
- )
- // For each server have the client create this many connections.
- let connectionsPerServer = 5
- // For each connection have the client create this many streams.
- let streamsPerConnection = 3
- try await withGRPCServer(
- transport: self.makeServerTransport(
- kind: serverKind,
- address: .ipv4(host: "127.0.0.1", port: 0),
- debug: serverDebug
- ),
- services: [StatsService(stats: stats)]
- ) { server in
- let address = try await server.listeningAddress!.ipv4!
- for connectionNumber in 1 ... connectionsPerServer {
- try await withGRPCClient(
- transport: self.makeClientTransport(
- kind: clientKind,
- target: .ipv4(address: address.host, port: address.port),
- debug: clientDebug
- )
- ) { client in
- let statsClient = StatsClient(wrapping: client)
- // Create a few streams per connection.
- for streamNumber in 1 ... streamsPerConnection {
- let streamCount = (connectionNumber - 1) * streamsPerConnection + streamNumber
- let stats = try await statsClient.getStats()
- #expect(stats.server.tcpListenersBound == 1)
- #expect(stats.server.tcpConnectionsAccepted == connectionNumber)
- #expect(stats.server.http2StreamsAccepted == streamCount)
- #expect(stats.client.tcpConnectionsCreated == connectionNumber)
- #expect(stats.client.http2StreamsCreated == streamCount)
- }
- }
- }
- }
- }
- @available(gRPCSwiftNIOTransport 2.0, *)
- private func makeServerTransport(
- kind: TransportKind,
- address: GRPCNIOTransportCore.SocketAddress,
- debug: HTTP2ServerTransport.Config.ChannelDebuggingCallbacks
- ) -> NIOServerTransport {
- switch kind {
- case .posix:
- return NIOServerTransport(
- .http2NIOPosix(
- address: address,
- transportSecurity: .plaintext,
- config: .defaults {
- $0.channelDebuggingCallbacks = debug
- }
- )
- )
- #if canImport(Network)
- case .transportServices:
- return NIOServerTransport(
- .http2NIOTS(
- address: address,
- transportSecurity: .plaintext,
- config: .defaults {
- $0.channelDebuggingCallbacks = debug
- }
- )
- )
- #endif
- case .wrappedChannel:
- fatalError("Unsupported")
- }
- }
- @available(gRPCSwiftNIOTransport 2.0, *)
- private func makeClientTransport(
- kind: TransportKind,
- target: any ResolvableTarget,
- debug: HTTP2ClientTransport.Config.ChannelDebuggingCallbacks
- ) throws -> NIOClientTransport {
- switch kind {
- case .posix:
- return NIOClientTransport(
- try .http2NIOPosix(
- target: target,
- transportSecurity: .plaintext,
- config: .defaults {
- $0.channelDebuggingCallbacks = debug
- }
- )
- )
- #if canImport(Network)
- case .transportServices:
- return NIOClientTransport(
- try .http2NIOTS(
- target: target,
- transportSecurity: .plaintext,
- config: .defaults {
- $0.channelDebuggingCallbacks = debug
- }
- )
- )
- #endif
- case .wrappedChannel:
- fatalError("Unsupported")
- }
- }
- }
|