diff options
Diffstat (limited to 'test/cpp')
-rw-r--r-- | test/cpp/common/alarm_cpp_test.cc (renamed from test/cpp/common/alarm_test.cc) | 29 | ||||
-rw-r--r-- | test/cpp/common/channel_arguments_test.cc | 191 | ||||
-rw-r--r-- | test/cpp/end2end/async_end2end_test.cc | 44 | ||||
-rw-r--r-- | test/cpp/end2end/end2end_test.cc | 90 | ||||
-rw-r--r-- | test/cpp/qps/client.h | 63 | ||||
-rw-r--r-- | test/cpp/qps/client_async.cc | 469 | ||||
-rw-r--r-- | test/cpp/qps/client_sync.cc | 7 | ||||
-rw-r--r-- | test/cpp/qps/driver.cc | 4 | ||||
-rw-r--r-- | test/cpp/qps/interarrival.h | 41 | ||||
-rwxr-xr-x | test/cpp/qps/qps-sweep.sh | 59 | ||||
-rw-r--r-- | test/cpp/qps/qps_interarrival_test.cc | 10 | ||||
-rw-r--r-- | test/cpp/qps/qps_openloop_test.cc | 2 | ||||
-rw-r--r-- | test/cpp/qps/qps_test.cc | 2 | ||||
-rw-r--r-- | test/cpp/qps/server_async.cc | 3 | ||||
-rw-r--r-- | test/cpp/util/test_credentials_provider.cc | 82 | ||||
-rw-r--r-- | test/cpp/util/test_credentials_provider.h | 63 |
16 files changed, 665 insertions, 494 deletions
diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_cpp_test.cc index 09df6852a5..4745ef14ec 100644 --- a/test/cpp/common/alarm_test.cc +++ b/test/cpp/common/alarm_cpp_test.cc @@ -35,58 +35,47 @@ #include <grpc++/completion_queue.h> #include <gtest/gtest.h> -#include <grpc++/completion_queue.h> #include "test/core/util/test_config.h" namespace grpc { namespace { -class TestTag : public CompletionQueueTag { - public: - TestTag() : tag_(0) {} - TestTag(intptr_t tag) : tag_(tag) {} - bool FinalizeResult(void** tag, bool* status) { return true; } - intptr_t tag() { return tag_; } - - private: - intptr_t tag_; -}; - TEST(AlarmTest, RegularExpiry) { CompletionQueue cq; - TestTag input_tag(1618033); - Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), &input_tag); + void* junk = reinterpret_cast<void*>(1618033); + Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), junk); - TestTag* output_tag; + void* output_tag; bool ok; const CompletionQueue::NextStatus status = cq.AsyncNext( (void**)&output_tag, &ok, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); - EXPECT_EQ(output_tag->tag(), input_tag.tag()); + EXPECT_EQ(junk, output_tag); } TEST(AlarmTest, Cancellation) { CompletionQueue cq; - TestTag input_tag(1618033); - Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2), &input_tag); + void* junk = reinterpret_cast<void*>(1618033); + Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2), junk); alarm.Cancel(); - TestTag* output_tag; + void* output_tag; bool ok; const CompletionQueue::NextStatus status = cq.AsyncNext( (void**)&output_tag, &ok, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_FALSE(ok); - EXPECT_EQ(output_tag->tag(), input_tag.tag()); + EXPECT_EQ(junk, output_tag); } } // namespace } // namespace grpc int main(int argc, char** argv) { + grpc_test_init(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/test/cpp/common/channel_arguments_test.cc b/test/cpp/common/channel_arguments_test.cc index e010d375cf..a4821b4d0b 100644 --- a/test/cpp/common/channel_arguments_test.cc +++ b/test/cpp/common/channel_arguments_test.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,94 +41,141 @@ namespace testing { class ChannelArgumentsTest : public ::testing::Test { protected: + ChannelArgumentsTest() + : pointer_vtable_({&ChannelArguments::PointerVtableMembers::Copy, + &ChannelArguments::PointerVtableMembers::Destroy, + &ChannelArguments::PointerVtableMembers::Compare}) {} + void SetChannelArgs(const ChannelArguments& channel_args, grpc_channel_args* args) { channel_args.SetChannelArgs(args); } + + grpc::string GetDefaultUserAgentPrefix() { + std::ostringstream user_agent_prefix; + user_agent_prefix << "grpc-c++/" << grpc_version_string(); + return user_agent_prefix.str(); + } + + void VerifyDefaultChannelArgs() { + grpc_channel_args args; + SetChannelArgs(channel_args_, &args); + EXPECT_EQ(static_cast<size_t>(1), args.num_args); + EXPECT_STREQ(GRPC_ARG_PRIMARY_USER_AGENT_STRING, args.args[0].key); + EXPECT_EQ(GetDefaultUserAgentPrefix(), + grpc::string(args.args[0].value.string)); + } + + bool HasArg(grpc_arg expected_arg) { + grpc_channel_args args; + SetChannelArgs(channel_args_, &args); + for (size_t i = 0; i < args.num_args; i++) { + const grpc_arg& arg = args.args[i]; + if (arg.type == expected_arg.type && + grpc::string(arg.key) == expected_arg.key) { + if (arg.type == GRPC_ARG_INTEGER) { + return arg.value.integer == expected_arg.value.integer; + } else if (arg.type == GRPC_ARG_STRING) { + return grpc::string(arg.value.string) == expected_arg.value.string; + } else if (arg.type == GRPC_ARG_POINTER) { + return arg.value.pointer.p == expected_arg.value.pointer.p && + arg.value.pointer.vtable->copy == + expected_arg.value.pointer.vtable->copy && + arg.value.pointer.vtable->destroy == + expected_arg.value.pointer.vtable->destroy; + } + } + } + return false; + } + grpc_arg_pointer_vtable pointer_vtable_; + ChannelArguments channel_args_; }; TEST_F(ChannelArgumentsTest, SetInt) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(0), args.num_args); - - grpc::string key("key0"); - channel_args.SetInt(key, 0); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_INTEGER; + arg0.key = const_cast<char*>(key0.c_str()); + arg0.value.integer = 0; + grpc::string key1("key1"); + grpc_arg arg1; + arg1.type = GRPC_ARG_INTEGER; + arg1.key = const_cast<char*>(key1.c_str()); + arg1.value.integer = 1; + + grpc::string arg_key0(key0); + channel_args_.SetInt(arg_key0, arg0.value.integer); // Clear key early to make sure channel_args takes a copy - key = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(1), args.num_args); - EXPECT_EQ(GRPC_ARG_INTEGER, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_EQ(0, args.args[0].value.integer); - - key = "key1"; - channel_args.SetInt(key, 1); - key = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(2), args.num_args); - // We do not enforce order on the arguments. - for (size_t i = 0; i < args.num_args; i++) { - EXPECT_EQ(GRPC_ARG_INTEGER, args.args[i].type); - if (grpc::string(args.args[i].key) == "key0") { - EXPECT_EQ(0, args.args[i].value.integer); - } else if (grpc::string(args.args[i].key) == "key1") { - EXPECT_EQ(1, args.args[i].value.integer); - } - } + arg_key0.clear(); + EXPECT_TRUE(HasArg(arg0)); + + grpc::string arg_key1(key1); + channel_args_.SetInt(arg_key1, arg1.value.integer); + arg_key1.clear(); + EXPECT_TRUE(HasArg(arg0)); + EXPECT_TRUE(HasArg(arg1)); } TEST_F(ChannelArgumentsTest, SetString) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(0), args.num_args); - - grpc::string key("key0"); - grpc::string val("val0"); - channel_args.SetString(key, val); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc::string val0("val0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_STRING; + arg0.key = const_cast<char*>(key0.c_str()); + arg0.value.string = const_cast<char*>(val0.c_str()); + grpc::string key1("key1"); + grpc::string val1("val1"); + grpc_arg arg1; + arg1.type = GRPC_ARG_STRING; + arg1.key = const_cast<char*>(key1.c_str()); + arg1.value.string = const_cast<char*>(val1.c_str()); + + grpc::string key(key0); + grpc::string val(val0); + channel_args_.SetString(key, val); // Clear key/val early to make sure channel_args takes a copy key = ""; val = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(1), args.num_args); - EXPECT_EQ(GRPC_ARG_STRING, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_STREQ("val0", args.args[0].value.string); - - key = "key1"; - val = "val1"; - channel_args.SetString(key, val); - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(2), args.num_args); - // We do not enforce order on the arguments. - for (size_t i = 0; i < args.num_args; i++) { - EXPECT_EQ(GRPC_ARG_STRING, args.args[i].type); - if (grpc::string(args.args[i].key) == "key0") { - EXPECT_STREQ("val0", args.args[i].value.string); - } else if (grpc::string(args.args[i].key) == "key1") { - EXPECT_STREQ("val1", args.args[i].value.string); - } - } + EXPECT_TRUE(HasArg(arg0)); + + key = key1; + val = val1; + channel_args_.SetString(key, val); + // Clear key/val early to make sure channel_args takes a copy + key = ""; + val = ""; + EXPECT_TRUE(HasArg(arg0)); + EXPECT_TRUE(HasArg(arg1)); } TEST_F(ChannelArgumentsTest, SetPointer) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(0), args.num_args); - - grpc::string key("key0"); - channel_args.SetPointer(key, &key); - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast<size_t>(1), args.num_args); - EXPECT_EQ(GRPC_ARG_POINTER, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_EQ(&key, args.args[0].value.pointer.p); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_POINTER; + arg0.key = const_cast<char*>(key0.c_str()); + arg0.value.pointer.p = &key0; + arg0.value.pointer.vtable = &pointer_vtable_; + + grpc::string key(key0); + channel_args_.SetPointer(key, arg0.value.pointer.p); + EXPECT_TRUE(HasArg(arg0)); +} + +TEST_F(ChannelArgumentsTest, SetUserAgentPrefix) { + VerifyDefaultChannelArgs(); + grpc::string prefix("prefix"); + grpc::string whole_prefix = prefix + " " + GetDefaultUserAgentPrefix(); + grpc_arg arg0; + arg0.type = GRPC_ARG_STRING; + arg0.key = const_cast<char*>(GRPC_ARG_PRIMARY_USER_AGENT_STRING); + arg0.value.string = const_cast<char*>(whole_prefix.c_str()); + + channel_args_.SetUserAgentPrefix(prefix); + EXPECT_TRUE(HasArg(arg0)); } } // namespace testing diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 252bda3798..a15cbd7ee2 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -43,6 +43,7 @@ #include <grpc/grpc.h> #include <grpc/support/thd.h> #include <grpc/support/time.h> +#include <grpc/support/tls.h> #include <gtest/gtest.h> #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" @@ -59,6 +60,8 @@ using grpc::testing::EchoRequest; using grpc::testing::EchoResponse; using std::chrono::system_clock; +GPR_TLS_DECL(g_is_async_end2end_test); + namespace grpc { namespace testing { @@ -67,9 +70,11 @@ namespace { void* tag(int i) { return (void*)(intptr_t)i; } #ifdef GPR_POSIX_SOCKET -static int assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds, - int timeout) { - GPR_ASSERT(timeout == 0); +static int maybe_assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds, + int timeout) { + if (gpr_tls_get(&g_is_async_end2end_test)) { + GPR_ASSERT(timeout == 0); + } return poll(pfds, nfds, timeout); } @@ -86,21 +91,21 @@ class PollOverride { grpc_poll_function_type prev_; }; -class PollingCheckRegion : public PollOverride { +class PollingOverrider : public PollOverride { public: - explicit PollingCheckRegion(bool allow_blocking) - : PollOverride(allow_blocking ? poll : assert_non_blocking_poll) {} + explicit PollingOverrider(bool allow_blocking) + : PollOverride(allow_blocking ? poll : maybe_assert_non_blocking_poll) {} }; #else -class PollingCheckRegion { +class PollingOverrider { public: - explicit PollingCheckRegion(bool allow_blocking) {} + explicit PollingOverrider(bool allow_blocking) {} }; #endif -class Verifier : public PollingCheckRegion { +class Verifier { public: - explicit Verifier(bool spin) : PollingCheckRegion(!spin), spin_(spin) {} + explicit Verifier(bool spin) : spin_(spin) {} Verifier& Expect(int i, bool expect_ok) { expectations_[tag(i)] = expect_ok; return *this; @@ -183,6 +188,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> { AsyncEnd2endTest() {} void SetUp() GRPC_OVERRIDE { + poll_overrider_.reset(new PollingOverrider(!GetParam())); + int port = grpc_pick_unused_port_or_die(); server_address_ << "localhost:" << port; @@ -193,6 +200,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> { builder.RegisterService(&service_); cq_ = builder.AddCompletionQueue(); server_ = builder.BuildAndStart(); + + gpr_tls_set(&g_is_async_end2end_test, 1); } void TearDown() GRPC_OVERRIDE { @@ -202,6 +211,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> { cq_->Shutdown(); while (cq_->Next(&ignored_tag, &ignored_ok)) ; + poll_overrider_.reset(); + gpr_tls_set(&g_is_async_end2end_test, 0); } void ResetStub() { @@ -249,6 +260,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> { std::unique_ptr<Server> server_; grpc::testing::EchoTestService::AsyncService service_; std::ostringstream server_address_; + + std::unique_ptr<PollingOverrider> poll_overrider_; }; TEST_P(AsyncEnd2endTest, SimpleRpc) { @@ -479,8 +492,10 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { send_request.set_message("Hello"); std::pair<grpc::string, grpc::string> meta1("key1", "val1"); std::pair<grpc::string, grpc::string> meta2("key2", "val2"); + std::pair<grpc::string, grpc::string> meta3("g.r.d-bin", "xyz"); cli_ctx.AddMetadata(meta1.first, meta1.second); cli_ctx.AddMetadata(meta2.first, meta2.second); + cli_ctx.AddMetadata(meta3.first, meta3.second); std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); @@ -494,6 +509,8 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { ToString(client_initial_metadata.find(meta1.first)->second)); EXPECT_EQ(meta2.second, ToString(client_initial_metadata.find(meta2.first)->second)); + EXPECT_EQ(meta3.second, + ToString(client_initial_metadata.find(meta3.first)->second)); EXPECT_GE(client_initial_metadata.size(), static_cast<size_t>(2)); send_response.set_message(recv_request.message()); @@ -1083,7 +1100,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { Verifier(GetParam()).Expect(7, true).Verify(cq_.get()); // This is expected to fail in all cases i.e for all values of - // server_try_cancel. This is becasue at this point, either there are no + // server_try_cancel. This is because at this point, either there are no // more msgs from the client (because client called WritesDone) or the RPC // is cancelled on the server srv_stream.Read(&recv_request, tag(8)); @@ -1160,6 +1177,9 @@ INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel, int main(int argc, char** argv) { grpc_test_init(argc, argv); + gpr_tls_init(&g_is_async_end2end_test); ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + int ret = RUN_ALL_TESTS(); + gpr_tls_destroy(&g_is_async_end2end_test); + return ret; } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 65da71b391..ce8e4d2a10 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -51,11 +51,11 @@ #include "src/core/security/credentials.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" -#include "test/core/end2end/data/ssl_test_data.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/string_ref_helper.h" +#include "test/cpp/util/test_credentials_provider.h" using grpc::testing::EchoRequest; using grpc::testing::EchoResponse; @@ -191,12 +191,14 @@ class TestServiceImplDupPkg class TestScenario { public: - TestScenario(bool proxy, bool tls) : use_proxy(proxy), use_tls(tls) {} + TestScenario(bool proxy, const grpc::string& creds_type) + : use_proxy(proxy), credentials_type(creds_type) {} void Log() const { - gpr_log(GPR_INFO, "Scenario: proxy %d, tls %d", use_proxy, use_tls); + gpr_log(GPR_INFO, "Scenario: proxy %d, credentials %s", use_proxy, + credentials_type.c_str()); } bool use_proxy; - bool use_tls; + const grpc::string credentials_type; }; class End2endTest : public ::testing::TestWithParam<TestScenario> { @@ -220,14 +222,8 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> { server_address_ << "127.0.0.1:" << port; // Setup server ServerBuilder builder; - auto server_creds = InsecureServerCredentials(); - if (GetParam().use_tls) { - SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, - test_server1_cert}; - SslServerCredentialsOptions ssl_opts; - ssl_opts.pem_root_certs = ""; - ssl_opts.pem_key_cert_pairs.push_back(pkcp); - server_creds = SslServerCredentials(ssl_opts); + auto server_creds = GetServerCredentials(GetParam().credentials_type); + if (GetParam().credentials_type != kInsecureCredentialsType) { server_creds->SetAuthMetadataProcessor(processor); } builder.AddListeningPort(server_address_.str(), server_creds); @@ -246,11 +242,10 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> { } EXPECT_TRUE(is_server_started_); ChannelArguments args; - auto channel_creds = InsecureChannelCredentials(); - if (GetParam().use_tls) { - SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; - args.SetSslTargetNameOverride("foo.test.google.fr"); - channel_creds = SslCredentials(ssl_opts); + auto channel_creds = + GetChannelCredentials(GetParam().credentials_type, &args); + if (!user_agent_prefix_.empty()) { + args.SetUserAgentPrefix(user_agent_prefix_); } args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test"); channel_ = CreateCustomChannel(server_address_.str(), channel_creds, args); @@ -285,6 +280,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> { TestServiceImpl service_; TestServiceImpl special_service_; TestServiceImplDupPkg dup_pkg_service_; + grpc::string user_agent_prefix_; }; static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs, @@ -601,6 +597,25 @@ TEST_P(End2endServerTryCancelTest, BidiStreamServerCancelAfter) { TestBidiStreamServerCancel(CANCEL_AFTER_PROCESSING, 5); } +TEST_P(End2endTest, SimpleRpcWithCustomeUserAgentPrefix) { + user_agent_prefix_ = "custom_prefix"; + ResetStub(); + EchoRequest request; + EchoResponse response; + request.set_message("Hello hello hello hello"); + request.mutable_param()->set_echo_metadata(true); + + ClientContext context; + Status s = stub_->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(s.ok()); + const auto& trailing_metadata = context.GetServerTrailingMetadata(); + auto iter = trailing_metadata.find("user-agent"); + EXPECT_TRUE(iter != trailing_metadata.end()); + grpc::string expected_prefix = user_agent_prefix_ + " grpc-c++/"; + EXPECT_TRUE(iter->second.starts_with(expected_prefix)); +} + TEST_P(End2endTest, MultipleRpcsWithVariedBinaryMetadataValue) { ResetStub(); std::vector<std::thread*> threads; @@ -918,7 +933,7 @@ TEST_P(End2endTest, ChannelState) { // Takes 10s. TEST_P(End2endTest, ChannelStateTimeout) { - if (GetParam().use_tls) { + if (GetParam().credentials_type != kInsecureCredentialsType) { return; } int port = grpc_pick_unused_port_or_die(); @@ -1127,7 +1142,7 @@ class SecureEnd2endTest : public End2endTest { protected: SecureEnd2endTest() { GPR_ASSERT(!GetParam().use_proxy); - GPR_ASSERT(GetParam().use_tls); + GPR_ASSERT(GetParam().credentials_type != kInsecureCredentialsType); } }; @@ -1350,21 +1365,42 @@ TEST_P(SecureEnd2endTest, ClientAuthContext) { EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2])); } +std::vector<TestScenario> CreateTestScenarios(bool use_proxy, + bool test_insecure, + bool test_secure) { + std::vector<TestScenario> scenarios; + std::vector<grpc::string> credentials_types; + if (test_secure) { + credentials_types = GetSecureCredentialsTypeList(); + } + if (test_insecure) { + credentials_types.push_back(kInsecureCredentialsType); + } + for (auto it = credentials_types.begin(); it != credentials_types.end(); + ++it) { + scenarios.push_back(TestScenario(false, *it)); + if (use_proxy) { + scenarios.push_back(TestScenario(true, *it)); + } + } + return scenarios; +} + INSTANTIATE_TEST_CASE_P(End2end, End2endTest, - ::testing::Values(TestScenario(false, false), - TestScenario(false, true))); + ::testing::ValuesIn(CreateTestScenarios(false, true, + true))); INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest, - ::testing::Values(TestScenario(false, false))); + ::testing::ValuesIn(CreateTestScenarios(false, true, + false))); INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest, - ::testing::Values(TestScenario(false, false), - TestScenario(false, true), - TestScenario(true, false), - TestScenario(true, true))); + ::testing::ValuesIn(CreateTestScenarios(true, true, + true))); INSTANTIATE_TEST_CASE_P(SecureEnd2end, SecureEnd2endTest, - ::testing::Values(TestScenario(false, true))); + ::testing::ValuesIn(CreateTestScenarios(false, false, + true))); } // namespace } // namespace testing diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index 50b2bf2514..c94a523fa1 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -41,6 +41,7 @@ #include <grpc++/support/byte_buffer.h> #include <grpc++/support/slice.h> #include <grpc/support/log.h> +#include <grpc/support/time.h> #include "src/proto/grpc/testing/payloads.grpc.pb.h" #include "src/proto/grpc/testing/services.grpc.pb.h" @@ -52,27 +53,8 @@ #include "test/cpp/util/create_test_channel.h" namespace grpc { - -#if defined(__APPLE__) -// Specialize Timepoint for high res clock as we need that -template <> -class TimePoint<std::chrono::high_resolution_clock::time_point> { - public: - TimePoint(const std::chrono::high_resolution_clock::time_point& time) { - TimepointHR2Timespec(time, &time_); - } - gpr_timespec raw_time() const { return time_; } - - private: - gpr_timespec time_; -}; -#endif - namespace testing { -typedef std::chrono::high_resolution_clock grpc_time_source; -typedef std::chrono::time_point<grpc_time_source> grpc_time; - template <class RequestType> class ClientRequestCreator { public: @@ -184,7 +166,7 @@ class Client { // Set up the load distribution based on the number of threads const auto& load = config.load_params(); - std::unique_ptr<RandomDist> random_dist; + std::unique_ptr<RandomDistInterface> random_dist; switch (load.load_case()) { case LoadParams::kClosedLoop: // Closed-loop doesn't use random dist at all @@ -218,25 +200,26 @@ class Client { closed_loop_ = false; // set up interarrival timer according to random dist interarrival_timer_.init(*random_dist, num_threads); + const auto now = gpr_now(GPR_CLOCK_MONOTONIC); for (size_t i = 0; i < num_threads; i++) { - next_time_.push_back( - grpc_time_source::now() + - std::chrono::duration_cast<grpc_time_source::duration>( - interarrival_timer_(i))); + next_time_.push_back(gpr_time_add( + now, + gpr_time_from_nanos(interarrival_timer_.next(i), GPR_TIMESPAN))); } } } - bool NextIssueTime(int thread_idx, grpc_time* time_delay) { - if (closed_loop_) { - return false; - } else { - *time_delay = next_time_[thread_idx]; - next_time_[thread_idx] += - std::chrono::duration_cast<grpc_time_source::duration>( - interarrival_timer_(thread_idx)); - return true; - } + gpr_timespec NextIssueTime(int thread_idx) { + const gpr_timespec result = next_time_[thread_idx]; + next_time_[thread_idx] = + gpr_time_add(next_time_[thread_idx], + gpr_time_from_nanos(interarrival_timer_.next(thread_idx), + GPR_TIMESPAN)); + return result; + } + std::function<gpr_timespec()> NextIssuer(int thread_idx) { + return closed_loop_ ? std::function<gpr_timespec()>() + : std::bind(&Client::NextIssueTime, this, thread_idx); } private: @@ -306,7 +289,7 @@ class Client { Histogram* new_stats_; Histogram histogram_; Client* client_; - size_t idx_; + const size_t idx_; std::thread impl_; }; @@ -314,7 +297,7 @@ class Client { std::unique_ptr<Timer> timer_; InterarrivalTimer interarrival_timer_; - std::vector<grpc_time> next_time_; + std::vector<gpr_timespec> next_time_; }; template <class StubType, class RequestType> @@ -323,9 +306,9 @@ class ClientImpl : public Client { ClientImpl(const ClientConfig& config, std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> create_stub) - : channels_(config.client_channels()), create_stub_(create_stub) { - cores_ = LimitCores(config.core_list().data(), config.core_list_size()); - + : cores_(LimitCores(config.core_list().data(), config.core_list_size())), + channels_(config.client_channels()), + create_stub_(create_stub) { for (int i = 0; i < config.client_channels(); i++) { channels_[i].init(config.server_targets(i % config.server_targets_size()), config, create_stub_); @@ -337,7 +320,7 @@ class ClientImpl : public Client { virtual ~ClientImpl() {} protected: - int cores_; + const int cores_; RequestType request_; class ClientChannelInfo { diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index f3f8f37051..9e8767d103 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -43,9 +43,9 @@ #include <vector> #include <gflags/gflags.h> +#include <grpc++/alarm.h> #include <grpc++/channel.h> #include <grpc++/client_context.h> -#include <grpc++/client_context.h> #include <grpc++/generic/generic_stub.h> #include <grpc/grpc.h> #include <grpc/support/cpu.h> @@ -60,11 +60,9 @@ namespace grpc { namespace testing { -typedef std::list<grpc_time> deadline_list; - class ClientRpcContext { public: - explicit ClientRpcContext(int ch) : channel_id_(ch) {} + ClientRpcContext() {} virtual ~ClientRpcContext() {} // next state, return false if done. Collect stats when appropriate virtual bool RunNextState(bool, Histogram* hist) = 0; @@ -74,72 +72,73 @@ class ClientRpcContext { return reinterpret_cast<ClientRpcContext*>(t); } - deadline_list::iterator deadline_posn() const { return deadline_posn_; } - void set_deadline_posn(const deadline_list::iterator& it) { - deadline_posn_ = it; - } virtual void Start(CompletionQueue* cq) = 0; - int channel_id() const { return channel_id_; } - - protected: - int channel_id_; - - private: - deadline_list::iterator deadline_posn_; }; template <class RequestType, class ResponseType> class ClientRpcContextUnaryImpl : public ClientRpcContext { public: ClientRpcContextUnaryImpl( - int channel_id, BenchmarkService::Stub* stub, const RequestType& req, + BenchmarkService::Stub* stub, const RequestType& req, + std::function<gpr_timespec()> next_issue, std::function< std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>( BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&, CompletionQueue*)> start_req, std::function<void(grpc::Status, ResponseType*)> on_done) - : ClientRpcContext(channel_id), - context_(), + : context_(), stub_(stub), + cq_(nullptr), req_(req), response_(), - next_state_(&ClientRpcContextUnaryImpl::RespDone), + next_state_(State::READY), callback_(on_done), + next_issue_(next_issue), start_req_(start_req) {} + ~ClientRpcContextUnaryImpl() GRPC_OVERRIDE {} void Start(CompletionQueue* cq) GRPC_OVERRIDE { - start_ = Timer::Now(); - response_reader_ = start_req_(stub_, &context_, req_, cq); - response_reader_->Finish(&response_, &status_, ClientRpcContext::tag(this)); + cq_ = cq; + if (!next_issue_) { // ready to issue + RunNextState(true, nullptr); + } else { // wait for the issue time + alarm_.reset(new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + } } - ~ClientRpcContextUnaryImpl() GRPC_OVERRIDE {} bool RunNextState(bool ok, Histogram* hist) GRPC_OVERRIDE { - bool ret = (this->*next_state_)(ok); - if (!ret) { - hist->Add((Timer::Now() - start_) * 1e9); + switch (next_state_) { + case State::READY: + start_ = Timer::Now(); + response_reader_ = start_req_(stub_, &context_, req_, cq_); + response_reader_->Finish(&response_, &status_, + ClientRpcContext::tag(this)); + next_state_ = State::RESP_DONE; + return true; + case State::RESP_DONE: + hist->Add((Timer::Now() - start_) * 1e9); + callback_(status_, &response_); + next_state_ = State::INVALID; + return false; + default: + GPR_ASSERT(false); + return false; } - return ret; } - ClientRpcContext* StartNewClone() GRPC_OVERRIDE { - return new ClientRpcContextUnaryImpl(channel_id_, stub_, req_, start_req_, + return new ClientRpcContextUnaryImpl(stub_, req_, next_issue_, start_req_, callback_); } private: - bool RespDone(bool) { - next_state_ = &ClientRpcContextUnaryImpl::DoCallBack; - return false; - } - bool DoCallBack(bool) { - callback_(status_, &response_); - return true; // we're done, this'll be ignored - } grpc::ClientContext context_; BenchmarkService::Stub* stub_; + CompletionQueue* cq_; + std::unique_ptr<Alarm> alarm_; RequestType req_; ResponseType response_; - bool (ClientRpcContextUnaryImpl::*next_state_)(bool); + enum State { INVALID, READY, RESP_DONE }; + State next_state_; std::function<void(grpc::Status, ResponseType*)> callback_; + std::function<gpr_timespec()> next_issue_; std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>( BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&, CompletionQueue*)> start_req_; @@ -157,49 +156,35 @@ class AsyncClient : public ClientImpl<StubType, RequestType> { // member name resolution until the template types are fully resolved public: using Client::SetupLoadTest; - using Client::NextIssueTime; using Client::closed_loop_; + using Client::NextIssuer; using ClientImpl<StubType, RequestType>::cores_; using ClientImpl<StubType, RequestType>::channels_; using ClientImpl<StubType, RequestType>::request_; AsyncClient(const ClientConfig& config, - std::function<ClientRpcContext*(int, StubType*, - const RequestType&)> setup_ctx, + std::function<ClientRpcContext*( + StubType*, std::function<gpr_timespec()> next_issue, + const RequestType&)> setup_ctx, std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> create_stub) : ClientImpl<StubType, RequestType>(config, create_stub), - num_async_threads_(NumThreads(config)), - channel_lock_(new std::mutex[config.client_channels()]), - contexts_(config.client_channels()), - max_outstanding_per_channel_(config.outstanding_rpcs_per_channel()), - channel_count_(config.client_channels()), - pref_channel_inc_(num_async_threads_) { + num_async_threads_(NumThreads(config)) { SetupLoadTest(config, num_async_threads_); for (int i = 0; i < num_async_threads_; i++) { cli_cqs_.emplace_back(new CompletionQueue); - if (!closed_loop_) { - rpc_deadlines_.emplace_back(); - next_channel_.push_back(i % channel_count_); - issue_allowed_.emplace_back(true); - - grpc_time next_issue; - NextIssueTime(i, &next_issue); - next_issue_.push_back(next_issue); - } + next_issuers_.emplace_back(NextIssuer(i)); } + using namespace std::placeholders; int t = 0; for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) { - for (int ch = 0; ch < channel_count_; ch++) { + for (int ch = 0; ch < config.client_channels(); ch++) { auto* cq = cli_cqs_[t].get(); + auto ctx = + setup_ctx(channels_[ch].get_stub(), next_issuers_[t], request_); + ctx->Start(cq); t = (t + 1) % cli_cqs_.size(); - auto ctx = setup_ctx(ch, channels_[ch].get_stub(), request_); - if (closed_loop_) { - ctx->Start(cq); - } else { - contexts_[ch].push_front(ctx); - } } } } @@ -212,140 +197,34 @@ class AsyncClient : public ClientImpl<StubType, RequestType> { delete ClientRpcContext::detag(got_tag); } } - // Now clear out all the pre-allocated idle contexts - for (int ch = 0; ch < channel_count_; ch++) { - while (!contexts_[ch].empty()) { - // Get an idle context from the front of the list - auto* ctx = *(contexts_[ch].begin()); - contexts_[ch].pop_front(); - delete ctx; - } - } - delete[] channel_lock_; } bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE GRPC_FINAL { void* got_tag; bool ok; - grpc_time deadline, short_deadline; - if (closed_loop_) { - deadline = grpc_time_source::now() + std::chrono::seconds(1); - short_deadline = deadline; - } else { - if (rpc_deadlines_[thread_idx].empty()) { - deadline = grpc_time_source::now() + std::chrono::seconds(1); - } else { - deadline = *(rpc_deadlines_[thread_idx].begin()); - } - short_deadline = - issue_allowed_[thread_idx] ? next_issue_[thread_idx] : deadline; - } - - bool got_event; - switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, short_deadline)) { - case CompletionQueue::SHUTDOWN: - return false; - case CompletionQueue::TIMEOUT: - got_event = false; - break; - case CompletionQueue::GOT_EVENT: - got_event = true; - break; - default: - GPR_ASSERT(false); - break; - } - if (got_event) { + if (cli_cqs_[thread_idx]->Next(&got_tag, &ok)) { + // Got a regular event, so process it ClientRpcContext* ctx = ClientRpcContext::detag(got_tag); - if (ctx->RunNextState(ok, histogram) == false) { - // call the callback and then clone the ctx - ctx->RunNextState(ok, histogram); - ClientRpcContext* clone_ctx = ctx->StartNewClone(); - if (closed_loop_) { - clone_ctx->Start(cli_cqs_[thread_idx].get()); - } else { - // Remove the entry from the rpc deadlines list - rpc_deadlines_[thread_idx].erase(ctx->deadline_posn()); - // Put the clone_ctx in the list of idle contexts for this channel - // Under lock - int ch = clone_ctx->channel_id(); - std::lock_guard<std::mutex> g(channel_lock_[ch]); - contexts_[ch].push_front(clone_ctx); - } + if (!ctx->RunNextState(ok, histogram)) { + // The RPC and callback are done, so clone the ctx + // and kickstart the new one + auto clone = ctx->StartNewClone(); + clone->Start(cli_cqs_[thread_idx].get()); // delete the old version delete ctx; } - if (!closed_loop_) - issue_allowed_[thread_idx] = - true; // may be ok now even if it hadn't been + return true; + } else { // queue is shutting down + return false; } - if (!closed_loop_ && issue_allowed_[thread_idx] && - grpc_time_source::now() >= next_issue_[thread_idx]) { - // Attempt to issue - bool issued = false; - for (int num_attempts = 0, channel_attempt = next_channel_[thread_idx]; - num_attempts < channel_count_ && !issued; num_attempts++) { - bool can_issue = false; - ClientRpcContext* ctx = nullptr; - { - std::lock_guard<std::mutex> g(channel_lock_[channel_attempt]); - if (!contexts_[channel_attempt].empty()) { - // Get an idle context from the front of the list - ctx = *(contexts_[channel_attempt].begin()); - contexts_[channel_attempt].pop_front(); - can_issue = true; - } - } - if (can_issue) { - // do the work to issue - rpc_deadlines_[thread_idx].emplace_back(grpc_time_source::now() + - std::chrono::seconds(1)); - auto it = rpc_deadlines_[thread_idx].end(); - --it; - ctx->set_deadline_posn(it); - ctx->Start(cli_cqs_[thread_idx].get()); - issued = true; - // If we did issue, then next time, try our thread's next - // preferred channel - next_channel_[thread_idx] += pref_channel_inc_; - if (next_channel_[thread_idx] >= channel_count_) - next_channel_[thread_idx] = (thread_idx % channel_count_); - } else { - // Do a modular increment of channel attempt if we couldn't issue - channel_attempt = (channel_attempt + 1) % channel_count_; - } - } - if (issued) { - // We issued one; see when we can issue the next - grpc_time next_issue; - NextIssueTime(thread_idx, &next_issue); - next_issue_[thread_idx] = next_issue; - } else { - issue_allowed_[thread_idx] = false; - } - } - return true; } protected: - int num_async_threads_; + const int num_async_threads_; private: - class boolean { // exists only to avoid data-race on vector<bool> - public: - boolean() : val_(false) {} - boolean(bool b) : val_(b) {} - operator bool() const { return val_; } - boolean& operator=(bool b) { - val_ = b; - return *this; - } - - private: - bool val_; - }; int NumThreads(const ClientConfig& config) { int num_threads = config.async_client_threads(); if (num_threads <= 0) { // Use dynamic sizing @@ -356,18 +235,7 @@ class AsyncClient : public ClientImpl<StubType, RequestType> { } std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_; - - std::vector<deadline_list> rpc_deadlines_; // per thread deadlines - std::vector<int> next_channel_; // per thread round-robin channel ctr - std::vector<boolean> issue_allowed_; // may this thread attempt to issue - std::vector<grpc_time> next_issue_; // when should it issue? - - std::mutex* - channel_lock_; // a vector, but avoid std::vector for old compilers - std::vector<context_list> contexts_; // per-channel list of idle contexts - int max_outstanding_per_channel_; - int channel_count_; - int pref_channel_inc_; + std::vector<std::function<gpr_timespec()>> next_issuers_; }; static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator( @@ -391,11 +259,11 @@ class AsyncUnaryClient GRPC_FINAL const SimpleRequest& request, CompletionQueue* cq) { return stub->AsyncUnaryCall(ctx, request, cq); }; - static ClientRpcContext* SetupCtx(int channel_id, - BenchmarkService::Stub* stub, + static ClientRpcContext* SetupCtx(BenchmarkService::Stub* stub, + std::function<gpr_timespec()> next_issue, const SimpleRequest& req) { return new ClientRpcContextUnaryImpl<SimpleRequest, SimpleResponse>( - channel_id, stub, req, AsyncUnaryClient::StartReq, + stub, req, next_issue, AsyncUnaryClient::StartReq, AsyncUnaryClient::CheckDone); } }; @@ -404,62 +272,94 @@ template <class RequestType, class ResponseType> class ClientRpcContextStreamingImpl : public ClientRpcContext { public: ClientRpcContextStreamingImpl( - int channel_id, BenchmarkService::Stub* stub, const RequestType& req, + BenchmarkService::Stub* stub, const RequestType& req, + std::function<gpr_timespec()> next_issue, std::function<std::unique_ptr< grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>( BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)> start_req, std::function<void(grpc::Status, ResponseType*)> on_done) - : ClientRpcContext(channel_id), - context_(), + : context_(), stub_(stub), + cq_(nullptr), req_(req), response_(), - next_state_(&ClientRpcContextStreamingImpl::ReqSent), + next_state_(State::INVALID), callback_(on_done), + next_issue_(next_issue), start_req_(start_req), start_(Timer::Now()) {} ~ClientRpcContextStreamingImpl() GRPC_OVERRIDE {} + void Start(CompletionQueue* cq) GRPC_OVERRIDE { + cq_ = cq; + stream_ = start_req_(stub_, &context_, cq, ClientRpcContext::tag(this)); + next_state_ = State::STREAM_IDLE; + } bool RunNextState(bool ok, Histogram* hist) GRPC_OVERRIDE { - return (this->*next_state_)(ok, hist); + while (true) { + switch (next_state_) { + case State::STREAM_IDLE: + if (!next_issue_) { // ready to issue + next_state_ = State::READY_TO_WRITE; + } else { + next_state_ = State::WAIT; + } + break; // loop around, don't return + case State::WAIT: + alarm_.reset( + new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + next_state_ = State::READY_TO_WRITE; + return true; + case State::READY_TO_WRITE: + if (!ok) { + return false; + } + start_ = Timer::Now(); + next_state_ = State::WRITE_DONE; + stream_->Write(req_, ClientRpcContext::tag(this)); + return true; + case State::WRITE_DONE: + if (!ok) { + return false; + } + next_state_ = State::READ_DONE; + stream_->Read(&response_, ClientRpcContext::tag(this)); + return true; + break; + case State::READ_DONE: + hist->Add((Timer::Now() - start_) * 1e9); + callback_(status_, &response_); + next_state_ = State::STREAM_IDLE; + break; // loop around + default: + GPR_ASSERT(false); + return false; + } + } } ClientRpcContext* StartNewClone() GRPC_OVERRIDE { - return new ClientRpcContextStreamingImpl(channel_id_, stub_, req_, + return new ClientRpcContextStreamingImpl(stub_, req_, next_issue_, start_req_, callback_); } - void Start(CompletionQueue* cq) GRPC_OVERRIDE { - stream_ = start_req_(stub_, &context_, cq, ClientRpcContext::tag(this)); - } private: - bool ReqSent(bool ok, Histogram*) { return StartWrite(ok); } - bool StartWrite(bool ok) { - if (!ok) { - return (false); - } - start_ = Timer::Now(); - next_state_ = &ClientRpcContextStreamingImpl::WriteDone; - stream_->Write(req_, ClientRpcContext::tag(this)); - return true; - } - bool WriteDone(bool ok, Histogram*) { - if (!ok) { - return (false); - } - next_state_ = &ClientRpcContextStreamingImpl::ReadDone; - stream_->Read(&response_, ClientRpcContext::tag(this)); - return true; - } - bool ReadDone(bool ok, Histogram* hist) { - hist->Add((Timer::Now() - start_) * 1e9); - return StartWrite(ok); - } grpc::ClientContext context_; BenchmarkService::Stub* stub_; + CompletionQueue* cq_; + std::unique_ptr<Alarm> alarm_; RequestType req_; ResponseType response_; - bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram*); + enum State { + INVALID, + STREAM_IDLE, + WAIT, + READY_TO_WRITE, + WRITE_DONE, + READ_DONE + }; + State next_state_; std::function<void(grpc::Status, ResponseType*)> callback_; + std::function<gpr_timespec()> next_issue_; std::function< std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>( BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, @@ -475,9 +375,6 @@ class AsyncStreamingClient GRPC_FINAL public: explicit AsyncStreamingClient(const ClientConfig& config) : AsyncClient(config, SetupCtx, BenchmarkStubCreator) { - // async streaming currently only supports closed loop - GPR_ASSERT(closed_loop_); - StartThreads(num_async_threads_); } @@ -492,11 +389,11 @@ class AsyncStreamingClient GRPC_FINAL auto stream = stub->AsyncStreamingCall(ctx, cq, tag); return stream; }; - static ClientRpcContext* SetupCtx(int channel_id, - BenchmarkService::Stub* stub, + static ClientRpcContext* SetupCtx(BenchmarkService::Stub* stub, + std::function<gpr_timespec()> next_issue, const SimpleRequest& req) { return new ClientRpcContextStreamingImpl<SimpleRequest, SimpleResponse>( - channel_id, stub, req, AsyncStreamingClient::StartReq, + stub, req, next_issue, AsyncStreamingClient::StartReq, AsyncStreamingClient::CheckDone); } }; @@ -504,64 +401,96 @@ class AsyncStreamingClient GRPC_FINAL class ClientRpcContextGenericStreamingImpl : public ClientRpcContext { public: ClientRpcContextGenericStreamingImpl( - int channel_id, grpc::GenericStub* stub, const ByteBuffer& req, + grpc::GenericStub* stub, const ByteBuffer& req, + std::function<gpr_timespec()> next_issue, std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>( grpc::GenericStub*, grpc::ClientContext*, const grpc::string& method_name, CompletionQueue*, void*)> start_req, std::function<void(grpc::Status, ByteBuffer*)> on_done) - : ClientRpcContext(channel_id), - context_(), + : context_(), stub_(stub), + cq_(nullptr), req_(req), response_(), - next_state_(&ClientRpcContextGenericStreamingImpl::ReqSent), + next_state_(State::INVALID), callback_(on_done), + next_issue_(next_issue), start_req_(start_req), start_(Timer::Now()) {} ~ClientRpcContextGenericStreamingImpl() GRPC_OVERRIDE {} - bool RunNextState(bool ok, Histogram* hist) GRPC_OVERRIDE { - return (this->*next_state_)(ok, hist); - } - ClientRpcContext* StartNewClone() GRPC_OVERRIDE { - return new ClientRpcContextGenericStreamingImpl(channel_id_, stub_, req_, - start_req_, callback_); - } void Start(CompletionQueue* cq) GRPC_OVERRIDE { + cq_ = cq; const grpc::string kMethodName( "/grpc.testing.BenchmarkService/StreamingCall"); stream_ = start_req_(stub_, &context_, kMethodName, cq, ClientRpcContext::tag(this)); + next_state_ = State::STREAM_IDLE; } - - private: - bool ReqSent(bool ok, Histogram*) { return StartWrite(ok); } - bool StartWrite(bool ok) { - if (!ok) { - return (false); - } - start_ = Timer::Now(); - next_state_ = &ClientRpcContextGenericStreamingImpl::WriteDone; - stream_->Write(req_, ClientRpcContext::tag(this)); - return true; - } - bool WriteDone(bool ok, Histogram*) { - if (!ok) { - return (false); + bool RunNextState(bool ok, Histogram* hist) GRPC_OVERRIDE { + while (true) { + switch (next_state_) { + case State::STREAM_IDLE: + if (!next_issue_) { // ready to issue + next_state_ = State::READY_TO_WRITE; + } else { + next_state_ = State::WAIT; + } + break; // loop around, don't return + case State::WAIT: + alarm_.reset( + new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + next_state_ = State::READY_TO_WRITE; + return true; + case State::READY_TO_WRITE: + if (!ok) { + return false; + } + start_ = Timer::Now(); + next_state_ = State::WRITE_DONE; + stream_->Write(req_, ClientRpcContext::tag(this)); + return true; + case State::WRITE_DONE: + if (!ok) { + return false; + } + next_state_ = State::READ_DONE; + stream_->Read(&response_, ClientRpcContext::tag(this)); + return true; + break; + case State::READ_DONE: + hist->Add((Timer::Now() - start_) * 1e9); + callback_(status_, &response_); + next_state_ = State::STREAM_IDLE; + break; // loop around + default: + GPR_ASSERT(false); + return false; + } } - next_state_ = &ClientRpcContextGenericStreamingImpl::ReadDone; - stream_->Read(&response_, ClientRpcContext::tag(this)); - return true; } - bool ReadDone(bool ok, Histogram* hist) { - hist->Add((Timer::Now() - start_) * 1e9); - return StartWrite(ok); + ClientRpcContext* StartNewClone() GRPC_OVERRIDE { + return new ClientRpcContextGenericStreamingImpl(stub_, req_, next_issue_, + start_req_, callback_); } + + private: grpc::ClientContext context_; grpc::GenericStub* stub_; + CompletionQueue* cq_; + std::unique_ptr<Alarm> alarm_; ByteBuffer req_; ByteBuffer response_; - bool (ClientRpcContextGenericStreamingImpl::*next_state_)(bool, Histogram*); + enum State { + INVALID, + STREAM_IDLE, + WAIT, + READY_TO_WRITE, + WRITE_DONE, + READ_DONE + }; + State next_state_; std::function<void(grpc::Status, ByteBuffer*)> callback_; + std::function<gpr_timespec()> next_issue_; std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>( grpc::GenericStub*, grpc::ClientContext*, const grpc::string&, CompletionQueue*, void*)> start_req_; @@ -580,9 +509,6 @@ class GenericAsyncStreamingClient GRPC_FINAL public: explicit GenericAsyncStreamingClient(const ClientConfig& config) : AsyncClient(config, SetupCtx, GenericStubCreator) { - // async streaming currently only supports closed loop - GPR_ASSERT(closed_loop_); - StartThreads(num_async_threads_); } @@ -596,10 +522,11 @@ class GenericAsyncStreamingClient GRPC_FINAL auto stream = stub->Call(ctx, method_name, cq, tag); return stream; }; - static ClientRpcContext* SetupCtx(int channel_id, grpc::GenericStub* stub, + static ClientRpcContext* SetupCtx(grpc::GenericStub* stub, + std::function<gpr_timespec()> next_issue, const ByteBuffer& req) { return new ClientRpcContextGenericStreamingImpl( - channel_id, stub, req, GenericAsyncStreamingClient::StartReq, + stub, req, next_issue, GenericAsyncStreamingClient::StartReq, GenericAsyncStreamingClient::CheckDone); } }; diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index d93537b279..edfc246a25 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -84,11 +84,8 @@ class SynchronousClient protected: void WaitToIssue(int thread_idx) { - grpc_time next_time; - if (NextIssueTime(thread_idx, &next_time)) { - gpr_timespec next_timespec; - TimepointHR2Timespec(next_time, &next_timespec); - gpr_sleep_until(next_timespec); + if (!closed_loop_) { + gpr_sleep_until(NextIssueTime(thread_idx)); } } diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 80f6ada409..1c7fdf8796 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -197,9 +197,7 @@ std::unique_ptr<ScenarioResult> RunScenario( workers.resize(num_clients + num_servers); gpr_timespec deadline = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_seconds( - warmup_seconds + benchmark_seconds + 20, GPR_TIMESPAN)); + GRPC_TIMEOUT_SECONDS_TO_DEADLINE(warmup_seconds + benchmark_seconds + 20); // Start servers using runsc::ServerData; diff --git a/test/cpp/qps/interarrival.h b/test/cpp/qps/interarrival.h index 841619e3ff..b6fd67b77c 100644 --- a/test/cpp/qps/interarrival.h +++ b/test/cpp/qps/interarrival.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,15 +51,15 @@ namespace testing { // stacks. Thus, this code only uses a uniform distribution of doubles [0,1) // and then provides the distribution functions itself. -class RandomDist { +class RandomDistInterface { public: - RandomDist() {} - virtual ~RandomDist() = 0; - // Argument to operator() is a uniform double in the range [0,1) - virtual double operator()(double uni) const = 0; + RandomDistInterface() {} + virtual ~RandomDistInterface() = 0; + // Argument to transform is a uniform double in the range [0,1) + virtual double transform(double uni) const = 0; }; -inline RandomDist::~RandomDist() {} +inline RandomDistInterface::~RandomDistInterface() {} // ExpDist implements an exponential distribution, which is the // interarrival distribution for a Poisson process. The parameter @@ -69,11 +69,11 @@ inline RandomDist::~RandomDist() {} // independent identical stationary sources. For more information, // see http://en.wikipedia.org/wiki/Exponential_distribution -class ExpDist GRPC_FINAL : public RandomDist { +class ExpDist GRPC_FINAL : public RandomDistInterface { public: explicit ExpDist(double lambda) : lambda_recip_(1.0 / lambda) {} ~ExpDist() GRPC_OVERRIDE {} - double operator()(double uni) const GRPC_OVERRIDE { + double transform(double uni) const GRPC_OVERRIDE { // Note: Use 1.0-uni above to avoid NaN if uni is 0 return lambda_recip_ * (-log(1.0 - uni)); } @@ -87,11 +87,11 @@ class ExpDist GRPC_FINAL : public RandomDist { // mean interarrival time is (lo+hi)/2. For more information, // see http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 -class UniformDist GRPC_FINAL : public RandomDist { +class UniformDist GRPC_FINAL : public RandomDistInterface { public: UniformDist(double lo, double hi) : lo_(lo), range_(hi - lo) {} ~UniformDist() GRPC_OVERRIDE {} - double operator()(double uni) const GRPC_OVERRIDE { + double transform(double uni) const GRPC_OVERRIDE { return uni * range_ + lo_; } @@ -106,11 +106,11 @@ class UniformDist GRPC_FINAL : public RandomDist { // clients) will not preserve any deterministic interarrival gap across // requests. -class DetDist GRPC_FINAL : public RandomDist { +class DetDist GRPC_FINAL : public RandomDistInterface { public: explicit DetDist(double val) : val_(val) {} ~DetDist() GRPC_OVERRIDE {} - double operator()(double uni) const GRPC_OVERRIDE { return val_; } + double transform(double uni) const GRPC_OVERRIDE { return val_; } private: double val_; @@ -123,12 +123,12 @@ class DetDist GRPC_FINAL : public RandomDist { // good representation of the response times of data center jobs. See // http://en.wikipedia.org/wiki/Pareto_distribution -class ParetoDist GRPC_FINAL : public RandomDist { +class ParetoDist GRPC_FINAL : public RandomDistInterface { public: ParetoDist(double base, double alpha) : base_(base), alpha_recip_(1.0 / alpha) {} ~ParetoDist() GRPC_OVERRIDE {} - double operator()(double uni) const GRPC_OVERRIDE { + double transform(double uni) const GRPC_OVERRIDE { // Note: Use 1.0-uni above to avoid div by zero if uni is 0 return base_ / pow(1.0 - uni, alpha_recip_); } @@ -145,13 +145,14 @@ class ParetoDist GRPC_FINAL : public RandomDist { class InterarrivalTimer { public: InterarrivalTimer() {} - void init(const RandomDist& r, int threads, int entries = 1000000) { + void init(const RandomDistInterface& r, int threads, int entries = 1000000) { for (int i = 0; i < entries; i++) { // rand is the only choice that is portable across POSIX and Windows // and that supports new and old compilers - const double uniform_0_1 = rand() / RAND_MAX; + const double uniform_0_1 = + static_cast<double>(rand()) / static_cast<double>(RAND_MAX); random_table_.push_back( - std::chrono::nanoseconds(static_cast<int64_t>(1e9 * r(uniform_0_1)))); + static_cast<int64_t>(1e9 * r.transform(uniform_0_1))); } // Now set up the thread positions for (int i = 0; i < threads; i++) { @@ -160,7 +161,7 @@ class InterarrivalTimer { } virtual ~InterarrivalTimer(){}; - std::chrono::nanoseconds operator()(int thread_num) { + int64_t next(int thread_num) { auto ret = *(thread_posns_[thread_num]++); if (thread_posns_[thread_num] == random_table_.end()) thread_posns_[thread_num] = random_table_.begin(); @@ -168,7 +169,7 @@ class InterarrivalTimer { } private: - typedef std::vector<std::chrono::nanoseconds> time_table; + typedef std::vector<int64_t> time_table; std::vector<time_table::const_iterator> thread_posns_; time_table random_table_; }; diff --git a/test/cpp/qps/qps-sweep.sh b/test/cpp/qps/qps-sweep.sh index 539da1d893..7a35788849 100755 --- a/test/cpp/qps/qps-sweep.sh +++ b/test/cpp/qps/qps-sweep.sh @@ -37,9 +37,26 @@ fi bins=`find . .. ../.. ../../.. -name bins | head -1` +# Print out each command that gets executed set -x +# +# Specify parameters used in some of the tests +# + +# big is the size in bytes of large messages (0 is the size otherwise) big=65536 + +# wide is the number of client channels in multi-channel tests (1 otherwise) +wide=64 + +# deep is the number of RPCs outstanding on a channel in non-ping-pong tests +# (the value used is 1 otherwise) +deep=100 + +# half is half the count of worker processes, used in the crossbar scenario +# that uses equal clients and servers. The other scenarios use only 1 server +# and either 1 client or N-1 clients as appropriate half=`echo $QPS_WORKERS | awk -F, '{print int(NF/2)}'` for secure in true false; do @@ -52,30 +69,40 @@ for secure in true false; do # Scenario 2: generic async streaming "unconstrained" (QPS) "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ - --num_servers=1 --num_clients=0 + --num_servers=1 --num_clients=0 |& tee /tmp/qps-test.$$ # Scenario 2b: QPS with a single server core "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=0 --server_core_limit=1 # Scenario 2c: protobuf-based QPS "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --simple_req_size=0 --simple_resp_size=0 \ + --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --simple_req_size=0 --simple_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=0 - # Scenario 3: Latency at near-peak load (TBD) + # Scenario 3: Latency at sub-peak load (all clients equally loaded) + for loadfactor in 0.2 0.5 0.7; do + "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ + --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ + --num_servers=1 --num_clients=0 --poisson_load=`awk -v lf=$loadfactor \ + '$5 == "QPS:" {print int(lf * $6); exit}' /tmp/qps-test.$$` + done + + rm /tmp/qps-test.$$ # Scenario 4: Single-channel bidirectional throughput test (like TCP_STREAM). "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 @@ -108,35 +135,35 @@ for secure in true false; do # Scenario 9: Crossbar QPS test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=$half --num_clients=0 # Scenario 10: Multi-channel bidir throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=$big --bbuf_resp_size=$big \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=1 \ + --client_channels=$wide --bbuf_req_size=$big --bbuf_resp_size=$big \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 11: Single-channel request throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=0 \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 12: Single-channel response throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=0 --bbuf_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 13: Single-channel bidirectional protobuf throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --simple_req_size=$big --simple_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 diff --git a/test/cpp/qps/qps_interarrival_test.cc b/test/cpp/qps/qps_interarrival_test.cc index ccda28f09a..77e81fb84b 100644 --- a/test/cpp/qps/qps_interarrival_test.cc +++ b/test/cpp/qps/qps_interarrival_test.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,17 +39,17 @@ #include "test/cpp/qps/interarrival.h" -using grpc::testing::RandomDist; +using grpc::testing::RandomDistInterface; using grpc::testing::InterarrivalTimer; -static void RunTest(RandomDist &&r, int threads, std::string title) { +static void RunTest(RandomDistInterface &&r, int threads, std::string title) { InterarrivalTimer timer; timer.init(r, threads); gpr_histogram *h(gpr_histogram_create(0.01, 60e9)); for (int i = 0; i < 10000000; i++) { for (int j = 0; j < threads; j++) { - gpr_histogram_add(h, timer(j).count()); + gpr_histogram_add(h, timer.next(j)); } } @@ -70,7 +70,7 @@ using grpc::testing::ParetoDist; int main(int argc, char **argv) { RunTest(ExpDist(10.0), 5, std::string("Exponential(10)")); RunTest(DetDist(5.0), 5, std::string("Det(5)")); - RunTest(UniformDist(0.0, 10.0), 5, std::string("Uniform(1,10)")); + RunTest(UniformDist(0.0, 10.0), 5, std::string("Uniform(0,10)")); RunTest(ParetoDist(1.0, 1.0), 5, std::string("Pareto(1,1)")); return 0; } diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc index fe5f685b6e..0ac41d9f96 100644 --- a/test/cpp/qps/qps_openloop_test.cc +++ b/test/cpp/qps/qps_openloop_test.cc @@ -53,7 +53,7 @@ static void RunQPS() { client_config.set_outstanding_rpcs_per_channel(1000); client_config.set_client_channels(8); client_config.set_async_client_threads(8); - client_config.set_rpc_type(UNARY); + client_config.set_rpc_type(STREAMING); client_config.mutable_load_params()->mutable_poisson()->set_offered_load( 1000.0); diff --git a/test/cpp/qps/qps_test.cc b/test/cpp/qps/qps_test.cc index 15054db892..27aaf137f6 100644 --- a/test/cpp/qps/qps_test.cc +++ b/test/cpp/qps/qps_test.cc @@ -53,7 +53,7 @@ static void RunQPS() { client_config.set_outstanding_rpcs_per_channel(1000); client_config.set_client_channels(8); client_config.set_async_client_threads(8); - client_config.set_rpc_type(UNARY); + client_config.set_rpc_type(STREAMING); client_config.mutable_load_params()->mutable_closed_loop(); ServerConfig server_config; diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 1302d718f0..2024e0bfef 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -51,6 +51,7 @@ #include <gtest/gtest.h> #include "src/proto/grpc/testing/services.grpc.pb.h" +#include "test/core/util/test_config.h" #include "test/cpp/qps/server.h" namespace grpc { @@ -129,7 +130,7 @@ class AsyncQpsServerTest : public Server { } } ~AsyncQpsServerTest() { - auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); + auto deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10); server_->Shutdown(deadline); for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) { (*ss)->set_shutdown(); diff --git a/test/cpp/util/test_credentials_provider.cc b/test/cpp/util/test_credentials_provider.cc new file mode 100644 index 0000000000..1086e14258 --- /dev/null +++ b/test/cpp/util/test_credentials_provider.cc @@ -0,0 +1,82 @@ + +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/util/test_credentials_provider.h" + +#include "test/core/end2end/data/ssl_test_data.h" + +namespace grpc { +namespace testing { + +const char kTlsCredentialsType[] = "TLS_CREDENTIALS"; + +std::shared_ptr<ChannelCredentials> GetChannelCredentials( + const grpc::string& type, ChannelArguments* args) { + if (type == kInsecureCredentialsType) { + return InsecureChannelCredentials(); + } else if (type == kTlsCredentialsType) { + SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; + args->SetSslTargetNameOverride("foo.test.google.fr"); + return SslCredentials(ssl_opts); + } else { + gpr_log(GPR_ERROR, "Unsupported credentials type %s.", type.c_str()); + } + return nullptr; +} + +std::shared_ptr<ServerCredentials> GetServerCredentials( + const grpc::string& type) { + if (type == kInsecureCredentialsType) { + return InsecureServerCredentials(); + } else if (type == kTlsCredentialsType) { + SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, + test_server1_cert}; + SslServerCredentialsOptions ssl_opts; + ssl_opts.pem_root_certs = ""; + ssl_opts.pem_key_cert_pairs.push_back(pkcp); + return SslServerCredentials(ssl_opts); + } else { + gpr_log(GPR_ERROR, "Unsupported credentials type %s.", type.c_str()); + } + return nullptr; +} + +std::vector<grpc::string> GetSecureCredentialsTypeList() { + std::vector<grpc::string> types; + types.push_back(kTlsCredentialsType); + return types; +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/util/test_credentials_provider.h b/test/cpp/util/test_credentials_provider.h new file mode 100644 index 0000000000..f7253051a9 --- /dev/null +++ b/test/cpp/util/test_credentials_provider.h @@ -0,0 +1,63 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H +#define GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H + +#include <memory> + +#include <grpc++/security/credentials.h> +#include <grpc++/security/server_credentials.h> +#include <grpc++/support/channel_arguments.h> + +namespace grpc { +namespace testing { + +const char kInsecureCredentialsType[] = "INSECURE_CREDENTIALS"; + +// Provide channel credentials according to the given type. Alter the channel +// arguments if needed. +std::shared_ptr<ChannelCredentials> GetChannelCredentials( + const grpc::string& type, ChannelArguments* args); + +// Provide server credentials according to the given type. +std::shared_ptr<ServerCredentials> GetServerCredentials( + const grpc::string& type); + +// Provide a list of secure credentials type. +std::vector<grpc::string> GetSecureCredentialsTypeList(); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H |