diff options
author | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2015-04-11 01:27:32 +0200 |
---|---|---|
committer | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2015-04-11 01:53:09 +0200 |
commit | b7c2035e83a9b3e346f1fd37f9ad55c2070fb02e (patch) | |
tree | 6d4703d352f4f3204415d6785df52320d3d14a9b /test/cpp | |
parent | 27a0dc0208e90b6463049df16da6c35216eab0aa (diff) | |
parent | 05f2d9f8267d69bfeb60f52446385a1955eddd93 (diff) |
Merge branch 'master' of https://github.com/grpc/grpc into the-purge-2
Conflicts:
test/cpp/end2end/async_end2end_test.cc
test/cpp/end2end/end2end_test.cc
test/cpp/interop/client.cc
Diffstat (limited to 'test/cpp')
27 files changed, 1138 insertions, 480 deletions
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 698f1bb547..c5d6840bcc 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -33,10 +33,10 @@ #include <memory> -#include "test/core/util/test_config.h" #include "test/core/util/port.h" -#include "test/cpp/util/echo_duplicate.pb.h" -#include "test/cpp/util/echo.pb.h" +#include "test/core/util/test_config.h" +#include "test/cpp/util/echo_duplicate.grpc.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include <grpc++/async_unary_call.h> #include <grpc++/channel_arguments.h> #include <grpc++/channel_interface.h> diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 0e79e21ee0..198b1742e6 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -35,8 +35,8 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" -#include "test/cpp/util/echo_duplicate.pb.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo_duplicate.grpc.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include "src/cpp/server/thread_pool.h" #include <grpc++/channel_arguments.h> #include <grpc++/channel_interface.h> diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index 3551251d1d..9603cdc0b3 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -36,7 +36,7 @@ #include "src/cpp/proto/proto_utils.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include <grpc++/async_generic_service.h> #include <grpc++/async_unary_call.h> #include <grpc++/byte_buffer.h> diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index a4641b667e..189cdeb0ee 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -31,28 +31,19 @@ * */ -#include <fstream> #include <memory> -#include <sstream> -#include <string> -#include <thread> #include <unistd.h> #include <grpc/grpc.h> #include <grpc/support/log.h> #include <gflags/gflags.h> -#include <grpc++/channel_arguments.h> #include <grpc++/channel_interface.h> #include <grpc++/client_context.h> -#include <grpc++/create_channel.h> -#include <grpc++/credentials.h> #include <grpc++/status.h> #include <grpc++/stream.h> -#include "test/cpp/util/create_test_channel.h" -#include "test/cpp/interop/test.pb.h" -#include "test/cpp/interop/empty.pb.h" -#include "test/cpp/interop/messages.pb.h" +#include "test/cpp/interop/client_helper.h" +#include "test/cpp/interop/interop_client.h" DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls."); DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google"); @@ -80,21 +71,8 @@ DEFINE_string(service_account_key_file, "", "Path to service account json key file."); DEFINE_string(oauth_scope, "", "Scope for OAuth tokens."); -using grpc::ChannelInterface; -using grpc::ClientContext; -using grpc::ComputeEngineCredentials; -using grpc::CreateTestChannel; -using grpc::Credentials; -using grpc::JWTCredentials; -using grpc::ServiceAccountCredentials; -using grpc::testing::ResponseParameters; -using grpc::testing::SimpleRequest; -using grpc::testing::SimpleResponse; -using grpc::testing::StreamingInputCallRequest; -using grpc::testing::StreamingInputCallResponse; -using grpc::testing::StreamingOutputCallRequest; -using grpc::testing::StreamingOutputCallResponse; -using grpc::testing::TestService; +using grpc::testing::CreateChannelForTestCase; +using grpc::testing::GetServiceAccountJsonKey; // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. @@ -103,361 +81,48 @@ namespace gflags {} using namespace google; using namespace gflags; -namespace { -// The same value is defined by the Java client. -const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904}; -const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979}; -const int kNumResponseMessages = 2000; -const int kResponseMessageSize = 1030; -const int kReceiveDelayMilliSeconds = 20; -const int kLargeRequestSize = 314159; -const int kLargeResponseSize = 271812; -} // namespace - -grpc::string GetServiceAccountJsonKey() { - static grpc::string json_key; - if (json_key.empty()) { - std::ifstream json_key_file(FLAGS_service_account_key_file); - std::stringstream key_stream; - key_stream << json_key_file.rdbuf(); - json_key = key_stream.str(); - } - return json_key; -} - -std::shared_ptr<ChannelInterface> CreateChannelForTestCase( - const grpc::string& test_case) { - GPR_ASSERT(FLAGS_server_port); - const int host_port_buf_size = 1024; - char host_port[host_port_buf_size]; - snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), - FLAGS_server_port); - - if (test_case == "service_account_creds") { - std::unique_ptr<Credentials> creds; - GPR_ASSERT(FLAGS_enable_ssl); - grpc::string json_key = GetServiceAccountJsonKey(); - creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope, 3600); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else if (test_case == "compute_engine_creds") { - std::unique_ptr<Credentials> creds; - GPR_ASSERT(FLAGS_enable_ssl); - creds = ComputeEngineCredentials(); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else if (test_case == "jwt_token_creds") { - std::unique_ptr<Credentials> creds; - GPR_ASSERT(FLAGS_enable_ssl); - grpc::string json_key = GetServiceAccountJsonKey(); - creds = JWTCredentials(json_key, 3600); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else { - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots); - } -} - -void AssertOkOrPrintErrorStatus(const grpc::Status& s) { - if (s.IsOk()) { - return; - } - gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(), - s.details().c_str()); - GPR_ASSERT(0); -} - -void DoEmpty() { - gpr_log(GPR_INFO, "Sending an empty rpc..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("empty_unary"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::testing::Empty request = grpc::testing::Empty::default_instance(); - grpc::testing::Empty response = grpc::testing::Empty::default_instance(); - ClientContext context; - - grpc::Status s = stub->EmptyCall(&context, request, &response); - AssertOkOrPrintErrorStatus(s); - - gpr_log(GPR_INFO, "Empty rpc done."); -} - -// Shared code to set large payload, make rpc and check response payload. -void PerformLargeUnary(std::shared_ptr<ChannelInterface> channel, - SimpleRequest* request, SimpleResponse* response) { - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - ClientContext context; - request->set_response_type(grpc::testing::PayloadType::COMPRESSABLE); - request->set_response_size(kLargeResponseSize); - grpc::string payload(kLargeRequestSize, '\0'); - request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize); - - grpc::Status s = stub->UnaryCall(&context, *request, response); - - AssertOkOrPrintErrorStatus(s); - GPR_ASSERT(response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE); - GPR_ASSERT(response->payload().body() == - grpc::string(kLargeResponseSize, '\0')); -} - -void DoComputeEngineCreds() { - gpr_log(GPR_INFO, - "Sending a large unary rpc with compute engine credentials ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("compute_engine_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - request.set_fill_oauth_scope(true); - PerformLargeUnary(channel, &request, &response); - gpr_log(GPR_INFO, "Got username %s", response.username().c_str()); - gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str()); - GPR_ASSERT(!response.username().empty()); - GPR_ASSERT(response.username().c_str() == FLAGS_default_service_account); - GPR_ASSERT(!response.oauth_scope().empty()); - const char* oauth_scope_str = response.oauth_scope().c_str(); - GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with compute engine creds done."); -} - -void DoServiceAccountCreds() { - gpr_log(GPR_INFO, - "Sending a large unary rpc with service account credentials ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("service_account_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - request.set_fill_oauth_scope(true); - PerformLargeUnary(channel, &request, &response); - GPR_ASSERT(!response.username().empty()); - GPR_ASSERT(!response.oauth_scope().empty()); - grpc::string json_key = GetServiceAccountJsonKey(); - GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos); - const char* oauth_scope_str = response.oauth_scope().c_str(); - GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with service account creds done."); -} - -void DoJwtTokenCreds() { - gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("jwt_token_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - PerformLargeUnary(channel, &request, &response); - GPR_ASSERT(!response.username().empty()); - grpc::string json_key = GetServiceAccountJsonKey(); - GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with JWT token creds done."); -} - -void DoLargeUnary() { - gpr_log(GPR_INFO, "Sending a large unary rpc..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("large_unary"); - SimpleRequest request; - SimpleResponse response; - PerformLargeUnary(channel, &request, &response); - gpr_log(GPR_INFO, "Large unary done."); -} - -void DoRequestStreaming() { - gpr_log(GPR_INFO, "Sending request steaming rpc ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("client_streaming"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingInputCallRequest request; - StreamingInputCallResponse response; - - std::unique_ptr<grpc::ClientWriter<StreamingInputCallRequest>> stream( - stub->StreamingInputCall(&context, &response)); - - int aggregated_payload_size = 0; - for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { - grpc::testing::Payload* payload = request.mutable_payload(); - payload->set_body(grpc::string(request_stream_sizes[i], '\0')); - GPR_ASSERT(stream->Write(request)); - aggregated_payload_size += request_stream_sizes[i]; - } - stream->WritesDone(); - grpc::Status s = stream->Finish(); - - GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Request streaming done."); -} - -void DoResponseStreaming() { - gpr_log(GPR_INFO, "Receiving response steaming rpc ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("server_streaming"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingOutputCallRequest request; - for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { - ResponseParameters* response_parameter = request.add_response_parameters(); - response_parameter->set_size(response_stream_sizes[i]); - } - StreamingOutputCallResponse response; - std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream( - stub->StreamingOutputCall(&context, request)); - - unsigned int i = 0; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - ++i; - } - GPR_ASSERT(response_stream_sizes.size() == i); - grpc::Status s = stream->Finish(); - - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Response streaming done."); -} - -void DoResponseStreamingWithSlowConsumer() { - gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("slow_consumer"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingOutputCallRequest request; - - for (int i = 0; i < kNumResponseMessages; ++i) { - ResponseParameters* response_parameter = request.add_response_parameters(); - response_parameter->set_size(kResponseMessageSize); - } - StreamingOutputCallResponse response; - std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream( - stub->StreamingOutputCall(&context, request)); - - int i = 0; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().body() == - grpc::string(kResponseMessageSize, '\0')); - gpr_log(GPR_INFO, "received message %d", i); - usleep(kReceiveDelayMilliSeconds * 1000); - ++i; - } - GPR_ASSERT(kNumResponseMessages == i); - grpc::Status s = stream->Finish(); - - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Response streaming done."); -} - -void DoHalfDuplex() { - gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("half_duplex"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest, - StreamingOutputCallResponse>> - stream(stub->HalfDuplexCall(&context)); - - StreamingOutputCallRequest request; - ResponseParameters* response_parameter = request.add_response_parameters(); - for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { - response_parameter->set_size(response_stream_sizes[i]); - GPR_ASSERT(stream->Write(request)); - } - stream->WritesDone(); - - unsigned int i = 0; - StreamingOutputCallResponse response; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().has_body()); - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - ++i; - } - GPR_ASSERT(response_stream_sizes.size() == i); - grpc::Status s = stream->Finish(); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Half-duplex streaming rpc done."); -} - -void DoPingPong() { - gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ..."); - std::shared_ptr<ChannelInterface> channel = - CreateChannelForTestCase("ping_pong"); - std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest, - StreamingOutputCallResponse>> - stream(stub->FullDuplexCall(&context)); - - StreamingOutputCallRequest request; - request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE); - ResponseParameters* response_parameter = request.add_response_parameters(); - grpc::testing::Payload* payload = request.mutable_payload(); - StreamingOutputCallResponse response; - for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { - response_parameter->set_size(response_stream_sizes[i]); - payload->set_body(grpc::string(request_stream_sizes[i], '\0')); - GPR_ASSERT(stream->Write(request)); - GPR_ASSERT(stream->Read(&response)); - GPR_ASSERT(response.payload().has_body()); - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - } - - stream->WritesDone(); - GPR_ASSERT(!stream->Read(&response)); - grpc::Status s = stream->Finish(); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Ping pong streaming done."); -} - int main(int argc, char** argv) { grpc_init(); ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InteropClient client( + CreateChannelForTestCase(FLAGS_test_case)); if (FLAGS_test_case == "empty_unary") { - DoEmpty(); + client.DoEmpty(); } else if (FLAGS_test_case == "large_unary") { - DoLargeUnary(); + client.DoLargeUnary(); } else if (FLAGS_test_case == "client_streaming") { - DoRequestStreaming(); + client.DoRequestStreaming(); } else if (FLAGS_test_case == "server_streaming") { - DoResponseStreaming(); + client.DoResponseStreaming(); } else if (FLAGS_test_case == "slow_consumer") { - DoResponseStreamingWithSlowConsumer(); + client.DoResponseStreamingWithSlowConsumer(); } else if (FLAGS_test_case == "half_duplex") { - DoHalfDuplex(); + client.DoHalfDuplex(); } else if (FLAGS_test_case == "ping_pong") { - DoPingPong(); + client.DoPingPong(); } else if (FLAGS_test_case == "service_account_creds") { - DoServiceAccountCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope); } else if (FLAGS_test_case == "compute_engine_creds") { - DoComputeEngineCreds(); + client.DoComputeEngineCreds(FLAGS_default_service_account, + FLAGS_oauth_scope); } else if (FLAGS_test_case == "jwt_token_creds") { - DoJwtTokenCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoJwtTokenCreds(json_key); } else if (FLAGS_test_case == "all") { - DoEmpty(); - DoLargeUnary(); - DoRequestStreaming(); - DoResponseStreaming(); - DoHalfDuplex(); - DoPingPong(); + client.DoEmpty(); + client.DoLargeUnary(); + client.DoRequestStreaming(); + client.DoResponseStreaming(); + client.DoHalfDuplex(); + client.DoPingPong(); // service_account_creds and jwt_token_creds can only run with ssl. if (FLAGS_enable_ssl) { - DoServiceAccountCreds(); - DoJwtTokenCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope); + client.DoJwtTokenCreds(json_key); } // compute_engine_creds only runs in GCE. } else { @@ -468,6 +133,7 @@ int main(int argc, char** argv) { "service_account_creds|compute_engine_creds|jwt_token_creds", FLAGS_test_case.c_str()); } + client.Reset(nullptr); grpc_shutdown(); return 0; diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc new file mode 100644 index 0000000000..909a17cb45 --- /dev/null +++ b/test/cpp/interop/client_helper.cc @@ -0,0 +1,121 @@ +/* + * + * Copyright 2015, 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/interop/client_helper.h" + +#include <fstream> +#include <memory> +#include <sstream> + +#include <unistd.h> + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <gflags/gflags.h> +#include <grpc++/channel_arguments.h> +#include <grpc++/channel_interface.h> +#include <grpc++/create_channel.h> +#include <grpc++/credentials.h> +#include <grpc++/stream.h> +#include "test/cpp/util/create_test_channel.h" + +DECLARE_bool(enable_ssl); +DECLARE_bool(use_prod_roots); +DECLARE_int32(server_port); +DECLARE_string(server_host); +DECLARE_string(server_host_override); +DECLARE_string(test_case); +DECLARE_string(default_service_account); +DECLARE_string(service_account_key_file); +DECLARE_string(oauth_scope); + +// In some distros, gflags is in the namespace google, and in some others, +// in gflags. This hack is enabling us to find both. +namespace google {} +namespace gflags {} +using namespace google; +using namespace gflags; + +namespace grpc { +namespace testing { + +grpc::string GetServiceAccountJsonKey() { + static grpc::string json_key; + if (json_key.empty()) { + std::ifstream json_key_file(FLAGS_service_account_key_file); + std::stringstream key_stream; + key_stream << json_key_file.rdbuf(); + json_key = key_stream.str(); + } + return json_key; +} + +std::shared_ptr<ChannelInterface> CreateChannelForTestCase( + const grpc::string& test_case) { + GPR_ASSERT(FLAGS_server_port); + const int host_port_buf_size = 1024; + char host_port[host_port_buf_size]; + snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), + FLAGS_server_port); + + if (test_case == "service_account_creds") { + std::unique_ptr<Credentials> creds; + GPR_ASSERT(FLAGS_enable_ssl); + grpc::string json_key = GetServiceAccountJsonKey(); + std::chrono::seconds token_lifetime = std::chrono::hours(1); + creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope, + token_lifetime.count()); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else if (test_case == "compute_engine_creds") { + std::unique_ptr<Credentials> creds; + GPR_ASSERT(FLAGS_enable_ssl); + creds = ComputeEngineCredentials(); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else if (test_case == "jwt_token_creds") { + std::unique_ptr<Credentials> creds; + GPR_ASSERT(FLAGS_enable_ssl); + grpc::string json_key = GetServiceAccountJsonKey(); + std::chrono::seconds token_lifetime = std::chrono::hours(1); + creds = JWTCredentials(json_key, token_lifetime.count()); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else { + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots); + } +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h new file mode 100644 index 0000000000..897f974026 --- /dev/null +++ b/test/cpp/interop/client_helper.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015, 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_INTEROP_CLIENT_HELPER_H +#define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H + +#include <memory> + +#include <grpc++/config.h> +#include <grpc++/channel_interface.h> + +namespace grpc { +namespace testing { + +grpc::string GetServiceAccountJsonKey(); + +std::shared_ptr<ChannelInterface> CreateChannelForTestCase( + const grpc::string& test_case); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc new file mode 100644 index 0000000000..fd9c2e024a --- /dev/null +++ b/test/cpp/interop/interop_client.cc @@ -0,0 +1,311 @@ +/* + * + * Copyright 2015, 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/interop/interop_client.h" + +#include <memory> + +#include <unistd.h> + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <grpc++/channel_interface.h> +#include <grpc++/client_context.h> +#include <grpc++/status.h> +#include <grpc++/stream.h> +#include "test/cpp/interop/test.grpc.pb.h" +#include "test/cpp/interop/empty.grpc.pb.h" +#include "test/cpp/interop/messages.grpc.pb.h" + +namespace grpc { +namespace testing { + +namespace { +// The same value is defined by the Java client. +const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904}; +const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979}; +const int kNumResponseMessages = 2000; +const int kResponseMessageSize = 1030; +const int kReceiveDelayMilliSeconds = 20; +const int kLargeRequestSize = 314159; +const int kLargeResponseSize = 271812; +} // namespace + +InteropClient::InteropClient(std::shared_ptr<ChannelInterface> channel) + : channel_(channel) {} + +void InteropClient::AssertOkOrPrintErrorStatus(const Status& s) { + if (s.IsOk()) { + return; + } + gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(), + s.details().c_str()); + GPR_ASSERT(0); +} + +void InteropClient::DoEmpty() { + gpr_log(GPR_INFO, "Sending an empty rpc..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + Empty request = Empty::default_instance(); + Empty response = Empty::default_instance(); + ClientContext context; + + Status s = stub->EmptyCall(&context, request, &response); + AssertOkOrPrintErrorStatus(s); + + gpr_log(GPR_INFO, "Empty rpc done."); +} + +// Shared code to set large payload, make rpc and check response payload. +void InteropClient::PerformLargeUnary(SimpleRequest* request, + SimpleResponse* response) { + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + request->set_response_type(PayloadType::COMPRESSABLE); + request->set_response_size(kLargeResponseSize); + grpc::string payload(kLargeRequestSize, '\0'); + request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize); + + Status s = stub->UnaryCall(&context, *request, response); + + AssertOkOrPrintErrorStatus(s); + GPR_ASSERT(response->payload().type() == PayloadType::COMPRESSABLE); + GPR_ASSERT(response->payload().body() == + grpc::string(kLargeResponseSize, '\0')); +} + +void InteropClient::DoComputeEngineCreds( + const grpc::string& default_service_account, + const grpc::string& oauth_scope) { + gpr_log(GPR_INFO, + "Sending a large unary rpc with compute engine credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + request.set_fill_oauth_scope(true); + PerformLargeUnary(&request, &response); + gpr_log(GPR_INFO, "Got username %s", response.username().c_str()); + gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str()); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(response.username().c_str() == default_service_account); + GPR_ASSERT(!response.oauth_scope().empty()); + const char* oauth_scope_str = response.oauth_scope().c_str(); + GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with compute engine creds done."); +} + +void InteropClient::DoServiceAccountCreds(const grpc::string& username, + const grpc::string& oauth_scope) { + gpr_log(GPR_INFO, + "Sending a large unary rpc with service account credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + request.set_fill_oauth_scope(true); + PerformLargeUnary(&request, &response); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(!response.oauth_scope().empty()); + GPR_ASSERT(username.find(response.username()) != grpc::string::npos); + const char* oauth_scope_str = response.oauth_scope().c_str(); + GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with service account creds done."); +} + +void InteropClient::DoJwtTokenCreds(const grpc::string& username) { + gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + PerformLargeUnary(&request, &response); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(username.find(response.username()) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with JWT token creds done."); +} + +void InteropClient::DoLargeUnary() { + gpr_log(GPR_INFO, "Sending a large unary rpc..."); + SimpleRequest request; + SimpleResponse response; + PerformLargeUnary(&request, &response); + gpr_log(GPR_INFO, "Large unary done."); +} + +void InteropClient::DoRequestStreaming() { + gpr_log(GPR_INFO, "Sending request steaming rpc ..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingInputCallRequest request; + StreamingInputCallResponse response; + + std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream( + stub->StreamingInputCall(&context, &response)); + + int aggregated_payload_size = 0; + for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { + Payload* payload = request.mutable_payload(); + payload->set_body(grpc::string(request_stream_sizes[i], '\0')); + GPR_ASSERT(stream->Write(request)); + aggregated_payload_size += request_stream_sizes[i]; + } + stream->WritesDone(); + Status s = stream->Finish(); + + GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Request streaming done."); +} + +void InteropClient::DoResponseStreaming() { + gpr_log(GPR_INFO, "Receiving response steaming rpc ..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingOutputCallRequest request; + for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { + ResponseParameters* response_parameter = request.add_response_parameters(); + response_parameter->set_size(response_stream_sizes[i]); + } + StreamingOutputCallResponse response; + std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream( + stub->StreamingOutputCall(&context, request)); + + unsigned int i = 0; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + ++i; + } + GPR_ASSERT(response_stream_sizes.size() == i); + Status s = stream->Finish(); + + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Response streaming done."); +} + +void InteropClient::DoResponseStreamingWithSlowConsumer() { + gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingOutputCallRequest request; + + for (int i = 0; i < kNumResponseMessages; ++i) { + ResponseParameters* response_parameter = request.add_response_parameters(); + response_parameter->set_size(kResponseMessageSize); + } + StreamingOutputCallResponse response; + std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream( + stub->StreamingOutputCall(&context, request)); + + int i = 0; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().body() == + grpc::string(kResponseMessageSize, '\0')); + gpr_log(GPR_INFO, "received message %d", i); + usleep(kReceiveDelayMilliSeconds * 1000); + ++i; + } + GPR_ASSERT(kNumResponseMessages == i); + Status s = stream->Finish(); + + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Response streaming done."); +} + +void InteropClient::DoHalfDuplex() { + gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest, + StreamingOutputCallResponse>> + stream(stub->HalfDuplexCall(&context)); + + StreamingOutputCallRequest request; + ResponseParameters* response_parameter = request.add_response_parameters(); + for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { + response_parameter->set_size(response_stream_sizes[i]); + GPR_ASSERT(stream->Write(request)); + } + stream->WritesDone(); + + unsigned int i = 0; + StreamingOutputCallResponse response; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().has_body()); + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + ++i; + } + GPR_ASSERT(response_stream_sizes.size() == i); + Status s = stream->Finish(); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Half-duplex streaming rpc done."); +} + +void InteropClient::DoPingPong() { + gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ..."); + std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); + + ClientContext context; + std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest, + StreamingOutputCallResponse>> + stream(stub->FullDuplexCall(&context)); + + StreamingOutputCallRequest request; + request.set_response_type(PayloadType::COMPRESSABLE); + ResponseParameters* response_parameter = request.add_response_parameters(); + Payload* payload = request.mutable_payload(); + StreamingOutputCallResponse response; + for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { + response_parameter->set_size(response_stream_sizes[i]); + payload->set_body(grpc::string(request_stream_sizes[i], '\0')); + GPR_ASSERT(stream->Write(request)); + GPR_ASSERT(stream->Read(&response)); + GPR_ASSERT(response.payload().has_body()); + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + } + + stream->WritesDone(); + GPR_ASSERT(!stream->Read(&response)); + Status s = stream->Finish(); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Ping pong streaming done."); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h new file mode 100644 index 0000000000..b0ab320f8d --- /dev/null +++ b/test/cpp/interop/interop_client.h @@ -0,0 +1,79 @@ +/* + * + * Copyright 2015, 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_INTEROP_INTEROP_CLIENT_H +#define GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H +#include <memory> + +#include <grpc/grpc.h> +#include <grpc++/channel_interface.h> +#include <grpc++/status.h> +#include "test/cpp/interop/messages.grpc.pb.h" + +namespace grpc { +namespace testing { + +class InteropClient { + public: + explicit InteropClient(std::shared_ptr<ChannelInterface> channel); + ~InteropClient() {} + + void Reset(std::shared_ptr<ChannelInterface> channel) { channel_ = channel; } + + void DoEmpty(); + void DoLargeUnary(); + void DoPingPong(); + void DoHalfDuplex(); + void DoRequestStreaming(); + void DoResponseStreaming(); + void DoResponseStreamingWithSlowConsumer(); + // Auth tests. + // username is a string containing the user email + void DoJwtTokenCreds(const grpc::string& username); + void DoComputeEngineCreds(const grpc::string& default_service_account, + const grpc::string& oauth_scope); + // username is a string containing the user email + void DoServiceAccountCreds(const grpc::string& username, + const grpc::string& oauth_scope); + + private: + void PerformLargeUnary(SimpleRequest* request, SimpleResponse* response); + void AssertOkOrPrintErrorStatus(const Status& s); + + std::shared_ptr<ChannelInterface> channel_; +}; + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc index 780a7370ac..d87493b813 100644 --- a/test/cpp/interop/server.cc +++ b/test/cpp/interop/server.cc @@ -41,7 +41,6 @@ #include <gflags/gflags.h> #include <grpc/grpc.h> #include <grpc/support/log.h> -#include "test/core/end2end/data/ssl_test_data.h" #include <grpc++/config.h> #include <grpc++/server.h> #include <grpc++/server_builder.h> @@ -49,9 +48,10 @@ #include <grpc++/server_credentials.h> #include <grpc++/status.h> #include <grpc++/stream.h> -#include "test/cpp/interop/test.pb.h" -#include "test/cpp/interop/empty.pb.h" -#include "test/cpp/interop/messages.pb.h" +#include "test/cpp/interop/test.grpc.pb.h" +#include "test/cpp/interop/empty.grpc.pb.h" +#include "test/cpp/interop/messages.grpc.pb.h" +#include "test/cpp/interop/server_helper.h" DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls."); DEFINE_int32(port, 0, "Server port."); @@ -211,15 +211,8 @@ void RunServer() { ServerBuilder builder; builder.RegisterService(&service); - std::shared_ptr<ServerCredentials> creds = grpc::InsecureServerCredentials(); - if (FLAGS_enable_ssl) { - 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); - creds = grpc::SslServerCredentials(ssl_opts); - } + std::shared_ptr<ServerCredentials> creds = + grpc::testing::CreateInteropServerCredentials(); builder.AddListeningPort(server_address.str(), creds); std::unique_ptr<Server> server(builder.BuildAndStart()); gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str()); diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc new file mode 100644 index 0000000000..56597c83c4 --- /dev/null +++ b/test/cpp/interop/server_helper.cc @@ -0,0 +1,69 @@ +/* + * + * Copyright 2015, 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/interop/server_helper.h" + +#include <memory> + +#include <gflags/gflags.h> +#include "test/core/end2end/data/ssl_test_data.h" +#include <grpc++/config.h> +#include <grpc++/server_credentials.h> + +DECLARE_bool(enable_ssl); + +// In some distros, gflags is in the namespace google, and in some others, +// in gflags. This hack is enabling us to find both. +namespace google {} +namespace gflags {} +using namespace google; +using namespace gflags; + +namespace grpc { +namespace testing { + +std::shared_ptr<ServerCredentials> CreateInteropServerCredentials() { + if (FLAGS_enable_ssl) { + 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 { + return InsecureServerCredentials(); + } +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h new file mode 100644 index 0000000000..f98e67bb67 --- /dev/null +++ b/test/cpp/interop/server_helper.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, 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_INTEROP_SERVER_HELPER_H +#define GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H + +#include <memory> + +#include <grpc++/server_credentials.h> + +namespace grpc { +namespace testing { + +std::shared_ptr<ServerCredentials> CreateInteropServerCredentials(); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index cae7f44537..2dc5b3860f 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -36,7 +36,7 @@ #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/timer.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include <condition_variable> #include <mutex> @@ -104,7 +104,7 @@ class Client { void EndThreads() { threads_.clear(); } - virtual void ThreadFunc(Histogram* histogram, size_t thread_idx) = 0; + virtual bool ThreadFunc(Histogram* histogram, size_t thread_idx) = 0; private: class Thread { @@ -113,20 +113,24 @@ class Client { : done_(false), new_(nullptr), impl_([this, idx, client]() { - for (;;) { - // run the loop body - client->ThreadFunc(&histogram_, idx); - // lock, see if we're done - std::lock_guard<std::mutex> g(mu_); - if (done_) {return;} - // check if we're marking, swap out the histogram if so - if (new_) { - new_->Swap(&histogram_); - new_ = nullptr; - cv_.notify_one(); + for (;;) { + // run the loop body + bool thread_still_ok = client->ThreadFunc(&histogram_, idx); + // lock, see if we're done + std::lock_guard<std::mutex> g(mu_); + if (!thread_still_ok) { + gpr_log(GPR_ERROR, "Finishing client thread due to RPC error"); + done_ = true; + } + if (done_) {return;} + // check if we're marking, swap out the histogram if so + if (new_) { + new_->Swap(&histogram_); + new_ = nullptr; + cv_.notify_one(); + } } - } - }) {} + }) {} ~Thread() { { diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index 1ed3c7157f..0a6d9beeca 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -48,7 +48,7 @@ #include <grpc++/status.h> #include <grpc++/stream.h> #include "test/cpp/util/create_test_channel.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/timer.h" #include "test/cpp/qps/client.h" @@ -137,13 +137,7 @@ class AsyncUnaryClient GRPC_FINAL : public Client { cli_cqs_.emplace_back(new CompletionQueue); } - auto payload_size = config.payload_size(); - auto check_done = [payload_size](grpc::Status s, SimpleResponse* response) { - GPR_ASSERT(s.IsOk() && (response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE) && - (response->payload().body().length() == - static_cast<size_t>(payload_size))); - }; + auto check_done = [](grpc::Status s, SimpleResponse* response) {}; int t = 0; for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) { @@ -179,10 +173,14 @@ class AsyncUnaryClient GRPC_FINAL : public Client { } } - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { void* got_tag; bool ok; - cli_cqs_[thread_idx]->Next(&got_tag, &ok); + switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) { + case CompletionQueue::SHUTDOWN: return false; + case CompletionQueue::TIMEOUT: return true; + case CompletionQueue::GOT_EVENT: break; + } ClientRpcContext* ctx = ClientRpcContext::detag(got_tag); if (ctx->RunNextState(ok, histogram) == false) { @@ -191,6 +189,8 @@ class AsyncUnaryClient GRPC_FINAL : public Client { ctx->StartNewClone(); delete ctx; } + + return true; } std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_; @@ -270,13 +270,7 @@ class AsyncStreamingClient GRPC_FINAL : public Client { cli_cqs_.emplace_back(new CompletionQueue); } - auto payload_size = config.payload_size(); - auto check_done = [payload_size](grpc::Status s, SimpleResponse *response) { - GPR_ASSERT(s.IsOk() && (response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE) && - (response->payload().body().length() == - static_cast<size_t>(payload_size))); - }; + auto check_done = [](grpc::Status s, SimpleResponse* response) {}; int t = 0; for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) { @@ -313,10 +307,14 @@ class AsyncStreamingClient GRPC_FINAL : public Client { } } - void ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE { void *got_tag; bool ok; - cli_cqs_[thread_idx]->Next(&got_tag, &ok); + switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) { + case CompletionQueue::SHUTDOWN: return false; + case CompletionQueue::TIMEOUT: return true; + case CompletionQueue::GOT_EVENT: break; + } ClientRpcContext *ctx = ClientRpcContext::detag(got_tag); if (ctx->RunNextState(ok, histogram) == false) { @@ -325,6 +323,8 @@ class AsyncStreamingClient GRPC_FINAL : public Client { ctx->StartNewClone(); delete ctx; } + + return true; } std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_; diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index 77da1725ff..aea5a0fb27 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -55,7 +55,7 @@ #include <gtest/gtest.h> #include "test/cpp/util/create_test_channel.h" #include "test/cpp/qps/client.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/timer.h" @@ -83,13 +83,14 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient { SynchronousClient(config) {StartThreads(num_threads_);} ~SynchronousUnaryClient() {} - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); double start = Timer::Now(); grpc::ClientContext context; grpc::Status s = stub->UnaryCall(&context, request_, &responses_[thread_idx]); histogram->Add((Timer::Now() - start) * 1e9); + return s.IsOk(); } }; @@ -111,11 +112,13 @@ class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient { } } - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { double start = Timer::Now(); - EXPECT_TRUE(stream_->Write(request_)); - EXPECT_TRUE(stream_->Read(&responses_[thread_idx])); - histogram->Add((Timer::Now() - start) * 1e9); + if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) { + histogram->Add((Timer::Now() - start) * 1e9); + return true; + } + return false; } private: grpc::ClientContext context_; diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 64a53496ae..f44883783d 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -74,7 +74,9 @@ static vector<string> get_hosts(const string& name) { ScenarioResult RunScenario(const ClientConfig& initial_client_config, size_t num_clients, const ServerConfig& server_config, - size_t num_servers) { + size_t num_servers, + int warmup_seconds, + int benchmark_seconds) { // ClientContext allocator (all are destroyed at scope exit) list<ClientContext> contexts; auto alloc_context = [&contexts]() { @@ -146,7 +148,7 @@ ScenarioResult RunScenario(const ClientConfig& initial_client_config, // Let everything warmup gpr_log(GPR_INFO, "Warming up"); gpr_timespec start = gpr_now(); - gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(5))); + gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(warmup_seconds))); // Start a run gpr_log(GPR_INFO, "Starting"); @@ -171,7 +173,7 @@ ScenarioResult RunScenario(const ClientConfig& initial_client_config, // Wait some time gpr_log(GPR_INFO, "Running"); - gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(15))); + gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(benchmark_seconds))); // Finish a run ScenarioResult result; diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index d87e80dc55..b3a8bf8cc4 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -35,7 +35,7 @@ #define TEST_QPS_DRIVER_H #include "test/cpp/qps/histogram.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { @@ -54,7 +54,10 @@ struct ScenarioResult { ScenarioResult RunScenario(const grpc::testing::ClientConfig& client_config, size_t num_clients, const grpc::testing::ServerConfig& server_config, - size_t num_servers); + size_t num_servers, + int warmup_seconds, + int benchmark_seconds); + } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h index 7ba00e94c3..0547b7283a 100644 --- a/test/cpp/qps/histogram.h +++ b/test/cpp/qps/histogram.h @@ -35,7 +35,7 @@ #define TEST_QPS_HISTOGRAM_H #include <grpc/support/histogram.h> -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { @@ -50,10 +50,10 @@ class Histogram { void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); } void Add(double value) { gpr_histogram_add(impl_, value); } - double Percentile(double pctile) { + double Percentile(double pctile) const { return gpr_histogram_percentile(impl_, pctile); } - double Count() { return gpr_histogram_count(impl_); } + double Count() const { return gpr_histogram_count(impl_); } void Swap(Histogram* other) { std::swap(impl_, other->impl_); } void FillProto(HistogramData* p) { size_t n; diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc index f7aa8e2aba..220f826118 100644 --- a/test/cpp/qps/qps_driver.cc +++ b/test/cpp/qps/qps_driver.cc @@ -35,11 +35,14 @@ #include <grpc/support/log.h> #include "test/cpp/qps/driver.h" -#include "test/cpp/qps/stats.h" +#include "test/cpp/qps/report.h" DEFINE_int32(num_clients, 1, "Number of client binaries"); DEFINE_int32(num_servers, 1, "Number of server binaries"); +DEFINE_int32(warmup_seconds, 5, "Warmup time (in seconds)"); +DEFINE_int32(benchmark_seconds, 30, "Benchmark time (in seconds)"); + // Common config DEFINE_bool(enable_ssl, false, "Use SSL"); DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING"); @@ -62,7 +65,6 @@ using grpc::testing::ClientType; using grpc::testing::ServerType; using grpc::testing::RpcType; using grpc::testing::ResourceUsage; -using grpc::testing::sum; // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. @@ -98,40 +100,13 @@ int main(int argc, char** argv) { server_config.set_threads(FLAGS_server_threads); server_config.set_enable_ssl(FLAGS_enable_ssl); - auto result = RunScenario(client_config, FLAGS_num_clients, server_config, - FLAGS_num_servers); - - gpr_log(GPR_INFO, "QPS: %.1f", - result.latencies.Count() / - average(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); - - gpr_log(GPR_INFO, "Latencies (50/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f us", - result.latencies.Percentile(50) / 1000, - result.latencies.Percentile(95) / 1000, - result.latencies.Percentile(99) / 1000, - result.latencies.Percentile(99.9) / 1000); - - gpr_log(GPR_INFO, "Server system time: %.2f%%", - 100.0 * sum(result.server_resources, - [](ResourceUsage u) { return u.system_time; }) / - sum(result.server_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Server user time: %.2f%%", - 100.0 * sum(result.server_resources, - [](ResourceUsage u) { return u.user_time; }) / - sum(result.server_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Client system time: %.2f%%", - 100.0 * sum(result.client_resources, - [](ResourceUsage u) { return u.system_time; }) / - sum(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Client user time: %.2f%%", - 100.0 * sum(result.client_resources, - [](ResourceUsage u) { return u.user_time; }) / - sum(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); + auto result = RunScenario(client_config, FLAGS_num_clients, + server_config, FLAGS_num_servers, + FLAGS_warmup_seconds, FLAGS_benchmark_seconds); + + ReportQPSPerCore(result, server_config); + ReportLatency(result); + ReportTimes(result); grpc_shutdown(); return 0; diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc new file mode 100644 index 0000000000..29d88da344 --- /dev/null +++ b/test/cpp/qps/report.cc @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015, 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/qps/report.h" + +#include <grpc/support/log.h> +#include "test/cpp/qps/stats.h" + +namespace grpc { +namespace testing { + +// QPS: XXX +void ReportQPS(const ScenarioResult& result) { + gpr_log(GPR_INFO, "QPS: %.1f", + result.latencies.Count() / + average(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); +} + +// QPS: XXX (YYY/server core) +void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& server_config) { + auto qps = + result.latencies.Count() / + average(result.client_resources, + [](ResourceUsage u) { return u.wall_time; }); + + gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps, qps/server_config.threads()); +} + +// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us +void ReportLatency(const ScenarioResult& result) { + gpr_log(GPR_INFO, "Latencies (50/90/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f/%.1f us", + result.latencies.Percentile(50) / 1000, + result.latencies.Percentile(90) / 1000, + result.latencies.Percentile(95) / 1000, + result.latencies.Percentile(99) / 1000, + result.latencies.Percentile(99.9) / 1000); +} + +void ReportTimes(const ScenarioResult& result) { + gpr_log(GPR_INFO, "Server system time: %.2f%%", + 100.0 * sum(result.server_resources, + [](ResourceUsage u) { return u.system_time; }) / + sum(result.server_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Server user time: %.2f%%", + 100.0 * sum(result.server_resources, + [](ResourceUsage u) { return u.user_time; }) / + sum(result.server_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Client system time: %.2f%%", + 100.0 * sum(result.client_resources, + [](ResourceUsage u) { return u.system_time; }) / + sum(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Client user time: %.2f%%", + 100.0 * sum(result.client_resources, + [](ResourceUsage u) { return u.user_time; }) / + sum(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h new file mode 100644 index 0000000000..343e426ca4 --- /dev/null +++ b/test/cpp/qps/report.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015, 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 TEST_QPS_REPORT_H +#define TEST_QPS_REPORT_H + +#include "test/cpp/qps/driver.h" + +namespace grpc { +namespace testing { + +// QPS: XXX +void ReportQPS(const ScenarioResult& result); +// QPS: XXX (YYY/server core) +void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& config); +// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us +void ReportLatency(const ScenarioResult& result); +// Server system time: XX% +// Server user time: XX% +// Client system time: XX% +// Client user time: XX% +void ReportTimes(const ScenarioResult& result); + +} // namespace testing +} // namespace grpc + +#endif diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index ef71cb94d0..68e0115410 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -35,7 +35,7 @@ #define TEST_QPS_SERVER_H #include "test/cpp/qps/timer.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 65c170af81..b19c443c82 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -52,7 +52,7 @@ #include <grpc++/stream.h> #include <gtest/gtest.h> #include "src/cpp/server/thread_pool.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" #include <grpc/grpc.h> @@ -97,15 +97,15 @@ class AsyncQpsServerTest : public Server { bool ok; void* got_tag; while (srv_cq_.Next(&got_tag, &ok)) { - ServerRpcContext* ctx = detag(got_tag); - // The tag is a pointer to an RPC context to invoke - if (ctx->RunNextState(ok) == false) { - // this RPC context is done, so refresh it + ServerRpcContext* ctx = detag(got_tag); + // The tag is a pointer to an RPC context to invoke + if (ctx->RunNextState(ok) == false) { + // this RPC context is done, so refresh it std::lock_guard<std::mutex> g(shutdown_mutex_); if (!shutdown_) { ctx->Reset(); } - } + } } return; })); @@ -175,8 +175,9 @@ class AsyncQpsServerTest : public Server { private: bool finisher(bool) { return false; } bool invoker(bool ok) { - if (!ok) - return false; + if (!ok) { + return false; + } ResponseType response; @@ -230,8 +231,9 @@ class AsyncQpsServerTest : public Server { private: bool request_done(bool ok) { - if (!ok) - return false; + if (!ok) { + return false; + } stream_.Read(&req_, AsyncQpsServerTest::tag(this)); next_state_ = &ServerRpcContextStreamingImpl::read_done; return true; diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index 9964429901..2770233a7c 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -47,7 +47,7 @@ #include <grpc++/status.h> #include <grpc++/stream.h> #include "src/cpp/server/thread_pool.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" #include "test/cpp/qps/timer.h" diff --git a/test/cpp/qps/smoke_test.cc b/test/cpp/qps/smoke_test.cc new file mode 100644 index 0000000000..c9d321f133 --- /dev/null +++ b/test/cpp/qps/smoke_test.cc @@ -0,0 +1,149 @@ +/* + * + * Copyright 2015, 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 <grpc/support/log.h> + +#include "test/cpp/qps/driver.h" +#include "test/cpp/qps/report.h" + +namespace grpc { +namespace testing { + +static const int WARMUP = 5; +static const int BENCHMARK = 10; + +static void RunSynchronousUnaryPingPong() { + gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(SYNCHRONOUS_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(SYNCHRONOUS_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunSynchronousStreamingPingPong() { + gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(SYNCHRONOUS_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_rpc_type(STREAMING); + + ServerConfig server_config; + server_config.set_server_type(SYNCHRONOUS_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunAsyncUnaryPingPong() { + gpr_log(GPR_INFO, "Running Async Unary Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(ASYNC_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_async_client_threads(1); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(ASYNC_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunQPS() { + gpr_log(GPR_INFO, "Running QPS test"); + + ClientConfig client_config; + client_config.set_client_type(ASYNC_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1000); + client_config.set_client_channels(8); + client_config.set_payload_size(1); + client_config.set_async_client_threads(8); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(ASYNC_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(4); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPSPerCore(result, server_config); + ReportLatency(result); +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_init(); + + using namespace grpc::testing; + RunSynchronousStreamingPingPong(); + RunSynchronousUnaryPingPong(); + RunAsyncUnaryPingPong(); + RunQPS(); + + grpc_shutdown(); + return 0; +} diff --git a/test/cpp/qps/smoke_test.sh b/test/cpp/qps/smoke_test.sh new file mode 100755 index 0000000000..ba7f0a4f27 --- /dev/null +++ b/test/cpp/qps/smoke_test.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# performs a single qps run with one client and one server + +set -ex + +cd $(dirname $0)/../../.. + +killall qps_worker || true + +config=opt + +NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count()'` + +make CONFIG=$config qps_worker qps_smoke_test -j$NUMCPUS + +bins/$config/qps_worker -driver_port 10000 -server_port 10001 & +PID1=$! +bins/$config/qps_worker -driver_port 10010 -server_port 10011 & +PID2=$! + +export QPS_WORKERS="localhost:10000,localhost:10010" + +bins/$config/qps_smoke_test $* + +kill -2 $PID1 $PID2 +wait + diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc index b6830cc055..101eb9f969 100644 --- a/test/cpp/qps/worker.cc +++ b/test/cpp/qps/worker.cc @@ -55,7 +55,7 @@ #include <grpc++/stream.h> #include "test/core/util/grpc_profiler.h" #include "test/cpp/util/create_test_channel.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/client.h" #include "test/cpp/qps/server.h" diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 91fc40c31f..32ef392cc4 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -33,7 +33,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/cli_call.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include "src/cpp/server/thread_pool.h" #include <grpc++/channel_arguments.h> #include <grpc++/channel_interface.h> |