diff --git a/Sources/Examples/Echo/Model/echo.grpc.swift b/Sources/Examples/Echo/Model/echo.grpc.swift index 9e91d1488..1ade5bd0f 100644 --- a/Sources/Examples/Echo/Model/echo.grpc.swift +++ b/Sources/Examples/Echo/Model/echo.grpc.swift @@ -214,7 +214,8 @@ extension Echo_EchoAsyncClientProtocol { return self.makeAsyncUnaryCall( path: "/echo.Echo/Get", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeGetInterceptors() ?? [] ) } @@ -225,7 +226,8 @@ extension Echo_EchoAsyncClientProtocol { return self.makeAsyncServerStreamingCall( path: "/echo.Echo/Expand", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeExpandInterceptors() ?? [] ) } @@ -234,7 +236,8 @@ extension Echo_EchoAsyncClientProtocol { ) -> GRPCAsyncClientStreamingCall { return self.makeAsyncClientStreamingCall( path: "/echo.Echo/Collect", - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeCollectInterceptors() ?? [] ) } @@ -243,7 +246,8 @@ extension Echo_EchoAsyncClientProtocol { ) -> GRPCAsyncBidirectionalStreamingCall { return self.makeAsyncBidirectionalStreamingCall( path: "/echo.Echo/Update", - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeUpdateInterceptors() ?? [] ) } } @@ -257,7 +261,8 @@ extension Echo_EchoAsyncClientProtocol { return try await self.performAsyncUnaryCall( path: "/echo.Echo/Get", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeGetInterceptors() ?? [] ) } @@ -268,7 +273,8 @@ extension Echo_EchoAsyncClientProtocol { return self.performAsyncServerStreamingCall( path: "/echo.Echo/Expand", request: request, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeExpandInterceptors() ?? [] ) } @@ -279,7 +285,8 @@ extension Echo_EchoAsyncClientProtocol { return try await self.performAsyncClientStreamingCall( path: "/echo.Echo/Collect", requests: requests, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeCollectInterceptors() ?? [] ) } @@ -290,7 +297,8 @@ extension Echo_EchoAsyncClientProtocol { return try await self.performAsyncClientStreamingCall( path: "/echo.Echo/Collect", requests: requests, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeCollectInterceptors() ?? [] ) } @@ -301,7 +309,8 @@ extension Echo_EchoAsyncClientProtocol { return self.performAsyncBidirectionalStreamingCall( path: "/echo.Echo/Update", requests: requests, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeUpdateInterceptors() ?? [] ) } @@ -312,7 +321,8 @@ extension Echo_EchoAsyncClientProtocol { return self.performAsyncBidirectionalStreamingCall( path: "/echo.Echo/Update", requests: requests, - callOptions: callOptions ?? self.defaultCallOptions + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeUpdateInterceptors() ?? [] ) } } diff --git a/Sources/Examples/HelloWorld/Model/helloworld.grpc.swift b/Sources/Examples/HelloWorld/Model/helloworld.grpc.swift index f232bac73..4f90d36d9 100644 --- a/Sources/Examples/HelloWorld/Model/helloworld.grpc.swift +++ b/Sources/Examples/HelloWorld/Model/helloworld.grpc.swift @@ -131,3 +131,4 @@ public protocol Helloworld_GreeterServerInterceptorFactoryProtocol { /// Defaults to calling `self.makeInterceptors()`. func makeSayHelloInterceptors() -> [ServerInterceptor] } + diff --git a/Sources/Examples/RouteGuide/Model/route_guide.grpc.swift b/Sources/Examples/RouteGuide/Model/route_guide.grpc.swift index 3e225310b..951abdff0 100644 --- a/Sources/Examples/RouteGuide/Model/route_guide.grpc.swift +++ b/Sources/Examples/RouteGuide/Model/route_guide.grpc.swift @@ -295,3 +295,4 @@ public protocol Routeguide_RouteGuideServerInterceptorFactoryProtocol { /// Defaults to calling `self.makeInterceptors()`. func makeRouteChatInterceptors() -> [ServerInterceptor] } + diff --git a/Sources/protoc-gen-grpc-swift/Generator-Client+AsyncAwait.swift b/Sources/protoc-gen-grpc-swift/Generator-Client+AsyncAwait.swift index 9244f1ca3..d91a6a33c 100644 --- a/Sources/protoc-gen-grpc-swift/Generator-Client+AsyncAwait.swift +++ b/Sources/protoc-gen-grpc-swift/Generator-Client+AsyncAwait.swift @@ -108,7 +108,10 @@ extension Generator { self.withIndentation("return self.make\(callTypeWithoutPrefix)", braces: .round) { self.println("path: \(self.methodPath),") self.println("request: request,") - self.println("callOptions: callOptions ?? self.defaultCallOptions") + self.println("callOptions: callOptions ?? self.defaultCallOptions,") + self.println( + "interceptors: self.interceptors?.\(self.methodInterceptorFactoryName)() ?? []" + ) } } @@ -121,7 +124,10 @@ extension Generator { ) { self.withIndentation("return self.make\(callTypeWithoutPrefix)", braces: .round) { self.println("path: \(self.methodPath),") - self.println("callOptions: callOptions ?? self.defaultCallOptions") + self.println("callOptions: callOptions ?? self.defaultCallOptions,") + self.println( + "interceptors: self.interceptors?.\(self.methodInterceptorFactoryName)() ?? []" + ) } } } @@ -181,7 +187,10 @@ extension Generator { ) { self.println("path: \(self.methodPath),") self.println("\(requestParamName): \(requestParamName),") - self.println("callOptions: callOptions ?? self.defaultCallOptions") + self.println("callOptions: callOptions ?? self.defaultCallOptions,") + self.println( + "interceptors: self.interceptors?.\(self.methodInterceptorFactoryName)() ?? []" + ) } } } diff --git a/Tests/GRPCTests/AsyncAwaitSupport/InterceptorsAsyncTests.swift b/Tests/GRPCTests/AsyncAwaitSupport/InterceptorsAsyncTests.swift new file mode 100644 index 000000000..1d29ad075 --- /dev/null +++ b/Tests/GRPCTests/AsyncAwaitSupport/InterceptorsAsyncTests.swift @@ -0,0 +1,173 @@ +/* + * Copyright 2021, 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. + */ +#if compiler(>=5.5) +import EchoImplementation +import EchoModel +import GRPC +import HelloWorldModel +import NIOCore +import NIOHPACK +import NIOPosix +import SwiftProtobuf +import XCTest + +@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +class InterceptorsAsyncTests: GRPCTestCase { + private var group: EventLoopGroup! + private var server: Server! + private var connection: ClientConnection! + private var echo: Echo_EchoAsyncClient! + + override func setUp() { + super.setUp() + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + self.group = group + + let server = try! Server.insecure(group: group) + .withServiceProviders([EchoProvider()]) + .withLogger(self.serverLogger) + .bind(host: "127.0.0.1", port: 0) + .wait() + + self.server = server + + let connection = ClientConnection.insecure(group: group) + .withBackgroundActivityLogger(self.clientLogger) + .connect(host: "127.0.0.1", port: server.channel.localAddress!.port!) + + self.connection = connection + + self.echo = Echo_EchoAsyncClient( + channel: connection, + defaultCallOptions: CallOptions(logger: self.clientLogger), + interceptors: ReversingInterceptors() + ) + } + + override func tearDown() { + if let connection = self.connection { + XCTAssertNoThrow(try connection.close().wait()) + } + if let server = self.server { + XCTAssertNoThrow(try server.close().wait()) + } + if let group = self.group { + XCTAssertNoThrow(try group.syncShutdownGracefully()) + } + + super.tearDown() + } + + func testUnaryCall() { XCTAsyncTest { + let get = try await self.echo.get(.with { $0.text = "hello" }) + await assertThat(get, .is(.with { $0.text = "hello :teg ohce tfiwS" })) + } } + + func testMakingUnaryCall() { XCTAsyncTest { + let call = self.echo.makeGetCall(.with { $0.text = "hello" }) + await assertThat(try await call.response, .is(.with { $0.text = "hello :teg ohce tfiwS" })) + } } + + func testClientStreamingSequence() { XCTAsyncTest { + let requests = ["1 2", "3 4"].map { item in + Echo_EchoRequest.with { $0.text = item } + } + let response = try await self.echo.collect(requests, callOptions: .init()) + + await assertThat(response, .is(.with { $0.text = "3 4 1 2 :tcelloc ohce tfiwS" })) + } } + + func testClientStreamingAsyncSequence() { XCTAsyncTest { + let stream = AsyncStream { continuation in + continuation.yield(.with { $0.text = "1 2" }) + continuation.yield(.with { $0.text = "3 4" }) + continuation.finish() + } + let response = try await self.echo.collect(stream, callOptions: .init()) + + await assertThat(response, .is(.with { $0.text = "3 4 1 2 :tcelloc ohce tfiwS" })) + } } + + func testMakingCallClientStreaming() { XCTAsyncTest { + let call = self.echo.makeCollectCall(callOptions: .init()) + try await call.requestStream.send(.with { $0.text = "1 2" }) + try await call.requestStream.send(.with { $0.text = "3 4" }) + try await call.requestStream.finish() + + await assertThat( + try await call.response, + .is(.with { $0.text = "3 4 1 2 :tcelloc ohce tfiwS" }) + ) + } } + + func testServerStreaming() { XCTAsyncTest { + let responses = self.echo.expand(.with { $0.text = "hello" }, callOptions: .init()) + for try await response in responses { + // Expand splits on spaces, so we only expect one response. + await assertThat(response, .is(.with { $0.text = "hello :)0( dnapxe ohce tfiwS" })) + } + } } + + func testMakingCallServerStreaming() { XCTAsyncTest { + let call = self.echo.makeExpandCall(.with { $0.text = "hello" }, callOptions: .init()) + for try await response in call.responses { + // Expand splits on spaces, so we only expect one response. + await assertThat(response, .is(.with { $0.text = "hello :)0( dnapxe ohce tfiwS" })) + } + } } + + func testBidirectionalStreaming() { XCTAsyncTest { + let requests = ["1 2", "3 4"].map { item in + Echo_EchoRequest.with { $0.text = item } + } + let responses = self.echo.update(requests, callOptions: .init()) + + var count = 0 + for try await response in responses { + switch count { + case 0: + await assertThat(response, .is(.with { $0.text = "1 2 :)0( etadpu ohce tfiwS" })) + case 1: + await assertThat(response, .is(.with { $0.text = "3 4 :)1( etadpu ohce tfiwS" })) + default: + XCTFail("Got more than 2 responses") + } + count += 1 + } + } } + + func testMakingCallBidirectionalStreaming() { XCTAsyncTest { + let call = self.echo.makeUpdateCall(callOptions: .init()) + try await call.requestStream.send(.with { $0.text = "1 2" }) + try await call.requestStream.send(.with { $0.text = "3 4" }) + try await call.requestStream.finish() + + var count = 0 + for try await response in call.responses { + switch count { + case 0: + await assertThat(response, .is(.with { $0.text = "1 2 :)0( etadpu ohce tfiwS" })) + case 1: + await assertThat(response, .is(.with { $0.text = "3 4 :)1( etadpu ohce tfiwS" })) + default: + XCTFail("Got more than 2 responses") + } + count += 1 + } + } } +} + +#endif diff --git a/Tests/GRPCTests/Codegen/Normalization/normalization.grpc.swift b/Tests/GRPCTests/Codegen/Normalization/normalization.grpc.swift index 999b6d3c7..ff83c06b6 100644 --- a/Tests/GRPCTests/Codegen/Normalization/normalization.grpc.swift +++ b/Tests/GRPCTests/Codegen/Normalization/normalization.grpc.swift @@ -425,3 +425,4 @@ internal protocol Normalization_NormalizationServerInterceptorFactoryProtocol { /// Defaults to calling `self.makeInterceptors()`. func makebidirectionalStreamingInterceptors() -> [ServerInterceptor] } + diff --git a/Tests/GRPCTests/InterceptorsTests.swift b/Tests/GRPCTests/InterceptorsTests.swift index ef115ccec..48833b10d 100644 --- a/Tests/GRPCTests/InterceptorsTests.swift +++ b/Tests/GRPCTests/InterceptorsTests.swift @@ -335,7 +335,7 @@ class EchoReverseInterceptor: ClientInterceptor