Merge pull request #25175 from ZhouyihaiDing/callback_add_context

Support ServerContext for callback API
pull/25221/head
Zhouyihai Ding 4 years ago committed by GitHub
commit 6f6bdd03e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 54
      CMakeLists.txt
  2. 20
      build_autogenerated.yaml
  3. 12
      include/grpcpp/impl/codegen/server_callback_handlers.h
  4. 41
      include/grpcpp/impl/codegen/server_context.h
  5. 2
      include/grpcpp/impl/codegen/server_interface.h
  6. 15
      include/grpcpp/server.h
  7. 6
      include/grpcpp/server_builder.h
  8. 13
      src/cpp/server/server_builder.cc
  9. 43
      src/cpp/server/server_cc.cc
  10. 19
      test/cpp/end2end/BUILD
  11. 356
      test/cpp/end2end/context_allocator_end2end_test.cc
  12. 24
      tools/run_tests/generated/tests.json

@ -813,6 +813,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx codegen_test_minimal)
add_dependencies(buildtests_cxx connection_prefix_bad_client_test)
add_dependencies(buildtests_cxx connectivity_state_test)
add_dependencies(buildtests_cxx context_allocator_end2end_test)
add_dependencies(buildtests_cxx context_list_test)
add_dependencies(buildtests_cxx delegating_channel_test)
add_dependencies(buildtests_cxx destroy_grpclb_channel_with_active_connect_stress_test)
@ -10532,6 +10533,59 @@ target_link_libraries(connectivity_state_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(context_allocator_end2end_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
test/cpp/end2end/context_allocator_end2end_test.cc
test/cpp/end2end/test_service_impl.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(context_allocator_end2end_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(context_allocator_end2end_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr
address_sorting
upb
)
endif()
if(gRPC_BUILD_TESTS)

@ -5786,6 +5786,26 @@ targets:
- gpr
- address_sorting
- upb
- name: context_allocator_end2end_test
gtest: true
build: test
language: c++
headers:
- test/cpp/end2end/test_service_impl.h
src:
- src/proto/grpc/testing/echo.proto
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/simple_messages.proto
- test/cpp/end2end/context_allocator_end2end_test.cc
- test/cpp/end2end/test_service_impl.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr
- address_sorting
- upb
- name: context_list_test
gtest: true
build: test

@ -210,6 +210,9 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
allocator_state_->Release();
if (ctx_->context_allocator() != nullptr) {
ctx_->context_allocator()->Release(ctx_);
}
this->~ServerCallbackUnaryImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
@ -402,6 +405,9 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
if (ctx_->context_allocator() != nullptr) {
ctx_->context_allocator()->Release(ctx_);
}
this->~ServerCallbackReaderImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
@ -628,6 +634,9 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
if (ctx_->context_allocator() != nullptr) {
ctx_->context_allocator()->Release(ctx_);
}
this->~ServerCallbackWriterImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
@ -839,6 +848,9 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
if (ctx_->context_allocator() != nullptr) {
ctx_->context_allocator()->Release(ctx_);
}
this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();

@ -100,6 +100,7 @@ class CompletionQueue;
class GenericServerContext;
class Server;
class ServerInterface;
class ContextAllocator;
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
@ -340,6 +341,12 @@ class ServerContextBase {
ServerContextBase();
ServerContextBase(gpr_timespec deadline, grpc_metadata_array* arr);
void set_context_allocator(ContextAllocator* context_allocator) {
context_allocator_ = context_allocator;
}
ContextAllocator* context_allocator() const { return context_allocator_; }
private:
friend class ::grpc::testing::InteropServerContextInspector;
friend class ::grpc::testing::ServerContextTestSpouse;
@ -463,6 +470,7 @@ class ServerContextBase {
::grpc::experimental::ServerRpcInfo* rpc_info_ = nullptr;
::grpc::experimental::RpcAllocatorState* message_allocator_state_ = nullptr;
ContextAllocator* context_allocator_ = nullptr;
class Reactor : public ::grpc::ServerUnaryReactor {
public:
@ -590,12 +598,14 @@ class CallbackServerContext : public ServerContextBase {
using ServerContextBase::compression_algorithm;
using ServerContextBase::compression_level;
using ServerContextBase::compression_level_set;
using ServerContextBase::context_allocator;
using ServerContextBase::deadline;
using ServerContextBase::IsCancelled;
using ServerContextBase::peer;
using ServerContextBase::raw_deadline;
using ServerContextBase::set_compression_algorithm;
using ServerContextBase::set_compression_level;
using ServerContextBase::set_context_allocator;
using ServerContextBase::SetLoadReportingCosts;
using ServerContextBase::TryCancel;
@ -612,6 +622,37 @@ class CallbackServerContext : public ServerContextBase {
CallbackServerContext& operator=(const CallbackServerContext&) = delete;
};
/// A CallbackServerContext allows users to use the contents of the
/// CallbackServerContext or GenericCallbackServerContext structure for the
/// callback API.
/// The library will invoke the allocator any time a new call is initiated.
/// and call the Release method after the server OnDone.
class ContextAllocator {
public:
virtual ~ContextAllocator() {}
virtual CallbackServerContext* NewCallbackServerContext() { return nullptr; }
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
virtual experimental::GenericCallbackServerContext*
NewGenericCallbackServerContext() {
return nullptr;
}
#else
virtual GenericCallbackServerContext* NewGenericCallbackServerContext() {
return nullptr;
}
#endif
virtual void Release(CallbackServerContext*) {}
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
virtual void Release(experimental::GenericCallbackServerContext*) {}
#else
virtual void Release(GenericCallbackServerContext*) {}
#endif
};
} // namespace grpc
static_assert(

@ -147,6 +147,8 @@ class ServerInterface : public internal::CallHook {
/// May not be abstract since this is a post-1.0 API addition
virtual void RegisterCallbackGenericService(
experimental::CallbackGenericService* /*service*/) {}
virtual void RegisterContextAllocator(
std::unique_ptr<ContextAllocator> context_allocator) {}
};
/// NOTE: The function experimental_registration() is not stable public API.

@ -203,6 +203,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
health_check_service_ = std::move(service);
}
ContextAllocator* context_allocator() { return context_allocator_.get(); }
/// NOTE: This method is not part of the public API for this class.
bool health_check_service_disabled() const {
return health_check_service_disabled_;
@ -240,6 +242,12 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// ownership of theservice. The service must exist for the lifetime of the
/// Server instance.
void RegisterCallbackGenericService(CallbackGenericService* service) override;
void RegisterContextAllocator(
std::unique_ptr<ContextAllocator> context_allocator) {
context_allocator_ = std::move(context_allocator);
}
#else
/// NOTE: class experimental_registration_type is not part of the public API
/// of this class
@ -254,6 +262,11 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
server_->RegisterCallbackGenericService(service);
}
void RegisterContextAllocator(
std::unique_ptr<ContextAllocator> context_allocator) override {
server_->context_allocator_ = std::move(context_allocator);
}
private:
Server* server_;
};
@ -342,6 +355,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
std::unique_ptr<ServerInitializer> server_initializer_;
std::unique_ptr<ContextAllocator> context_allocator_;
std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
bool health_check_service_disabled_;

@ -269,6 +269,11 @@ class ServerBuilder {
builder_->interceptor_creators_ = std::move(interceptor_creators);
}
/// Set the allocator for creating and releasing callback server context.
/// Takes the owndership of the allocator.
ServerBuilder& SetContextAllocator(
std::unique_ptr<grpc::ContextAllocator> context_allocator);
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a generic service that uses the callback API.
/// Matches requests with any :authority
@ -389,6 +394,7 @@ class ServerBuilder {
std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>> plugins_;
grpc_resource_quota* resource_quota_;
grpc::AsyncGenericService* generic_service_{nullptr};
std::unique_ptr<ContextAllocator> context_allocator_;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
grpc::CallbackGenericService* callback_generic_service_{nullptr};
#else

@ -130,6 +130,12 @@ ServerBuilder& ServerBuilder::experimental_type::RegisterCallbackGenericService(
}
#endif
ServerBuilder& ServerBuilder::experimental_type::SetContextAllocator(
std::unique_ptr<grpc::ContextAllocator> context_allocator) {
builder_->context_allocator_ = std::move(context_allocator);
return *builder_;
}
std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
ServerBuilder::experimental_type::AddExternalConnectionAcceptor(
experimental_type::ExternalConnectionType type,
@ -369,6 +375,13 @@ std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
return nullptr;
}
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
server->RegisterContextAllocator(std::move(context_allocator_));
#else
server->experimental_registration()->RegisterContextAllocator(
std::move(context_allocator_));
#endif
for (const auto& value : services_) {
if (!server->RegisterService(value->host.get(), value->service)) {
return nullptr;

@ -552,7 +552,10 @@ class Server::CallbackRequest final
method->method_type() ==
grpc::internal::RpcMethod::SERVER_STREAMING),
cq_(cq),
tag_(this) {
tag_(this),
ctx_(server_->context_allocator() != nullptr
? server_->context_allocator()->NewCallbackServerContext()
: nullptr) {
CommonSetup(server, data);
data->deadline = &deadline_;
data->optional_payload = has_request_payload_ ? &request_payload_ : nullptr;
@ -567,7 +570,11 @@ class Server::CallbackRequest final
has_request_payload_(false),
call_details_(new grpc_call_details),
cq_(cq),
tag_(this) {
tag_(this),
ctx_(server_->context_allocator() != nullptr
? server_->context_allocator()
->NewGenericCallbackServerContext()
: nullptr) {
CommonSetup(server, data);
grpc_call_details_init(call_details_);
data->details = call_details_;
@ -579,6 +586,9 @@ class Server::CallbackRequest final
if (has_request_payload_ && request_payload_) {
grpc_byte_buffer_destroy(request_payload_);
}
if (server_->context_allocator() == nullptr || ctx_alloc_by_default_) {
delete ctx_;
}
server_->UnrefWithPossibleNotify();
}
@ -631,10 +641,10 @@ class Server::CallbackRequest final
}
// Bind the call, deadline, and metadata from what we got
req_->ctx_.set_call(req_->call_);
req_->ctx_.cq_ = req_->cq_;
req_->ctx_.BindDeadlineAndMetadata(req_->deadline_,
&req_->request_metadata_);
req_->ctx_->set_call(req_->call_);
req_->ctx_->cq_ = req_->cq_;
req_->ctx_->BindDeadlineAndMetadata(req_->deadline_,
&req_->request_metadata_);
req_->request_metadata_.count = 0;
// Create a C++ Call to control the underlying core call
@ -643,7 +653,7 @@ class Server::CallbackRequest final
grpc::internal::Call(
req_->call_, req_->server_, req_->cq_,
req_->server_->max_receive_message_size(),
req_->ctx_.set_server_rpc_info(
req_->ctx_->set_server_rpc_info(
req_->method_name(),
(req_->method_ != nullptr)
? req_->method_->method_type()
@ -657,7 +667,7 @@ class Server::CallbackRequest final
grpc::experimental::InterceptionHookPoints::
POST_RECV_INITIAL_METADATA);
req_->interceptor_methods_.SetRecvInitialMetadata(
&req_->ctx_.client_metadata_);
&req_->ctx_->client_metadata_);
if (req_->has_request_payload_) {
// Set interception point for RECV MESSAGE
@ -683,7 +693,7 @@ class Server::CallbackRequest final
? req_->method_->handler()
: req_->server_->generic_handler_.get();
handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
call_, &req_->ctx_, req_->request_, req_->request_status_,
call_, req_->ctx_, req_->request_, req_->request_status_,
req_->handler_data_, [this] { delete req_; }));
}
};
@ -695,6 +705,12 @@ class Server::CallbackRequest final
data->tag = &tag_;
data->call = &call_;
data->initial_metadata = &request_metadata_;
if (ctx_ == nullptr) {
// TODO(ddyihai): allocate the context with grpc_call_arena_alloc.
ctx_ = new ServerContextType();
ctx_alloc_by_default_ = true;
}
ctx_->set_context_allocator(server->context_allocator());
}
Server* const server_;
@ -709,8 +725,9 @@ class Server::CallbackRequest final
gpr_timespec deadline_;
grpc_metadata_array request_metadata_;
grpc::CompletionQueue* const cq_;
bool ctx_alloc_by_default_ = false;
CallbackCallTag tag_;
ServerContextType ctx_;
ServerContextType* ctx_ = nullptr;
grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
@ -727,8 +744,8 @@ bool Server::CallbackRequest<
if (*status) {
deadline_ = call_details_->deadline;
// TODO(yangg) remove the copy here
ctx_.method_ = grpc::StringFromCopiedSlice(call_details_->method);
ctx_.host_ = grpc::StringFromCopiedSlice(call_details_->host);
ctx_->method_ = grpc::StringFromCopiedSlice(call_details_->method);
ctx_->host_ = grpc::StringFromCopiedSlice(call_details_->host);
}
grpc_slice_unref(call_details_->method);
grpc_slice_unref(call_details_->host);
@ -744,7 +761,7 @@ const char* Server::CallbackRequest<grpc::CallbackServerContext>::method_name()
template <>
const char* Server::CallbackRequest<
grpc::GenericCallbackServerContext>::method_name() const {
return ctx_.method().c_str();
return ctx_->method().c_str();
}
// Implementation of ThreadManager. Each instance of SyncRequestThreadManager

@ -803,6 +803,25 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "context_allocator_end2end_test",
srcs = ["context_allocator_end2end_test.cc"],
external_deps = [
"gtest",
],
deps = [
":test_service_impl",
"//:gpr",
"//:grpc",
"//:grpc++",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//src/proto/grpc/testing:simple_messages_proto",
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
)
grpc_cc_test(
name = "port_sharing_end2end_test",
srcs = ["port_sharing_end2end_test.cc"],

@ -0,0 +1,356 @@
/*
*
* Copyright 2020 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.
*
*/
#include <grpc/impl/codegen/log.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <grpcpp/support/client_callback.h>
#include <grpcpp/support/message_allocator.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <sstream>
#include <thread>
#include "src/core/lib/iomgr/iomgr.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
#include "test/cpp/util/test_credentials_provider.h"
// MAYBE_SKIP_TEST is a macro to determine if this particular test configuration
// should be skipped based on a decision made at SetUp time. In particular, any
// callback tests can only be run if the iomgr can run in the background or if
// the transport is in-process.
#define MAYBE_SKIP_TEST \
do { \
if (do_not_test_) { \
return; \
} \
} while (0)
namespace grpc {
namespace testing {
namespace {
enum class Protocol { INPROC, TCP };
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
using experimental::GenericCallbackServerContext;
#endif
class TestScenario {
public:
TestScenario(Protocol protocol, const std::string& creds_type)
: protocol(protocol), credentials_type(creds_type) {}
void Log() const;
Protocol protocol;
const std::string credentials_type;
};
static std::ostream& operator<<(std::ostream& out,
const TestScenario& scenario) {
return out << "TestScenario{protocol="
<< (scenario.protocol == Protocol::INPROC ? "INPROC" : "TCP")
<< "," << scenario.credentials_type << "}";
}
void TestScenario::Log() const {
std::ostringstream out;
out << *this;
gpr_log(GPR_INFO, "%s", out.str().c_str());
}
class ContextAllocatorEnd2endTestBase
: public ::testing::TestWithParam<TestScenario> {
protected:
static void SetUpTestCase() { grpc_init(); }
static void TearDownTestCase() { grpc_shutdown(); }
ContextAllocatorEnd2endTestBase() {}
~ContextAllocatorEnd2endTestBase() override = default;
void SetUp() override {
GetParam().Log();
if (GetParam().protocol == Protocol::TCP) {
if (!grpc_iomgr_run_in_background()) {
do_not_test_ = true;
return;
}
}
}
void CreateServer(std::unique_ptr<grpc::ContextAllocator> context_allocator) {
ServerBuilder builder;
auto server_creds = GetCredentialsProvider()->GetServerCredentials(
GetParam().credentials_type);
if (GetParam().protocol == Protocol::TCP) {
picked_port_ = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << picked_port_;
builder.AddListeningPort(server_address_.str(), server_creds);
}
builder.experimental().SetContextAllocator(std::move(context_allocator));
builder.RegisterService(&callback_service_);
server_ = builder.BuildAndStart();
}
void DestroyServer() {
if (server_) {
server_->Shutdown();
server_.reset();
}
}
void ResetStub() {
ChannelArguments args;
auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
GetParam().credentials_type, &args);
switch (GetParam().protocol) {
case Protocol::TCP:
channel_ = ::grpc::CreateCustomChannel(server_address_.str(),
channel_creds, args);
break;
case Protocol::INPROC:
channel_ = server_->InProcessChannel(args);
break;
default:
assert(false);
}
stub_ = EchoTestService::NewStub(channel_);
}
void TearDown() override {
DestroyServer();
if (picked_port_ > 0) {
grpc_recycle_unused_port(picked_port_);
}
}
void SendRpcs(int num_rpcs) {
std::string test_string("");
for (int i = 0; i < num_rpcs; i++) {
EchoRequest request;
EchoResponse response;
ClientContext cli_ctx;
test_string += std::string(1024, 'x');
request.set_message(test_string);
std::string val;
cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
std::mutex mu;
std::condition_variable cv;
bool done = false;
stub_->experimental_async()->Echo(
&cli_ctx, &request, &response,
[&request, &response, &done, &mu, &cv, val](Status s) {
GPR_ASSERT(s.ok());
EXPECT_EQ(request.message(), response.message());
std::lock_guard<std::mutex> l(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> l(mu);
while (!done) {
cv.wait(l);
}
}
}
bool do_not_test_{false};
int picked_port_{0};
std::shared_ptr<Channel> channel_;
std::unique_ptr<EchoTestService::Stub> stub_;
CallbackTestServiceImpl callback_service_;
std::unique_ptr<Server> server_;
std::ostringstream server_address_;
};
class DefaultContextAllocatorTest : public ContextAllocatorEnd2endTestBase {};
TEST_P(DefaultContextAllocatorTest, SimpleRpc) {
MAYBE_SKIP_TEST;
const int kRpcCount = 10;
CreateServer(nullptr);
ResetStub();
SendRpcs(kRpcCount);
}
class NullContextAllocatorTest : public ContextAllocatorEnd2endTestBase {
public:
class NullAllocator : public grpc::ContextAllocator {
public:
NullAllocator(std::atomic<int>* allocation_count,
std::atomic<int>* deallocation_count)
: allocation_count_(allocation_count),
deallocation_count_(deallocation_count) {}
grpc::CallbackServerContext* NewCallbackServerContext() override {
allocation_count_->fetch_add(1, std::memory_order_relaxed);
return nullptr;
}
GenericCallbackServerContext* NewGenericCallbackServerContext() override {
allocation_count_->fetch_add(1, std::memory_order_relaxed);
return nullptr;
}
void Release(
grpc::CallbackServerContext* callback_server_context) override {
deallocation_count_->fetch_add(1, std::memory_order_relaxed);
}
void Release(GenericCallbackServerContext* generic_callback_server_context)
override {
deallocation_count_->fetch_add(1, std::memory_order_relaxed);
}
std::atomic<int>* allocation_count_;
std::atomic<int>* deallocation_count_;
};
};
TEST_P(NullContextAllocatorTest, UnaryRpc) {
MAYBE_SKIP_TEST;
const int kRpcCount = 10;
std::atomic<int> allocation_count{0};
std::atomic<int> deallocation_count{0};
std::unique_ptr<NullAllocator> allocator(
new NullAllocator(&allocation_count, &deallocation_count));
CreateServer(std::move(allocator));
ResetStub();
SendRpcs(kRpcCount);
// messages_deallocaton_count is updated in Release after server side
// OnDone.
DestroyServer();
EXPECT_EQ(kRpcCount, allocation_count);
EXPECT_EQ(kRpcCount, deallocation_count);
}
class SimpleContextAllocatorTest : public ContextAllocatorEnd2endTestBase {
public:
class SimpleAllocator : public grpc::ContextAllocator {
public:
SimpleAllocator(std::atomic<int>* allocation_count,
std::atomic<int>* deallocation_count)
: allocation_count_(allocation_count),
deallocation_count_(deallocation_count) {}
grpc::CallbackServerContext* NewCallbackServerContext() override {
allocation_count_->fetch_add(1, std::memory_order_relaxed);
return new grpc::CallbackServerContext();
}
GenericCallbackServerContext* NewGenericCallbackServerContext() override {
allocation_count_->fetch_add(1, std::memory_order_relaxed);
return new GenericCallbackServerContext();
}
void Release(
grpc::CallbackServerContext* callback_server_context) override {
deallocation_count_->fetch_add(1, std::memory_order_relaxed);
delete callback_server_context;
}
void Release(GenericCallbackServerContext* generic_callback_server_context)
override {
deallocation_count_->fetch_add(1, std::memory_order_relaxed);
delete generic_callback_server_context;
}
std::atomic<int>* allocation_count_;
std::atomic<int>* deallocation_count_;
};
};
TEST_P(SimpleContextAllocatorTest, UnaryRpc) {
MAYBE_SKIP_TEST;
const int kRpcCount = 10;
std::atomic<int> allocation_count{0};
std::atomic<int> deallocation_count{0};
std::unique_ptr<SimpleAllocator> allocator(
new SimpleAllocator(&allocation_count, &deallocation_count));
CreateServer(std::move(allocator));
ResetStub();
SendRpcs(kRpcCount);
// messages_deallocaton_count is updated in Release after server side
// OnDone.
DestroyServer();
EXPECT_EQ(kRpcCount, allocation_count);
EXPECT_EQ(kRpcCount, deallocation_count);
}
std::vector<TestScenario> CreateTestScenarios(bool test_insecure) {
std::vector<TestScenario> scenarios;
std::vector<std::string> credentials_types{
GetCredentialsProvider()->GetSecureCredentialsTypeList()};
auto insec_ok = [] {
// Only allow insecure credentials type when it is registered with the
// provider. User may create providers that do not have insecure.
return GetCredentialsProvider()->GetChannelCredentials(
kInsecureCredentialsType, nullptr) != nullptr;
};
if (test_insecure && insec_ok()) {
credentials_types.push_back(kInsecureCredentialsType);
}
GPR_ASSERT(!credentials_types.empty());
Protocol parr[]{Protocol::INPROC, Protocol::TCP};
for (Protocol p : parr) {
for (const auto& cred : credentials_types) {
if (p == Protocol::INPROC &&
(cred != kInsecureCredentialsType || !insec_ok())) {
continue;
}
scenarios.emplace_back(p, cred);
}
}
return scenarios;
}
// TODO(ddyihai): adding client streaming/server streaming/bidi streaming
// test.
INSTANTIATE_TEST_SUITE_P(DefaultContextAllocatorTest,
DefaultContextAllocatorTest,
::testing::ValuesIn(CreateTestScenarios(true)));
INSTANTIATE_TEST_SUITE_P(NullContextAllocatorTest, NullContextAllocatorTest,
::testing::ValuesIn(CreateTestScenarios(true)));
INSTANTIATE_TEST_SUITE_P(SimpleContextAllocatorTest, SimpleContextAllocatorTest,
::testing::ValuesIn(CreateTestScenarios(true)));
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}

@ -4239,6 +4239,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "context_allocator_end2end_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save