aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/cpp
diff options
context:
space:
mode:
authorGravatar Nicolas "Pixel" Noble <pixel@nobis-crew.org>2015-04-11 01:27:32 +0200
committerGravatar Nicolas "Pixel" Noble <pixel@nobis-crew.org>2015-04-11 01:53:09 +0200
commitb7c2035e83a9b3e346f1fd37f9ad55c2070fb02e (patch)
tree6d4703d352f4f3204415d6785df52320d3d14a9b /test/cpp
parent27a0dc0208e90b6463049df16da6c35216eab0aa (diff)
parent05f2d9f8267d69bfeb60f52446385a1955eddd93 (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')
-rw-r--r--test/cpp/end2end/async_end2end_test.cc6
-rw-r--r--test/cpp/end2end/end2end_test.cc4
-rw-r--r--test/cpp/end2end/generic_end2end_test.cc2
-rw-r--r--test/cpp/interop/client.cc392
-rw-r--r--test/cpp/interop/client_helper.cc121
-rw-r--r--test/cpp/interop/client_helper.h53
-rw-r--r--test/cpp/interop/interop_client.cc311
-rw-r--r--test/cpp/interop/interop_client.h79
-rw-r--r--test/cpp/interop/server.cc19
-rw-r--r--test/cpp/interop/server_helper.cc69
-rw-r--r--test/cpp/interop/server_helper.h49
-rw-r--r--test/cpp/qps/client.h34
-rw-r--r--test/cpp/qps/client_async.cc38
-rw-r--r--test/cpp/qps/client_sync.cc15
-rw-r--r--test/cpp/qps/driver.cc8
-rw-r--r--test/cpp/qps/driver.h7
-rw-r--r--test/cpp/qps/histogram.h6
-rw-r--r--test/cpp/qps/qps_driver.cc47
-rw-r--r--test/cpp/qps/report.cc94
-rw-r--r--test/cpp/qps/report.h57
-rw-r--r--test/cpp/qps/server.h2
-rw-r--r--test/cpp/qps/server_async.cc22
-rw-r--r--test/cpp/qps/server_sync.cc2
-rw-r--r--test/cpp/qps/smoke_test.cc149
-rwxr-xr-xtest/cpp/qps/smoke_test.sh28
-rw-r--r--test/cpp/qps/worker.cc2
-rw-r--r--test/cpp/util/cli_call_test.cc2
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>