client.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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 <fstream>
  34. #include <memory>
  35. #include <sstream>
  36. #include <string>
  37. #include <thread>
  38. #include <unistd.h>
  39. #include <grpc/grpc.h>
  40. #include <grpc/support/log.h>
  41. #include <gflags/gflags.h>
  42. #include <grpc++/channel_arguments.h>
  43. #include <grpc++/channel_interface.h>
  44. #include <grpc++/client_context.h>
  45. #include <grpc++/create_channel.h>
  46. #include <grpc++/credentials.h>
  47. #include <grpc++/status.h>
  48. #include <grpc++/stream.h>
  49. #include "test/cpp/util/create_test_channel.h"
  50. #include "test/cpp/interop/test.pb.h"
  51. #include "test/cpp/interop/empty.pb.h"
  52. #include "test/cpp/interop/messages.pb.h"
  53. DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
  54. DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google");
  55. DEFINE_int32(server_port, 0, "Server port.");
  56. DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
  57. DEFINE_string(server_host_override, "foo.test.google.fr",
  58. "Override the server host which is sent in HTTP header");
  59. DEFINE_string(test_case, "large_unary",
  60. "Configure different test cases. Valid options are: "
  61. "empty_unary : empty (zero bytes) request and response; "
  62. "large_unary : single request and (large) response; "
  63. "client_streaming : request streaming with single response; "
  64. "server_streaming : single request with response streaming; "
  65. "slow_consumer : single request with response; "
  66. " streaming with slow client consumer; "
  67. "half_duplex : half-duplex streaming; "
  68. "ping_pong : full-duplex streaming; "
  69. "service_account_creds : large_unary with service_account auth; "
  70. "compute_engine_creds: large_unary with compute engine auth; "
  71. "jwt_token_creds: large_unary with JWT token auth; "
  72. "all : all of above.");
  73. DEFINE_string(default_service_account, "",
  74. "Email of GCE default service account");
  75. DEFINE_string(service_account_key_file, "",
  76. "Path to service account json key file.");
  77. DEFINE_string(oauth_scope, "", "Scope for OAuth tokens.");
  78. using grpc::ChannelInterface;
  79. using grpc::ClientContext;
  80. using grpc::ComputeEngineCredentials;
  81. using grpc::CreateTestChannel;
  82. using grpc::Credentials;
  83. using grpc::JWTCredentials;
  84. using grpc::ServiceAccountCredentials;
  85. using grpc::testing::ResponseParameters;
  86. using grpc::testing::SimpleRequest;
  87. using grpc::testing::SimpleResponse;
  88. using grpc::testing::StreamingInputCallRequest;
  89. using grpc::testing::StreamingInputCallResponse;
  90. using grpc::testing::StreamingOutputCallRequest;
  91. using grpc::testing::StreamingOutputCallResponse;
  92. using grpc::testing::TestService;
  93. // In some distros, gflags is in the namespace google, and in some others,
  94. // in gflags. This hack is enabling us to find both.
  95. namespace google {}
  96. namespace gflags {}
  97. using namespace google;
  98. using namespace gflags;
  99. namespace {
  100. // The same value is defined by the Java client.
  101. const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
  102. const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
  103. const int kNumResponseMessages = 2000;
  104. const int kResponseMessageSize = 1030;
  105. const int kReceiveDelayMilliSeconds = 20;
  106. const int kLargeRequestSize = 314159;
  107. const int kLargeResponseSize = 271812;
  108. } // namespace
  109. grpc::string GetServiceAccountJsonKey() {
  110. static grpc::string json_key;
  111. if (json_key.empty()) {
  112. std::ifstream json_key_file(FLAGS_service_account_key_file);
  113. std::stringstream key_stream;
  114. key_stream << json_key_file.rdbuf();
  115. json_key = key_stream.str();
  116. }
  117. return json_key;
  118. }
  119. std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
  120. const grpc::string& test_case) {
  121. GPR_ASSERT(FLAGS_server_port);
  122. const int host_port_buf_size = 1024;
  123. char host_port[host_port_buf_size];
  124. snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
  125. FLAGS_server_port);
  126. if (test_case == "service_account_creds") {
  127. std::unique_ptr<Credentials> creds;
  128. GPR_ASSERT(FLAGS_enable_ssl);
  129. grpc::string json_key = GetServiceAccountJsonKey();
  130. creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope, 3600);
  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 = 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 = JWTCredentials(json_key, 3600);
  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 AssertOkOrPrintErrorStatus(const grpc::Status& s) {
  152. if (s.IsOk()) {
  153. return;
  154. }
  155. gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(),
  156. s.details().c_str());
  157. GPR_ASSERT(0);
  158. }
  159. void DoEmpty() {
  160. gpr_log(GPR_INFO, "Sending an empty rpc...");
  161. std::shared_ptr<ChannelInterface> channel =
  162. CreateChannelForTestCase("empty_unary");
  163. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  164. grpc::testing::Empty request = grpc::testing::Empty::default_instance();
  165. grpc::testing::Empty response = grpc::testing::Empty::default_instance();
  166. ClientContext context;
  167. grpc::Status s = stub->EmptyCall(&context, request, &response);
  168. AssertOkOrPrintErrorStatus(s);
  169. gpr_log(GPR_INFO, "Empty rpc done.");
  170. }
  171. // Shared code to set large payload, make rpc and check response payload.
  172. void PerformLargeUnary(std::shared_ptr<ChannelInterface> channel,
  173. SimpleRequest* request, SimpleResponse* response) {
  174. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  175. ClientContext context;
  176. request->set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
  177. request->set_response_size(kLargeResponseSize);
  178. grpc::string payload(kLargeRequestSize, '\0');
  179. request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
  180. grpc::Status s = stub->UnaryCall(&context, *request, response);
  181. AssertOkOrPrintErrorStatus(s);
  182. GPR_ASSERT(response->payload().type() ==
  183. grpc::testing::PayloadType::COMPRESSABLE);
  184. GPR_ASSERT(response->payload().body() ==
  185. grpc::string(kLargeResponseSize, '\0'));
  186. }
  187. void DoComputeEngineCreds() {
  188. gpr_log(GPR_INFO,
  189. "Sending a large unary rpc with compute engine credentials ...");
  190. std::shared_ptr<ChannelInterface> channel =
  191. CreateChannelForTestCase("compute_engine_creds");
  192. SimpleRequest request;
  193. SimpleResponse response;
  194. request.set_fill_username(true);
  195. request.set_fill_oauth_scope(true);
  196. PerformLargeUnary(channel, &request, &response);
  197. gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
  198. gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
  199. GPR_ASSERT(!response.username().empty());
  200. GPR_ASSERT(response.username().c_str() == FLAGS_default_service_account);
  201. GPR_ASSERT(!response.oauth_scope().empty());
  202. const char* oauth_scope_str = response.oauth_scope().c_str();
  203. GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  204. gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
  205. }
  206. void DoServiceAccountCreds() {
  207. gpr_log(GPR_INFO,
  208. "Sending a large unary rpc with service account credentials ...");
  209. std::shared_ptr<ChannelInterface> channel =
  210. CreateChannelForTestCase("service_account_creds");
  211. SimpleRequest request;
  212. SimpleResponse response;
  213. request.set_fill_username(true);
  214. request.set_fill_oauth_scope(true);
  215. PerformLargeUnary(channel, &request, &response);
  216. GPR_ASSERT(!response.username().empty());
  217. GPR_ASSERT(!response.oauth_scope().empty());
  218. grpc::string json_key = GetServiceAccountJsonKey();
  219. GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
  220. const char* oauth_scope_str = response.oauth_scope().c_str();
  221. GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  222. gpr_log(GPR_INFO, "Large unary with service account creds done.");
  223. }
  224. void DoJwtTokenCreds() {
  225. gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
  226. std::shared_ptr<ChannelInterface> channel =
  227. CreateChannelForTestCase("jwt_token_creds");
  228. SimpleRequest request;
  229. SimpleResponse response;
  230. request.set_fill_username(true);
  231. PerformLargeUnary(channel, &request, &response);
  232. GPR_ASSERT(!response.username().empty());
  233. grpc::string json_key = GetServiceAccountJsonKey();
  234. GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
  235. gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
  236. }
  237. void DoLargeUnary() {
  238. gpr_log(GPR_INFO, "Sending a large unary rpc...");
  239. std::shared_ptr<ChannelInterface> channel =
  240. CreateChannelForTestCase("large_unary");
  241. SimpleRequest request;
  242. SimpleResponse response;
  243. PerformLargeUnary(channel, &request, &response);
  244. gpr_log(GPR_INFO, "Large unary done.");
  245. }
  246. void DoRequestStreaming() {
  247. gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  248. std::shared_ptr<ChannelInterface> channel =
  249. CreateChannelForTestCase("client_streaming");
  250. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  251. grpc::ClientContext context;
  252. StreamingInputCallRequest request;
  253. StreamingInputCallResponse response;
  254. std::unique_ptr<grpc::ClientWriter<StreamingInputCallRequest>> stream(
  255. stub->StreamingInputCall(&context, &response));
  256. int aggregated_payload_size = 0;
  257. for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
  258. grpc::testing::Payload* payload = request.mutable_payload();
  259. payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
  260. GPR_ASSERT(stream->Write(request));
  261. aggregated_payload_size += request_stream_sizes[i];
  262. }
  263. stream->WritesDone();
  264. grpc::Status s = stream->Finish();
  265. GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
  266. AssertOkOrPrintErrorStatus(s);
  267. gpr_log(GPR_INFO, "Request streaming done.");
  268. }
  269. void DoResponseStreaming() {
  270. gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
  271. std::shared_ptr<ChannelInterface> channel =
  272. CreateChannelForTestCase("server_streaming");
  273. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  274. grpc::ClientContext context;
  275. StreamingOutputCallRequest request;
  276. for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
  277. ResponseParameters* response_parameter = request.add_response_parameters();
  278. response_parameter->set_size(response_stream_sizes[i]);
  279. }
  280. StreamingOutputCallResponse response;
  281. std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
  282. stub->StreamingOutputCall(&context, request));
  283. unsigned int i = 0;
  284. while (stream->Read(&response)) {
  285. GPR_ASSERT(response.payload().body() ==
  286. grpc::string(response_stream_sizes[i], '\0'));
  287. ++i;
  288. }
  289. GPR_ASSERT(response_stream_sizes.size() == i);
  290. grpc::Status s = stream->Finish();
  291. AssertOkOrPrintErrorStatus(s);
  292. gpr_log(GPR_INFO, "Response streaming done.");
  293. }
  294. void DoResponseStreamingWithSlowConsumer() {
  295. gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
  296. std::shared_ptr<ChannelInterface> channel =
  297. CreateChannelForTestCase("slow_consumer");
  298. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  299. grpc::ClientContext context;
  300. StreamingOutputCallRequest request;
  301. for (int i = 0; i < kNumResponseMessages; ++i) {
  302. ResponseParameters* response_parameter = request.add_response_parameters();
  303. response_parameter->set_size(kResponseMessageSize);
  304. }
  305. StreamingOutputCallResponse response;
  306. std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
  307. stub->StreamingOutputCall(&context, request));
  308. int i = 0;
  309. while (stream->Read(&response)) {
  310. GPR_ASSERT(response.payload().body() ==
  311. grpc::string(kResponseMessageSize, '\0'));
  312. gpr_log(GPR_INFO, "received message %d", i);
  313. usleep(kReceiveDelayMilliSeconds * 1000);
  314. ++i;
  315. }
  316. GPR_ASSERT(kNumResponseMessages == i);
  317. grpc::Status s = stream->Finish();
  318. AssertOkOrPrintErrorStatus(s);
  319. gpr_log(GPR_INFO, "Response streaming done.");
  320. }
  321. void DoHalfDuplex() {
  322. gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
  323. std::shared_ptr<ChannelInterface> channel =
  324. CreateChannelForTestCase("half_duplex");
  325. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  326. grpc::ClientContext context;
  327. std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
  328. StreamingOutputCallResponse>>
  329. stream(stub->HalfDuplexCall(&context));
  330. StreamingOutputCallRequest request;
  331. ResponseParameters* response_parameter = request.add_response_parameters();
  332. for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
  333. response_parameter->set_size(response_stream_sizes[i]);
  334. GPR_ASSERT(stream->Write(request));
  335. }
  336. stream->WritesDone();
  337. unsigned int i = 0;
  338. StreamingOutputCallResponse response;
  339. while (stream->Read(&response)) {
  340. GPR_ASSERT(response.payload().has_body());
  341. GPR_ASSERT(response.payload().body() ==
  342. grpc::string(response_stream_sizes[i], '\0'));
  343. ++i;
  344. }
  345. GPR_ASSERT(response_stream_sizes.size() == i);
  346. grpc::Status s = stream->Finish();
  347. AssertOkOrPrintErrorStatus(s);
  348. gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
  349. }
  350. void DoPingPong() {
  351. gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  352. std::shared_ptr<ChannelInterface> channel =
  353. CreateChannelForTestCase("ping_pong");
  354. std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
  355. grpc::ClientContext context;
  356. std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
  357. StreamingOutputCallResponse>>
  358. stream(stub->FullDuplexCall(&context));
  359. StreamingOutputCallRequest request;
  360. request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
  361. ResponseParameters* response_parameter = request.add_response_parameters();
  362. grpc::testing::Payload* payload = request.mutable_payload();
  363. StreamingOutputCallResponse response;
  364. for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
  365. response_parameter->set_size(response_stream_sizes[i]);
  366. payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
  367. GPR_ASSERT(stream->Write(request));
  368. GPR_ASSERT(stream->Read(&response));
  369. GPR_ASSERT(response.payload().has_body());
  370. GPR_ASSERT(response.payload().body() ==
  371. grpc::string(response_stream_sizes[i], '\0'));
  372. }
  373. stream->WritesDone();
  374. GPR_ASSERT(!stream->Read(&response));
  375. grpc::Status s = stream->Finish();
  376. AssertOkOrPrintErrorStatus(s);
  377. gpr_log(GPR_INFO, "Ping pong streaming done.");
  378. }
  379. int main(int argc, char** argv) {
  380. grpc_init();
  381. ParseCommandLineFlags(&argc, &argv, true);
  382. if (FLAGS_test_case == "empty_unary") {
  383. DoEmpty();
  384. } else if (FLAGS_test_case == "large_unary") {
  385. DoLargeUnary();
  386. } else if (FLAGS_test_case == "client_streaming") {
  387. DoRequestStreaming();
  388. } else if (FLAGS_test_case == "server_streaming") {
  389. DoResponseStreaming();
  390. } else if (FLAGS_test_case == "slow_consumer") {
  391. DoResponseStreamingWithSlowConsumer();
  392. } else if (FLAGS_test_case == "half_duplex") {
  393. DoHalfDuplex();
  394. } else if (FLAGS_test_case == "ping_pong") {
  395. DoPingPong();
  396. } else if (FLAGS_test_case == "service_account_creds") {
  397. DoServiceAccountCreds();
  398. } else if (FLAGS_test_case == "compute_engine_creds") {
  399. DoComputeEngineCreds();
  400. } else if (FLAGS_test_case == "jwt_token_creds") {
  401. DoJwtTokenCreds();
  402. } else if (FLAGS_test_case == "all") {
  403. DoEmpty();
  404. DoLargeUnary();
  405. DoRequestStreaming();
  406. DoResponseStreaming();
  407. DoHalfDuplex();
  408. DoPingPong();
  409. // service_account_creds and jwt_token_creds can only run with ssl.
  410. if (FLAGS_enable_ssl) {
  411. DoServiceAccountCreds();
  412. DoJwtTokenCreds();
  413. }
  414. // compute_engine_creds only runs in GCE.
  415. } else {
  416. gpr_log(
  417. GPR_ERROR,
  418. "Unsupported test case %s. Valid options are all|empty_unary|"
  419. "large_unary|client_streaming|server_streaming|half_duplex|ping_pong|"
  420. "service_account_creds|compute_engine_creds|jwt_token_creds",
  421. FLAGS_test_case.c_str());
  422. }
  423. grpc_shutdown();
  424. return 0;
  425. }