client.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #include <chrono>
  34. #include <fstream>
  35. #include <memory>
  36. #include <sstream>
  37. #include <string>
  38. #include <thread>
  39. #include <unistd.h>
  40. #include <grpc/grpc.h>
  41. #include <grpc/support/log.h>
  42. #include <gflags/gflags.h>
  43. #include <grpc++/channel_arguments.h>
  44. #include <grpc++/channel_interface.h>
  45. #include <grpc++/client_context.h>
  46. #include <grpc++/create_channel.h>
  47. #include <grpc++/credentials.h>
  48. #include <grpc++/status.h>
  49. #include <grpc++/stream.h>
  50. #include "test/cpp/util/create_test_channel.h"
  51. #include "test/cpp/interop/test.pb.h"
  52. #include "test/cpp/interop/empty.pb.h"
  53. #include "test/cpp/interop/messages.pb.h"
  54. DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
  55. DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google");
  56. DEFINE_int32(server_port, 0, "Server port.");
  57. DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
  58. DEFINE_string(server_host_override, "foo.test.google.fr",
  59. "Override the server host which is sent in HTTP header");
  60. DEFINE_string(test_case, "large_unary",
  61. "Configure different test cases. Valid options are: "
  62. "empty_unary : empty (zero bytes) request and response; "
  63. "large_unary : single request and (large) response; "
  64. "client_streaming : request streaming with single response; "
  65. "server_streaming : single request with response streaming; "
  66. "slow_consumer : single request with response; "
  67. " streaming with slow client consumer; "
  68. "half_duplex : half-duplex streaming; "
  69. "ping_pong : full-duplex streaming; "
  70. "service_account_creds : large_unary with service_account auth; "
  71. "compute_engine_creds: large_unary with compute engine auth; "
  72. "jwt_token_creds: large_unary with JWT token auth; "
  73. "all : all of above.");
  74. DEFINE_string(default_service_account, "",
  75. "Email of GCE default service account");
  76. DEFINE_string(service_account_key_file, "",
  77. "Path to service account json key file.");
  78. DEFINE_string(oauth_scope, "", "Scope for OAuth tokens.");
  79. using grpc::ChannelInterface;
  80. using grpc::ClientContext;
  81. using grpc::CreateTestChannel;
  82. using grpc::Credentials;
  83. using grpc::CredentialsFactory;
  84. using grpc::testing::ResponseParameters;
  85. using grpc::testing::SimpleRequest;
  86. using grpc::testing::SimpleResponse;
  87. using grpc::testing::StreamingInputCallRequest;
  88. using grpc::testing::StreamingInputCallResponse;
  89. using grpc::testing::StreamingOutputCallRequest;
  90. using grpc::testing::StreamingOutputCallResponse;
  91. using grpc::testing::TestService;
  92. // In some distros, gflags is in the namespace google, and in some others,
  93. // in gflags. This hack is enabling us to find both.
  94. namespace google { }
  95. namespace gflags { }
  96. using namespace google;
  97. using namespace gflags;
  98. namespace {
  99. // The same value is defined by the Java client.
  100. const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
  101. const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
  102. const int kNumResponseMessages = 2000;
  103. const int kResponseMessageSize = 1030;
  104. const int kReceiveDelayMilliSeconds = 20;
  105. const int kLargeRequestSize = 314159;
  106. const int kLargeResponseSize = 271812;
  107. } // namespace
  108. grpc::string GetServiceAccountJsonKey() {
  109. static grpc::string json_key;
  110. if (json_key.empty()) {
  111. std::ifstream json_key_file(FLAGS_service_account_key_file);
  112. std::stringstream key_stream;
  113. key_stream << json_key_file.rdbuf();
  114. json_key = key_stream.str();
  115. }
  116. return json_key;
  117. }
  118. std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
  119. const grpc::string& test_case) {
  120. GPR_ASSERT(FLAGS_server_port);
  121. const int host_port_buf_size = 1024;
  122. char host_port[host_port_buf_size];
  123. snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
  124. FLAGS_server_port);
  125. if (test_case == "service_account_creds") {
  126. std::unique_ptr<Credentials> creds;
  127. GPR_ASSERT(FLAGS_enable_ssl);
  128. grpc::string json_key = GetServiceAccountJsonKey();
  129. creds = CredentialsFactory::ServiceAccountCredentials(
  130. json_key, FLAGS_oauth_scope, std::chrono::hours(1));
  131. return CreateTestChannel(host_port, FLAGS_server_host_override,
  132. FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
  133. } else if (test_case == "compute_engine_creds") {
  134. std::unique_ptr<Credentials> creds;
  135. GPR_ASSERT(FLAGS_enable_ssl);
  136. creds = CredentialsFactory::ComputeEngineCredentials();
  137. return CreateTestChannel(host_port, FLAGS_server_host_override,
  138. FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
  139. } else if (test_case == "jwt_token_creds") {
  140. std::unique_ptr<Credentials> creds;
  141. GPR_ASSERT(FLAGS_enable_ssl);
  142. grpc::string json_key = GetServiceAccountJsonKey();
  143. creds = CredentialsFactory::JWTCredentials(json_key, std::chrono::hours(1));
  144. return CreateTestChannel(host_port, FLAGS_server_host_override,
  145. FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
  146. } else {
  147. return CreateTestChannel(host_port, FLAGS_server_host_override,
  148. FLAGS_enable_ssl, FLAGS_use_prod_roots);
  149. }
  150. }
  151. void DoEmpty() {
  152. gpr_log(GPR_INFO, "Sending an empty rpc...");
  153. std::shared_ptr<ChannelInterface> channel =
  154. CreateChannelForTestCase("empty_unary");
  155. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  156. grpc::testing::Empty request = grpc::testing::Empty::default_instance();
  157. grpc::testing::Empty response = grpc::testing::Empty::default_instance();
  158. ClientContext context;
  159. grpc::Status s = stub->EmptyCall(&context, request, &response);
  160. GPR_ASSERT(s.IsOk());
  161. gpr_log(GPR_INFO, "Empty rpc done.");
  162. }
  163. // Shared code to set large payload, make rpc and check response payload.
  164. void PerformLargeUnary(std::shared_ptr<ChannelInterface> channel,
  165. SimpleRequest* request, SimpleResponse* response) {
  166. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  167. ClientContext context;
  168. request->set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
  169. request->set_response_size(kLargeResponseSize);
  170. grpc::string payload(kLargeRequestSize, '\0');
  171. request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
  172. grpc::Status s = stub->UnaryCall(&context, *request, response);
  173. GPR_ASSERT(s.IsOk());
  174. GPR_ASSERT(response->payload().type() ==
  175. grpc::testing::PayloadType::COMPRESSABLE);
  176. GPR_ASSERT(response->payload().body() ==
  177. grpc::string(kLargeResponseSize, '\0'));
  178. }
  179. void DoComputeEngineCreds() {
  180. gpr_log(GPR_INFO,
  181. "Sending a large unary rpc with compute engine credentials ...");
  182. std::shared_ptr<ChannelInterface> channel =
  183. CreateChannelForTestCase("compute_engine_creds");
  184. SimpleRequest request;
  185. SimpleResponse response;
  186. request.set_fill_username(true);
  187. request.set_fill_oauth_scope(true);
  188. PerformLargeUnary(channel, &request, &response);
  189. gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
  190. gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
  191. GPR_ASSERT(!response.username().empty());
  192. GPR_ASSERT(response.username().c_str() == FLAGS_default_service_account);
  193. GPR_ASSERT(!response.oauth_scope().empty());
  194. const char *oauth_scope_str = response.oauth_scope().c_str();
  195. GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  196. gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
  197. }
  198. void DoServiceAccountCreds() {
  199. gpr_log(GPR_INFO,
  200. "Sending a large unary rpc with service account credentials ...");
  201. std::shared_ptr<ChannelInterface> channel =
  202. CreateChannelForTestCase("service_account_creds");
  203. SimpleRequest request;
  204. SimpleResponse response;
  205. request.set_fill_username(true);
  206. request.set_fill_oauth_scope(true);
  207. PerformLargeUnary(channel, &request, &response);
  208. GPR_ASSERT(!response.username().empty());
  209. GPR_ASSERT(!response.oauth_scope().empty());
  210. grpc::string json_key = GetServiceAccountJsonKey();
  211. GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
  212. const char *oauth_scope_str = response.oauth_scope().c_str();
  213. GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  214. gpr_log(GPR_INFO, "Large unary with service account creds done.");
  215. }
  216. void DoJwtTokenCreds() {
  217. gpr_log(GPR_INFO,
  218. "Sending a large unary rpc with JWT token credentials ...");
  219. std::shared_ptr<ChannelInterface> channel =
  220. CreateChannelForTestCase("jwt_token_creds");
  221. SimpleRequest request;
  222. SimpleResponse response;
  223. request.set_fill_username(true);
  224. PerformLargeUnary(channel, &request, &response);
  225. GPR_ASSERT(!response.username().empty());
  226. grpc::string json_key = GetServiceAccountJsonKey();
  227. GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
  228. gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
  229. }
  230. void DoLargeUnary() {
  231. gpr_log(GPR_INFO, "Sending a large unary rpc...");
  232. std::shared_ptr<ChannelInterface> channel =
  233. CreateChannelForTestCase("large_unary");
  234. SimpleRequest request;
  235. SimpleResponse response;
  236. PerformLargeUnary(channel, &request, &response);
  237. gpr_log(GPR_INFO, "Large unary done.");
  238. }
  239. void DoRequestStreaming() {
  240. gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  241. std::shared_ptr<ChannelInterface> channel =
  242. CreateChannelForTestCase("client_streaming");
  243. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  244. grpc::ClientContext context;
  245. StreamingInputCallRequest request;
  246. StreamingInputCallResponse response;
  247. std::unique_ptr<grpc::ClientWriter<StreamingInputCallRequest>> stream(
  248. stub->StreamingInputCall(&context, &response));
  249. int aggregated_payload_size = 0;
  250. for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
  251. grpc::testing::Payload* payload = request.mutable_payload();
  252. payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
  253. GPR_ASSERT(stream->Write(request));
  254. aggregated_payload_size += request_stream_sizes[i];
  255. }
  256. stream->WritesDone();
  257. grpc::Status s = stream->Finish();
  258. GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
  259. GPR_ASSERT(s.IsOk());
  260. gpr_log(GPR_INFO, "Request streaming done.");
  261. }
  262. void DoResponseStreaming() {
  263. gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
  264. std::shared_ptr<ChannelInterface> channel =
  265. CreateChannelForTestCase("server_streaming");
  266. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  267. grpc::ClientContext context;
  268. StreamingOutputCallRequest request;
  269. for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
  270. ResponseParameters* response_parameter = request.add_response_parameters();
  271. response_parameter->set_size(response_stream_sizes[i]);
  272. }
  273. StreamingOutputCallResponse response;
  274. std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
  275. stub->StreamingOutputCall(&context, request));
  276. unsigned int i = 0;
  277. while (stream->Read(&response)) {
  278. GPR_ASSERT(response.payload().body() ==
  279. grpc::string(response_stream_sizes[i], '\0'));
  280. ++i;
  281. }
  282. GPR_ASSERT(response_stream_sizes.size() == i);
  283. grpc::Status s = stream->Finish();
  284. GPR_ASSERT(s.IsOk());
  285. gpr_log(GPR_INFO, "Response streaming done.");
  286. }
  287. void DoResponseStreamingWithSlowConsumer() {
  288. gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
  289. std::shared_ptr<ChannelInterface> channel =
  290. CreateChannelForTestCase("slow_consumer");
  291. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  292. grpc::ClientContext context;
  293. StreamingOutputCallRequest request;
  294. for (int i = 0; i < kNumResponseMessages; ++i) {
  295. ResponseParameters* response_parameter = request.add_response_parameters();
  296. response_parameter->set_size(kResponseMessageSize);
  297. }
  298. StreamingOutputCallResponse response;
  299. std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
  300. stub->StreamingOutputCall(&context, request));
  301. int i = 0;
  302. while (stream->Read(&response)) {
  303. GPR_ASSERT(response.payload().body() ==
  304. grpc::string(kResponseMessageSize, '\0'));
  305. gpr_log(GPR_INFO, "received message %d", i);
  306. usleep(kReceiveDelayMilliSeconds * 1000);
  307. ++i;
  308. }
  309. GPR_ASSERT(kNumResponseMessages == i);
  310. grpc::Status s = stream->Finish();
  311. GPR_ASSERT(s.IsOk());
  312. gpr_log(GPR_INFO, "Response streaming done.");
  313. }
  314. void DoHalfDuplex() {
  315. gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
  316. std::shared_ptr<ChannelInterface> channel =
  317. CreateChannelForTestCase("half_duplex");
  318. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  319. grpc::ClientContext context;
  320. std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
  321. StreamingOutputCallResponse>>
  322. stream(stub->HalfDuplexCall(&context));
  323. StreamingOutputCallRequest request;
  324. ResponseParameters* response_parameter = request.add_response_parameters();
  325. for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
  326. response_parameter->set_size(response_stream_sizes[i]);
  327. GPR_ASSERT(stream->Write(request));
  328. }
  329. stream->WritesDone();
  330. unsigned int i = 0;
  331. StreamingOutputCallResponse response;
  332. while (stream->Read(&response)) {
  333. GPR_ASSERT(response.payload().has_body());
  334. GPR_ASSERT(response.payload().body() ==
  335. grpc::string(response_stream_sizes[i], '\0'));
  336. ++i;
  337. }
  338. GPR_ASSERT(response_stream_sizes.size() == i);
  339. grpc::Status s = stream->Finish();
  340. GPR_ASSERT(s.IsOk());
  341. gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
  342. }
  343. void DoPingPong() {
  344. gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  345. std::shared_ptr<ChannelInterface> channel =
  346. CreateChannelForTestCase("ping_pong");
  347. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  348. grpc::ClientContext context;
  349. std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
  350. StreamingOutputCallResponse>>
  351. stream(stub->FullDuplexCall(&context));
  352. StreamingOutputCallRequest request;
  353. request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
  354. ResponseParameters* response_parameter = request.add_response_parameters();
  355. grpc::testing::Payload* payload = request.mutable_payload();
  356. StreamingOutputCallResponse response;
  357. for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
  358. response_parameter->set_size(response_stream_sizes[i]);
  359. payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
  360. GPR_ASSERT(stream->Write(request));
  361. GPR_ASSERT(stream->Read(&response));
  362. GPR_ASSERT(response.payload().has_body());
  363. GPR_ASSERT(response.payload().body() ==
  364. grpc::string(response_stream_sizes[i], '\0'));
  365. }
  366. stream->WritesDone();
  367. GPR_ASSERT(!stream->Read(&response));
  368. grpc::Status s = stream->Finish();
  369. GPR_ASSERT(s.IsOk());
  370. gpr_log(GPR_INFO, "Ping pong streaming done.");
  371. }
  372. int main(int argc, char** argv) {
  373. grpc_init();
  374. ParseCommandLineFlags(&argc, &argv, true);
  375. if (FLAGS_test_case == "empty_unary") {
  376. DoEmpty();
  377. } else if (FLAGS_test_case == "large_unary") {
  378. DoLargeUnary();
  379. } else if (FLAGS_test_case == "client_streaming") {
  380. DoRequestStreaming();
  381. } else if (FLAGS_test_case == "server_streaming") {
  382. DoResponseStreaming();
  383. } else if (FLAGS_test_case == "slow_consumer") {
  384. DoResponseStreamingWithSlowConsumer();
  385. } else if (FLAGS_test_case == "half_duplex") {
  386. DoHalfDuplex();
  387. } else if (FLAGS_test_case == "ping_pong") {
  388. DoPingPong();
  389. } else if (FLAGS_test_case == "service_account_creds") {
  390. DoServiceAccountCreds();
  391. } else if (FLAGS_test_case == "compute_engine_creds") {
  392. DoComputeEngineCreds();
  393. } else if (FLAGS_test_case == "jwt_token_creds") {
  394. DoJwtTokenCreds();
  395. } else if (FLAGS_test_case == "all") {
  396. DoEmpty();
  397. DoLargeUnary();
  398. DoRequestStreaming();
  399. DoResponseStreaming();
  400. DoHalfDuplex();
  401. DoPingPong();
  402. // service_account_creds and jwt_token_creds can only run with ssl.
  403. if (FLAGS_enable_ssl) {
  404. DoServiceAccountCreds();
  405. DoJwtTokenCreds();
  406. }
  407. // compute_engine_creds only runs in GCE.
  408. } else {
  409. gpr_log(
  410. GPR_ERROR,
  411. "Unsupported test case %s. Valid options are all|empty_unary|"
  412. "large_unary|client_streaming|server_streaming|half_duplex|ping_pong|"
  413. "service_account_creds|compute_engine_creds|jwt_token_creds",
  414. FLAGS_test_case.c_str());
  415. }
  416. grpc_shutdown();
  417. return 0;
  418. }