From 102eccb63238f2b40e89d2ec1ed93a7771a82798 Mon Sep 17 00:00:00 2001 From: Yang Gao Date: Tue, 16 Jun 2015 00:43:25 -0700 Subject: [PATCH 1/2] Support sending and showing received metadata in grpc_cli --- test/cpp/util/cli_call.cc | 24 +++++++---- test/cpp/util/cli_call.h | 12 ++++-- test/cpp/util/cli_call_test.cc | 20 ++++++++- test/cpp/util/grpc_cli.cc | 74 +++++++++++++++++++++++++++++----- 4 files changed, 109 insertions(+), 21 deletions(-) diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc index eb67b8d314b..5c2b2adb5c7 100644 --- a/test/cpp/util/cli_call.cc +++ b/test/cpp/util/cli_call.cc @@ -52,11 +52,20 @@ namespace { void* tag(int i) { return (void*)(gpr_intptr) i; } } // namespace -void CliCall::Call(std::shared_ptr channel, - const grpc::string& method, const grpc::string& request, - grpc::string* response) { +Status CliCall::Call(std::shared_ptr channel, + const grpc::string& method, const grpc::string& request, + grpc::string* response, const MetadataContainer& metadata, + MetadataContainer* server_initial_metadata, + MetadataContainer* server_trailing_metadata) { std::unique_ptr stub(new grpc::GenericStub(channel)); grpc::ClientContext ctx; + if (!metadata.empty()) { + for (std::multimap::const_iterator iter = + metadata.begin(); + iter != metadata.end(); ++iter) { + ctx.AddMetadata(iter->first, iter->second); + } + } grpc::CompletionQueue cq; std::unique_ptr call( stub->Call(&ctx, method, &cq, tag(1))); @@ -79,7 +88,7 @@ void CliCall::Call(std::shared_ptr channel, cq.Next(&got_tag, &ok); if (!ok) { std::cout << "Failed to read response." << std::endl; - return; + return Status(StatusCode::INTERNAL, "Failed to read response"); } grpc::Status status; call->Finish(&status, tag(5)); @@ -87,7 +96,6 @@ void CliCall::Call(std::shared_ptr channel, GPR_ASSERT(ok); if (status.IsOk()) { - std::cout << "RPC finished with OK status." << std::endl; std::vector slices; recv_buffer.Dump(&slices); @@ -96,10 +104,10 @@ void CliCall::Call(std::shared_ptr channel, response->append(reinterpret_cast(slices[i].begin()), slices[i].size()); } - } else { - std::cout << "RPC finished with status code " << status.code() - << " details: " << status.details() << std::endl; } + *server_initial_metadata = ctx.GetServerInitialMetadata(); + *server_trailing_metadata = ctx.GetServerTrailingMetadata(); + return status; } } // namespace testing diff --git a/test/cpp/util/cli_call.h b/test/cpp/util/cli_call.h index 7be8bb63c41..8d114c9cb5e 100644 --- a/test/cpp/util/cli_call.h +++ b/test/cpp/util/cli_call.h @@ -34,17 +34,23 @@ #ifndef GRPC_TEST_CPP_UTIL_CLI_CALL_H #define GRPC_TEST_CPP_UTIL_CLI_CALL_H +#include + #include #include +#include namespace grpc { namespace testing { class CliCall GRPC_FINAL { public: - static void Call(std::shared_ptr channel, - const grpc::string& method, const grpc::string& request, - grpc::string* response); + typedef std::multimap MetadataContainer; + static Status Call(std::shared_ptr channel, + const grpc::string& method, const grpc::string& request, + grpc::string* response, const MetadataContainer& metadata, + MetadataContainer* server_initial_metadata, + MetadataContainer* server_trailing_metadata); }; } // namespace testing diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 457a5e77de8..fb6e9263674 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -60,6 +60,14 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { public: Status Echo(ServerContext* context, const EchoRequest* request, EchoResponse* response) GRPC_OVERRIDE { + if (!context->client_metadata().empty()) { + for (std::multimap::const_iterator iter = + context->client_metadata().begin(); + iter != context->client_metadata().end(); ++iter) { + context->AddInitialMetadata(iter->first, iter->second); + } + } + context->AddTrailingMetadata("trailing_key", "trailing_value"); response->set_message(request->message()); return Status::OK; } @@ -106,6 +114,7 @@ TEST_F(CliCallTest, SimpleRpc) { request.set_message("Hello"); ClientContext context; + context.AddMetadata("key1", "val1"); Status s = stub_->Echo(&context, request, &response); EXPECT_EQ(response.message(), request.message()); EXPECT_TRUE(s.IsOk()); @@ -114,8 +123,17 @@ TEST_F(CliCallTest, SimpleRpc) { grpc::string request_bin, response_bin, expected_response_bin; EXPECT_TRUE(request.SerializeToString(&request_bin)); EXPECT_TRUE(response.SerializeToString(&expected_response_bin)); - CliCall::Call(channel_, kMethod, request_bin, &response_bin); + std::multimap client_metadata, + server_initial_metadata, server_trailing_metadata; + client_metadata.insert(std::pair("key1", "val1")); + Status s2 = CliCall::Call(channel_, kMethod, request_bin, &response_bin, + client_metadata, &server_initial_metadata, + &server_trailing_metadata); + EXPECT_TRUE(s2.IsOk()); + EXPECT_EQ(expected_response_bin, response_bin); + EXPECT_EQ(context.GetServerInitialMetadata(), server_initial_metadata); + EXPECT_EQ(context.GetServerTrailingMetadata(), server_trailing_metadata); } } // namespace testing diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index ad3c0af8775..06a7029a6d3 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -41,8 +41,8 @@ body: "hello world" } b. under grpc/ run - protoc --proto_path=test/cpp/interop/ \ - --encode=grpc.testing.SimpleRequest test/cpp/interop/messages.proto \ + protoc --proto_path=test/proto/ \ + --encode=grpc.testing.SimpleRequest test/proto/messages.proto \ < input.txt > input.bin 2. Start a server make interop_server && bins/opt/interop_server --port=50051 @@ -51,10 +51,12 @@ /grpc.testing.TestService/UnaryCall --enable_ssl=false \ --input_binary_file=input.bin --output_binary_file=output.bin 4. Decode response - protoc --proto_path=test/cpp/interop/ \ - --decode=grpc.testing.SimpleResponse test/cpp/interop/messages.proto \ + protoc --proto_path=test/proto/ \ + --decode=grpc.testing.SimpleResponse test/proto/messages.proto \ < output.bin > output.txt 5. Now the text form of response should be in output.txt + Optionally, metadata can be passed to server via flag --metadata, e.g. + --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2" */ #include @@ -77,6 +79,44 @@ DEFINE_string(input_binary_file, "", "Path to input file containing serialized request."); DEFINE_string(output_binary_file, "output.bin", "Path to output file to write serialized response."); +DEFINE_string(metadata, "", + "Metadata to send to server, in the form of key1:val1:key2:val2"); + +void ParseMetadataFlag( + std::multimap* client_metadata) { + if (FLAGS_metadata.empty()) { + return; + } + std::vector fields; + grpc::string delim(":"); + size_t cur, next = -1; + do { + cur = next + 1; + next = FLAGS_metadata.find_first_of(delim, cur); + fields.push_back(FLAGS_metadata.substr(cur, next - cur)); + } while (next != grpc::string::npos); + if (fields.size() % 2) { + std::cout << "Failed to parse metadata flag" << std::endl; + exit(1); + } + for (size_t i = 0; i < fields.size(); i += 2) { + client_metadata->insert( + std::pair(fields[i], fields[i + 1])); + } +} + +void PrintMetadata(const std::multimap& m, + const grpc::string& message) { + if (m.empty()) { + return; + } + std::cout << message << std::endl; + for (std::multimap::const_iterator iter = + m.begin(); + iter != m.end(); ++iter) { + std::cout << iter->first << " : " << iter->second << std::endl; + } +} int main(int argc, char** argv) { grpc::testing::InitTest(&argc, &argv, true); @@ -118,11 +158,27 @@ int main(int argc, char** argv) { grpc::CreateChannel(server_address, creds, grpc::ChannelArguments()); grpc::string response; - grpc::testing::CliCall::Call(channel, method, input_stream.str(), &response); - if (!response.empty()) { - std::ofstream output_file(FLAGS_output_binary_file, - std::ios::trunc | std::ios::binary); - output_file << response; + std::multimap client_metadata, + server_initial_metadata, server_trailing_metadata; + ParseMetadataFlag(&client_metadata); + PrintMetadata(client_metadata, "Sending client initial metadata:"); + grpc::Status s = grpc::testing::CliCall::Call( + channel, method, input_stream.str(), &response, client_metadata, + &server_initial_metadata, &server_trailing_metadata); + PrintMetadata(server_initial_metadata, + "Received initial metadata from server:"); + PrintMetadata(server_trailing_metadata, + "Received trailing metadata from server:"); + if (s.IsOk()) { + std::cout << "Rpc succeeded with OK status" << std::endl; + if (!response.empty()) { + std::ofstream output_file(FLAGS_output_binary_file, + std::ios::trunc | std::ios::binary); + output_file << response; + } + } else { + std::cout << "Rpc failed with status code " << s.code() << " error message " + << s.details() << std::endl; } return 0; From 45bd28e0d3c7d7272333ca2531f1e53467037ecd Mon Sep 17 00:00:00 2001 From: Yang Gao Date: Tue, 16 Jun 2015 22:07:58 -0700 Subject: [PATCH 2/2] One more thing... --- test/cpp/util/cli_call_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index ac7a531f525..6cf86ea89bf 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -129,7 +129,7 @@ TEST_F(CliCallTest, SimpleRpc) { Status s2 = CliCall::Call(channel_, kMethod, request_bin, &response_bin, client_metadata, &server_initial_metadata, &server_trailing_metadata); - EXPECT_TRUE(s2.IsOk()); + EXPECT_TRUE(s2.ok()); EXPECT_EQ(expected_response_bin, response_bin); EXPECT_EQ(context.GetServerInitialMetadata(), server_initial_metadata);