diff options
author | Yash Tibrewal <yashkt@google.com> | 2018-09-12 16:58:44 -0700 |
---|---|---|
committer | Yash Tibrewal <yashkt@google.com> | 2018-09-26 19:25:30 -0700 |
commit | a1598c5abfadf9e622d21a5cc0f754b412378314 (patch) | |
tree | 2f1358e3a781f503d29fe670107732cc2227f6d7 | |
parent | c3db7d21ce1dfbd6f25bde500af62fd1c197928f (diff) |
Create interfaces and initial plumbing for interception API
-rw-r--r-- | include/grpcpp/channel.h | 14 | ||||
-rw-r--r-- | include/grpcpp/create_channel.h | 21 | ||||
-rw-r--r-- | include/grpcpp/impl/codegen/client_interceptor.h | 44 | ||||
-rw-r--r-- | include/grpcpp/impl/codegen/interceptor.h | 67 | ||||
-rw-r--r-- | include/grpcpp/security/credentials.h | 28 | ||||
-rw-r--r-- | src/cpp/client/channel_cc.cc | 8 | ||||
-rw-r--r-- | src/cpp/client/create_channel.cc | 42 | ||||
-rw-r--r-- | src/cpp/client/create_channel_internal.cc | 10 | ||||
-rw-r--r-- | src/cpp/client/create_channel_internal.h | 8 | ||||
-rw-r--r-- | src/cpp/client/create_channel_posix.cc | 9 | ||||
-rw-r--r-- | src/cpp/client/cronet_credentials.cc | 19 | ||||
-rw-r--r-- | src/cpp/client/insecure_credentials.cc | 11 | ||||
-rw-r--r-- | src/cpp/client/secure_credentials.cc | 12 | ||||
-rw-r--r-- | src/cpp/client/secure_credentials.h | 6 | ||||
-rw-r--r-- | src/cpp/server/server_cc.cc | 3 | ||||
-rw-r--r-- | test/cpp/microbenchmarks/bm_call_create.cc | 6 | ||||
-rw-r--r-- | test/cpp/microbenchmarks/fullstack_fixtures.h | 2 | ||||
-rw-r--r-- | test/cpp/performance/writes_per_rpc_test.cc | 2 |
18 files changed, 284 insertions, 28 deletions
diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h index f1dba5b8ad..b7c9e354de 100644 --- a/include/grpcpp/channel.h +++ b/include/grpcpp/channel.h @@ -24,6 +24,7 @@ #include <grpc/grpc.h> #include <grpcpp/impl/call.h> #include <grpcpp/impl/codegen/channel_interface.h> +#include <grpcpp/impl/codegen/client_interceptor.h> #include <grpcpp/impl/codegen/config.h> #include <grpcpp/impl/codegen/grpc_library.h> @@ -62,8 +63,14 @@ class Channel final : public ChannelInterface, friend class internal::BlockingUnaryCallImpl; friend void experimental::ChannelResetConnectionBackoff(Channel* channel); friend std::shared_ptr<Channel> CreateChannelInternal( - const grpc::string& host, grpc_channel* c_channel); - Channel(const grpc::string& host, grpc_channel* c_channel); + const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); + Channel(const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); internal::Call CreateCall(const internal::RpcMethod& method, ClientContext* context, @@ -91,6 +98,9 @@ class Channel final : public ChannelInterface, // It is _not owned_ by the channel; ownership belongs with its internal // shutdown callback tag (invoked when the CQ is fully shutdown). CompletionQueue* callback_cq_ = nullptr; + + std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>> + interceptor_creators_; }; } // namespace grpc diff --git a/include/grpcpp/create_channel.h b/include/grpcpp/create_channel.h index 7a505a7127..43188d09e7 100644 --- a/include/grpcpp/create_channel.h +++ b/include/grpcpp/create_channel.h @@ -22,6 +22,7 @@ #include <memory> #include <grpcpp/channel.h> +#include <grpcpp/impl/codegen/client_interceptor.h> #include <grpcpp/security/credentials.h> #include <grpcpp/support/channel_arguments.h> #include <grpcpp/support/config.h> @@ -53,6 +54,26 @@ std::shared_ptr<Channel> CreateCustomChannel( const std::shared_ptr<ChannelCredentials>& creds, const ChannelArguments& args); +namespace experimental { +/// Create a new \em custom \a Channel pointing to \a target with \a +/// interceptors being invoked per call. +/// +/// \warning For advanced use and testing ONLY. Override default channel +/// arguments only if necessary. +/// +/// \param target The URI of the endpoint to connect to. +/// \param creds Credentials to use for the created channel. If it does not +/// hold an object or is invalid, a lame channel (one on which all operations +/// fail) is returned. +/// \param args Options for channel creation. +std::shared_ptr<Channel> CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); +} // namespace experimental } // namespace grpc #endif // GRPCPP_CREATE_CHANNEL_H diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h new file mode 100644 index 0000000000..23111b2c4b --- /dev/null +++ b/include/grpcpp/impl/codegen/client_interceptor.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * 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. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H +#define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H + +#include <grpcpp/impl/codegen/interceptor.h> +#include <string> + +namespace grpc { +namespace experimental { +class ClientInterceptor { + public: + virtual ~ClientInterceptor() {} + + virtual void Intercept(InterceptorBatchMethods* methods) = 0; +}; + +class ClientRpcInfo {}; + +class ClientInterceptorFactoryInterface { + public: + virtual ~ClientInterceptorFactoryInterface() {} + virtual ClientInterceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0; +}; + +} // namespace experimental +} // namespace grpc +#endif /* GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H */ diff --git a/include/grpcpp/impl/codegen/interceptor.h b/include/grpcpp/impl/codegen/interceptor.h new file mode 100644 index 0000000000..930183e981 --- /dev/null +++ b/include/grpcpp/impl/codegen/interceptor.h @@ -0,0 +1,67 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * 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. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H +#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H + +namespace grpc { +namespace experimental { +class InterceptedMessage { + public: + template <class M> + bool Extract(M* msg); // returns false if definitely invalid extraction + template <class M> + M* MutableExtract(); + uint64_t length(); // length on wire +}; + +enum class InterceptionHookPoints { + /* The first two in this list are for clients and servers */ + PRE_SEND_INITIAL_METADATA, + PRE_SEND_MESSAGE, + PRE_SEND_STATUS /* server only */, + /* The following three are for hijacked clients only and can only be + registered by the global interceptor */ + PRE_RECV_INITIAL_METADATA, + PRE_RECV_MESSAGE, + PRE_RECV_STATUS, + /* The following two are for all clients and servers */ + POST_RECV_INITIAL_METADATA, + POST_RECV_MESSAGE, + POST_RECV_STATUS /* client only */, + POST_RECV_CLOSE /* server only */, + NUM_INTERCEPTION_HOOKS +}; + +class InterceptorBatchMethods { + public: + virtual ~InterceptorBatchMethods(); + // Queries to check whether the current batch has an interception hook point + // of type \a type + virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0; + // Calling this will signal that the interceptor is done intercepting the + // current batch of the RPC + virtual void Proceed() = 0; + // Calling this indicates that the interceptor has hijacked the RPC (only + // valid if the batch contains send_initial_metadata on the client side) + virtual void Hijack() = 0; +}; +} // namespace experimental +} // namespace grpc + +#endif /* GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H */ diff --git a/include/grpcpp/security/credentials.h b/include/grpcpp/security/credentials.h index bfadc15df5..53f0131c00 100644 --- a/include/grpcpp/security/credentials.h +++ b/include/grpcpp/security/credentials.h @@ -24,6 +24,7 @@ #include <vector> #include <grpc/grpc_security_constants.h> +#include <grpcpp/impl/codegen/client_interceptor.h> #include <grpcpp/impl/codegen/grpc_library.h> #include <grpcpp/security/auth_context.h> #include <grpcpp/support/status.h> @@ -38,6 +39,18 @@ class SecureChannelCredentials; class CallCredentials; class SecureCallCredentials; +class ChannelCredentials; + +namespace experimental { +std::shared_ptr<Channel> CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); +} // namespace experimental + /// A channel credentials object encapsulates all the state needed by a client /// to authenticate with a server for a given channel. /// It can make various assertions, e.g., about the client’s identity, role @@ -62,8 +75,23 @@ class ChannelCredentials : private GrpcLibraryCodegen { const std::shared_ptr<ChannelCredentials>& creds, const ChannelArguments& args); + friend std::shared_ptr<Channel> + experimental::CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); + virtual std::shared_ptr<Channel> CreateChannel( const grpc::string& target, const ChannelArguments& args) = 0; + + virtual std::shared_ptr<Channel> CreateChannelWithInterceptors( + const grpc::string& target, const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) = 0; }; /// A call credentials object encapsulates the state needed by a client to diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index c59059f045..00430d07db 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -50,8 +50,14 @@ namespace grpc { static internal::GrpcLibraryInitializer g_gli_initializer; -Channel::Channel(const grpc::string& host, grpc_channel* channel) +Channel::Channel( + const grpc::string& host, grpc_channel* channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) : host_(host), c_channel_(channel) { + auto vector = interceptor_creators.release(); + interceptor_creators_ = std::move(*vector); g_gli_initializer.summon(); } diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 67a46ce0e1..efdff6c265 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -39,11 +39,43 @@ std::shared_ptr<Channel> CreateCustomChannel( const std::shared_ptr<ChannelCredentials>& creds, const ChannelArguments& args) { GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds. - return creds ? creds->CreateChannel(target, args) - : CreateChannelInternal( - "", grpc_lame_client_channel_create( - nullptr, GRPC_STATUS_INVALID_ARGUMENT, - "Invalid credentials.")); + return creds + ? creds->CreateChannel(target, args) + : CreateChannelInternal("", + grpc_lame_client_channel_create( + nullptr, GRPC_STATUS_INVALID_ARGUMENT, + "Invalid credentials."), + nullptr); } +namespace experimental { +/// Create a new \em custom \a Channel pointing to \a target with \a +/// interceptors being invoked per call. +/// +/// \warning For advanced use and testing ONLY. Override default channel +/// arguments only if necessary. +/// +/// \param target The URI of the endpoint to connect to. +/// \param creds Credentials to use for the created channel. If it does not +/// hold an object or is invalid, a lame channel (one on which all operations +/// fail) is returned. +/// \param args Options for channel creation. +std::shared_ptr<Channel> CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, + const ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + return creds + ? creds->CreateChannelWithInterceptors( + target, args, std::move(interceptor_creators)) + : CreateChannelInternal("", + grpc_lame_client_channel_create( + nullptr, GRPC_STATUS_INVALID_ARGUMENT, + "Invalid credentials."), + nullptr); +} +} // namespace experimental + } // namespace grpc diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc index aa96edfcff..313d682aae 100644 --- a/src/cpp/client/create_channel_internal.cc +++ b/src/cpp/client/create_channel_internal.cc @@ -24,8 +24,12 @@ struct grpc_channel; namespace grpc { -std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host, - grpc_channel* c_channel) { - return std::shared_ptr<Channel>(new Channel(host, c_channel)); +std::shared_ptr<Channel> CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { + return std::shared_ptr<Channel>( + new Channel(host, c_channel, std::move(interceptor_creators))); } } // namespace grpc diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h index 86e8167277..512fc22866 100644 --- a/src/cpp/client/create_channel_internal.h +++ b/src/cpp/client/create_channel_internal.h @@ -21,6 +21,7 @@ #include <memory> +#include <grpcpp/impl/codegen/client_interceptor.h> #include <grpcpp/support/config.h> struct grpc_channel; @@ -28,8 +29,11 @@ struct grpc_channel; namespace grpc { class Channel; -std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host, - grpc_channel* c_channel); +std::shared_ptr<Channel> CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators); } // namespace grpc diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc index f9285c9b28..b9e5887bcc 100644 --- a/src/cpp/client/create_channel_posix.cc +++ b/src/cpp/client/create_channel_posix.cc @@ -33,7 +33,8 @@ std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target, internal::GrpcLibrary init_lib; init_lib.init(); return CreateChannelInternal( - "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr)); + "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr), + nullptr); } std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd( @@ -42,8 +43,10 @@ std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd( init_lib.init(); grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); - return CreateChannelInternal("", grpc_insecure_channel_create_from_fd( - target.c_str(), fd, &channel_args)); + return CreateChannelInternal( + "", + grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args), + nullptr); } #endif // GPR_SUPPORT_CHANNELS_FROM_FD diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc index 5c65ad05ea..09a76b428c 100644 --- a/src/cpp/client/cronet_credentials.cc +++ b/src/cpp/client/cronet_credentials.cc @@ -31,16 +31,25 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials { std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override { - grpc_channel_args channel_args; - args.SetChannelArgs(&channel_args); - return CreateChannelInternal( - "", grpc_cronet_secure_channel_create(engine_, target.c_str(), - &channel_args, nullptr)); + return CreateChannelWithInterceptors(target, args, nullptr); } SecureChannelCredentials* AsSecureCredentials() override { return nullptr; } private: + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override { + grpc_channel_args channel_args; + args.SetChannelArgs(&channel_args); + return CreateChannelInternal( + "", + grpc_cronet_secure_channel_create(engine_, target.c_str(), + &channel_args, nullptr), + std::move(interceptor_creators)); + } void* engine_; }; diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc index 04dc5c0bcc..b816e0c59a 100644 --- a/src/cpp/client/insecure_credentials.cc +++ b/src/cpp/client/insecure_credentials.cc @@ -32,11 +32,20 @@ class InsecureChannelCredentialsImpl final : public ChannelCredentials { public: std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override { + return CreateChannelWithInterceptors(target, args, nullptr); + } + + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( "", - grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)); + grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr), + std::move(interceptor_creators)); } SecureChannelCredentials* AsSecureCredentials() override { return nullptr; } diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index e48fbeb86d..d1cd78e755 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -36,12 +36,22 @@ SecureChannelCredentials::SecureChannelCredentials( std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel( const string& target, const grpc::ChannelArguments& args) { + return CreateChannelWithInterceptors(target, args, nullptr); +} + +std::shared_ptr<grpc::Channel> +SecureChannelCredentials::CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( args.GetSslTargetNameOverride(), grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args, - nullptr)); + nullptr), + std::move(interceptor_creators)); } SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds) diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index 85cb54227c..bfb6e17ee9 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -36,9 +36,15 @@ class SecureChannelCredentials final : public ChannelCredentials { std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) override; + SecureChannelCredentials* AsSecureCredentials() override { return this; } private: + std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors( + const string& target, const grpc::ChannelArguments& args, + std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>> + interceptor_creators) override; grpc_channel_credentials* const c_creds_; }; diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 36f7eb81f9..72371e5384 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -473,7 +473,8 @@ std::shared_ptr<Channel> Server::InProcessChannel( const ChannelArguments& args) { grpc_channel_args channel_args = args.c_channel_args(); return CreateChannelInternal( - "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr)); + "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr), + nullptr); } static grpc_server_register_method_payload_handling PayloadHandlingForMethod( diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc index 9516b2e3e2..389b888084 100644 --- a/test/cpp/microbenchmarks/bm_call_create.cc +++ b/test/cpp/microbenchmarks/bm_call_create.cc @@ -133,8 +133,10 @@ static void BM_LameChannelCallCreateCpp(benchmark::State& state) { TrackCounters track_counters; auto stub = grpc::testing::EchoTestService::NewStub(grpc::CreateChannelInternal( - "", grpc_lame_client_channel_create( - "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah"))); + "", + grpc_lame_client_channel_create("localhost:1234", + GRPC_STATUS_UNAUTHENTICATED, "blah"), + nullptr)); grpc::CompletionQueue cq; grpc::testing::EchoRequest send_request; grpc::testing::EchoResponse recv_response; diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h index d390ae08f6..7188a2a28a 100644 --- a/test/cpp/microbenchmarks/fullstack_fixtures.h +++ b/test/cpp/microbenchmarks/fullstack_fixtures.h @@ -218,7 +218,7 @@ class EndpointPairFixture : public BaseFixture { "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport_); grpc_chttp2_transport_start_reading(client_transport_, nullptr, nullptr); - channel_ = CreateChannelInternal("", channel); + channel_ = CreateChannelInternal("", channel, nullptr); } } diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc index 0ea3181f7e..7b51260e5b 100644 --- a/test/cpp/performance/writes_per_rpc_test.cc +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -118,7 +118,7 @@ class EndpointPairFixture { "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); - channel_ = CreateChannelInternal("", channel); + channel_ = CreateChannelInternal("", channel, nullptr); } } |