From 256cc7aa034f038f8e82f3e278ca61b64252693b Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 7 Jul 2016 11:09:49 -0700 Subject: Support server reflection in CLI --- Makefile | 8 ++-- build.yaml | 4 ++ test/cpp/util/grpc_cli.cc | 44 ++++++++++++---------- test/cpp/util/proto_file_parser.cc | 42 +++++++++++++++++++-- test/cpp/util/proto_file_parser.h | 11 ++++++ .../util/proto_reflection_descriptor_database.cc | 12 +++++- tools/run_tests/sources_and_headers.json | 8 +++- .../vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj | 3 ++ .../grpc_cli_libs/grpc_cli_libs.vcxproj.filters | 6 +++ vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj | 3 ++ 10 files changed, 111 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 7011996371..6ba584cbdc 100644 --- a/Makefile +++ b/Makefile @@ -4140,6 +4140,7 @@ endif LIBGRPC_CLI_LIBS_SRC = \ test/cpp/util/cli_call.cc \ test/cpp/util/proto_file_parser.cc \ + test/cpp/util/proto_reflection_descriptor_database.cc \ PUBLIC_HEADERS_CXX += \ @@ -11079,16 +11080,16 @@ $(BINDIR)/$(CONFIG)/grpc_cli: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli + $(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o: $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o: $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a deps_grpc_cli: $(GRPC_CLI_OBJS:.o=.dep) @@ -15002,6 +15003,7 @@ test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP) test/cpp/util/cli_call.cc: $(OPENSSL_DEP) test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP) test/cpp/util/proto_file_parser.cc: $(OPENSSL_DEP) +test/cpp/util/proto_reflection_descriptor_database.cc: $(OPENSSL_DEP) test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP) test/cpp/util/subprocess.cc: $(OPENSSL_DEP) test/cpp/util/test_config.cc: $(OPENSSL_DEP) diff --git a/build.yaml b/build.yaml index 1c485fd5c9..8fabaad774 100644 --- a/build.yaml +++ b/build.yaml @@ -1028,10 +1028,13 @@ libs: headers: - test/cpp/util/cli_call.h - test/cpp/util/proto_file_parser.h + - test/cpp/util/proto_reflection_descriptor_database.h src: - test/cpp/util/cli_call.cc - test/cpp/util/proto_file_parser.cc + - test/cpp/util/proto_reflection_descriptor_database.cc deps: + - grpc++_reflection - grpc++ - grpc_plugin_support - name: grpc_plugin_support @@ -2669,6 +2672,7 @@ targets: - grpc_cli_libs - grpc++_test_util - grpc_test_util + - grpc++_reflection - grpc++ - grpc - gpr_test_util diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index c52e48bae6..71470e5214 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -86,6 +86,7 @@ DEFINE_string(output_binary_file, "", DEFINE_string(metadata, "", "Metadata to send to server, in the form of key1:val1:key2:val2"); DEFINE_string(proto_path, ".", "Path to look for the proto file."); +DEFINE_string(proto_file, "", "Name of the proto file."); void ParseMetadataFlag( std::multimap* client_metadata) { @@ -129,31 +130,47 @@ void PrintMetadata(const T& m, const grpc::string& message) { int main(int argc, char** argv) { grpc::testing::InitTest(&argc, &argv, true); - if (argc < 4 || argc == 5 || grpc::string(argv[1]) != "call") { + if (argc < 4 || grpc::string(argv[1]) != "call") { std::cout << "Usage: grpc_cli call server_host:port method_name " << "[proto file] [text format request] []" << std::endl; + return 1; } - grpc::string file_name; grpc::string request_text; grpc::string server_address(argv[2]); grpc::string method_name(argv[3]); std::unique_ptr parser; grpc::string serialized_request_proto; - if (argc == 6) { - file_name = argv[4]; + if (argc == 5) { // TODO(yangg) read from stdin as well? - request_text = argv[5]; + request_text = argv[4]; } + std::shared_ptr creds; + if (!FLAGS_enable_ssl) { + creds = grpc::InsecureChannelCredentials(); + } else { + if (FLAGS_use_auth) { + creds = grpc::GoogleDefaultCredentials(); + } else { + creds = grpc::SslCredentials(grpc::SslCredentialsOptions()); + } + } + std::shared_ptr channel = + grpc::CreateChannel(server_address, creds); + if (request_text.empty() && FLAGS_input_binary_file.empty()) { std::cout << "Missing input. Use text format input or " << "--input_binary_file for serialized request" << std::endl; return 1; } else if (!request_text.empty()) { - parser.reset(new grpc::testing::ProtoFileParser(FLAGS_proto_path, file_name, - method_name)); + if (!FLAGS_proto_file.empty()) { + parser.reset(new grpc::testing::ProtoFileParser( + FLAGS_proto_path, FLAGS_proto_file, method_name)); + } else { + parser.reset(new grpc::testing::ProtoFileParser(channel, method_name)); + } method_name = parser->GetFullMethodName(); if (parser->HasError()) { return 1; @@ -175,19 +192,6 @@ int main(int argc, char** argv) { } std::cout << "connecting to " << server_address << std::endl; - std::shared_ptr creds; - if (!FLAGS_enable_ssl) { - creds = grpc::InsecureChannelCredentials(); - } else { - if (FLAGS_use_auth) { - creds = grpc::GoogleDefaultCredentials(); - } else { - creds = grpc::SslCredentials(grpc::SslCredentialsOptions()); - } - } - std::shared_ptr channel = - grpc::CreateChannel(server_address, creds); - grpc::string serialized_response_proto; std::multimap client_metadata; std::multimap server_initial_metadata, diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc index 25aec329eb..2ac19858bf 100644 --- a/test/cpp/util/proto_file_parser.cc +++ b/test/cpp/util/proto_file_parser.cc @@ -95,9 +95,45 @@ ProtoFileParser::ProtoFileParser(const grpc::string& proto_path, dynamic_factory_.reset( new google::protobuf::DynamicMessageFactory(importer_->pool())); + std::vector service_desc_list; + for (int i = 0; i < file_desc->service_count(); i++) { + service_desc_list.push_back(file_desc->service(i)); + } + InitProtoFileParser(method, service_desc_list); +} + +ProtoFileParser::ProtoFileParser(std::shared_ptr channel, + const grpc::string& method) + : has_error_(false), + desc_db_(new grpc::ProtoReflectionDescriptorDatabase(channel)), + desc_pool_(new google::protobuf::DescriptorPool(desc_db_.get())) { + std::vector service_list; + if (!desc_db_->GetServices(&service_list)) { + LogError("Failed to get services"); + } + if (has_error_) { + return; + } + dynamic_factory_.reset( + new google::protobuf::DynamicMessageFactory(desc_pool_.get())); + + std::vector service_desc_list; + for (auto it = service_list.begin(); it != service_list.end(); it++) { + service_desc_list.push_back(desc_pool_->FindServiceByName(*it)); + } + InitProtoFileParser(method, service_desc_list); +} + +ProtoFileParser::~ProtoFileParser() {} + +void ProtoFileParser::InitProtoFileParser( + const grpc::string& method, + const std::vector + service_desc_list) { const google::protobuf::MethodDescriptor* method_descriptor = nullptr; - for (int i = 0; !method_descriptor && i < file_desc->service_count(); i++) { - const auto* service_desc = file_desc->service(i); + for (auto it = service_desc_list.begin(); it != service_desc_list.end(); + it++) { + const auto* service_desc = *it; for (int j = 0; j < service_desc->method_count(); j++) { const auto* method_desc = service_desc->method(j); if (MethodNameMatch(method_desc->full_name(), method)) { @@ -130,8 +166,6 @@ ProtoFileParser::ProtoFileParser(const grpc::string& proto_path, dynamic_factory_->GetPrototype(method_descriptor->output_type())->New()); } -ProtoFileParser::~ProtoFileParser() {} - grpc::string ProtoFileParser::GetSerializedProto( const grpc::string& text_format_proto, bool is_request) { grpc::string serialized; diff --git a/test/cpp/util/proto_file_parser.h b/test/cpp/util/proto_file_parser.h index 46cdd66503..b442d77db9 100644 --- a/test/cpp/util/proto_file_parser.h +++ b/test/cpp/util/proto_file_parser.h @@ -38,8 +38,10 @@ #include #include +#include #include "src/compiler/config.h" +#include "test/cpp/util/proto_reflection_descriptor_database.h" namespace grpc { namespace testing { @@ -53,6 +55,9 @@ class ProtoFileParser { // even just Method. It will log an error if there is ambiguity. ProtoFileParser(const grpc::string& proto_path, const grpc::string& file_name, const grpc::string& method); + + ProtoFileParser(std::shared_ptr channel, + const grpc::string& method); ~ProtoFileParser(); grpc::string GetFullMethodName() const { return full_method_name_; } @@ -68,12 +73,18 @@ class ProtoFileParser { void LogError(const grpc::string& error_msg); private: + void InitProtoFileParser( + const grpc::string& method, + const std::vector services); + bool has_error_; grpc::string request_text_; grpc::string full_method_name_; google::protobuf::compiler::DiskSourceTree source_tree_; std::unique_ptr error_printer_; std::unique_ptr importer_; + std::unique_ptr desc_db_; + std::unique_ptr desc_pool_; std::unique_ptr dynamic_factory_; std::unique_ptr request_prototype_; std::unique_ptr response_prototype_; diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc index 25b720aee0..48998551a5 100644 --- a/test/cpp/util/proto_reflection_descriptor_database.cc +++ b/test/cpp/util/proto_reflection_descriptor_database.cc @@ -53,7 +53,17 @@ ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( std::shared_ptr channel) : stub_(ServerReflection::NewStub(channel)) {} -ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {} +ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() { + if (!stream_) { + GetStream()->WritesDone(); + Status status = stream_->Finish(); + if (!status.ok()) { + gpr_log(GPR_ERROR, + "ServerReflectionInfo rpc failed. Error code: %d, details: %s", + (int)status.error_code(), status.error_message().c_str()); + } + } +} bool ProtoReflectionDescriptorDatabase::FindFileByName( const string& filename, google::protobuf::FileDescriptorProto* output) { diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 6d7cfdaf23..86383fa0cc 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -2149,6 +2149,7 @@ "gpr_test_util", "grpc", "grpc++", + "grpc++_reflection", "grpc++_test_config", "grpc++_test_util", "grpc_cli_libs", @@ -4479,7 +4480,8 @@ ], "headers": [ "test/cpp/util/cli_call.h", - "test/cpp/util/proto_file_parser.h" + "test/cpp/util/proto_file_parser.h", + "test/cpp/util/proto_reflection_descriptor_database.h" ], "language": "c++", "name": "grpc_cli_libs", @@ -4487,7 +4489,9 @@ "test/cpp/util/cli_call.cc", "test/cpp/util/cli_call.h", "test/cpp/util/proto_file_parser.cc", - "test/cpp/util/proto_file_parser.h" + "test/cpp/util/proto_file_parser.h", + "test/cpp/util/proto_reflection_descriptor_database.cc", + "test/cpp/util/proto_reflection_descriptor_database.h" ], "third_party": false, "type": "lib" diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj index 39cb1e0cb5..03c82f686c 100644 --- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj +++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj @@ -149,12 +149,15 @@ + + + diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters index 55ef18bf30..4add8ed5e1 100644 --- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters @@ -7,6 +7,9 @@ test\cpp\util + + test\cpp\util + @@ -15,6 +18,9 @@ test\cpp\util + + test\cpp\util + diff --git a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj index cd844d1579..9c8cdc54c2 100644 --- a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj +++ b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj @@ -173,6 +173,9 @@ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + {5F575402-3F89-5D1A-6910-9DB8BF5D2BAB} + {C187A093-A0FE-489D-A40A-6E33DE0F9FEB} -- cgit v1.2.3 From c24e0ee4f00a348a2f9948c820cf08be813c5f8a Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 7 Jul 2016 11:32:25 -0700 Subject: Update docs --- test/cpp/util/grpc_cli.cc | 21 ++++++++++++--------- test/cpp/util/proto_file_parser.cc | 7 +++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index 71470e5214..1a9662694a 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -34,18 +34,21 @@ /* A command line tool to talk to a grpc server. Example of talking to grpc interop server: - grpc_cli call localhost:50051 UnaryCall src/proto/grpc/testing/test.proto \ - "response_size:10" --enable_ssl=false + grpc_cli call localhost:50051 UnaryCall "response_size:10" \ + --proto_file=src/proto/grpc/testing/test.prot --enable_ssl=false Options: - 1. --proto_path, if your proto file is not under current working directory, + 1. --proto_file, use this flag to provide a proto file if the server does + does not have the reflection service. + 2. --proto_path, if your proto file is not under current working directory, use this flag to provide a search root. It should work similar to the - counterpart in protoc. - 2. --metadata specifies metadata to be sent to the server, such as: + counterpart in protoc. This option is valid only when proto_file is + provided. + 3. --metadata specifies metadata to be sent to the server, such as: --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2" - 3. --enable_ssl, whether to use tls. - 4. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call - 3. --input_binary_file, a file containing the serialized request. The file + 4. --enable_ssl, whether to use tls. + 5. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call + 6. --input_binary_file, a file containing the serialized request. The file can be generated by calling something like: protoc --proto_path=src/proto/grpc/testing/ \ --encode=grpc.testing.SimpleRequest \ @@ -53,7 +56,7 @@ < input.txt > input.bin If this is used and no proto file is provided in the argument list, the method string has to be exact in the form of /package.service/method. - 4. --output_binary_file, a file to write binary format response into, it can + 7. --output_binary_file, a file to write binary format response into, it can be later decoded using protoc: protoc --proto_path=src/proto/grpc/testing/ \ --decode=grpc.testing.SimpleResponse \ diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc index 2ac19858bf..b1bf0471e1 100644 --- a/test/cpp/util/proto_file_parser.cc +++ b/test/cpp/util/proto_file_parser.cc @@ -109,7 +109,10 @@ ProtoFileParser::ProtoFileParser(std::shared_ptr channel, desc_pool_(new google::protobuf::DescriptorPool(desc_db_.get())) { std::vector service_list; if (!desc_db_->GetServices(&service_list)) { - LogError("Failed to get services"); + LogError( + "Failed to get services from the server, " + "it may not have the reflection service.\n" + "Please try to use the --proto_file option to provide a proto file."); } if (has_error_) { return; @@ -177,7 +180,7 @@ grpc::string ProtoFileParser::GetSerializedProto( LogError("Failed to parse text format to proto."); return ""; } - ok = request_prototype_->SerializeToString(&serialized); + ok = msg->SerializeToString(&serialized); if (!ok) { LogError("Failed to serialize proto."); return ""; -- cgit v1.2.3 From a17c8d993d3bc4867fcc9d6fcf42e6bfff9c9cd8 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 7 Jul 2016 11:40:05 -0700 Subject: Fix typos --- test/cpp/util/grpc_cli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index 1a9662694a..7c8e2cdc63 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -35,7 +35,7 @@ A command line tool to talk to a grpc server. Example of talking to grpc interop server: grpc_cli call localhost:50051 UnaryCall "response_size:10" \ - --proto_file=src/proto/grpc/testing/test.prot --enable_ssl=false + --proto_file=src/proto/grpc/testing/test.proto --enable_ssl=false Options: 1. --proto_file, use this flag to provide a proto file if the server does -- cgit v1.2.3 From 39070fe3a536819708aaa4422ea912b303cbe30f Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 7 Jul 2016 13:57:12 -0700 Subject: Rerun generate_projects.sh --- tools/run_tests/sources_and_headers.json | 1 + vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 86383fa0cc..141c898266 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -4476,6 +4476,7 @@ { "deps": [ "grpc++", + "grpc++_reflection", "grpc_plugin_support" ], "headers": [ diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj index 03c82f686c..d25c692e3e 100644 --- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj +++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj @@ -160,6 +160,9 @@ + + {5F575402-3F89-5D1A-6910-9DB8BF5D2BAB} + {C187A093-A0FE-489D-A40A-6E33DE0F9FEB} -- cgit v1.2.3 From c68640f05cea2cf79bf2703d83da6b76fa6dc5e6 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 7 Jul 2016 14:13:35 -0700 Subject: Read from stdin Read from stdin if the request text and binary file are not provided --- test/cpp/util/grpc_cli.cc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index 7c8e2cdc63..fdb1a7c2a0 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -64,6 +64,7 @@ < output.bin > output.txt */ +#include #include #include #include @@ -146,7 +147,6 @@ int main(int argc, char** argv) { grpc::string serialized_request_proto; if (argc == 5) { - // TODO(yangg) read from stdin as well? request_text = argv[4]; } @@ -164,10 +164,15 @@ int main(int argc, char** argv) { grpc::CreateChannel(server_address, creds); if (request_text.empty() && FLAGS_input_binary_file.empty()) { - std::cout << "Missing input. Use text format input or " - << "--input_binary_file for serialized request" << std::endl; - return 1; - } else if (!request_text.empty()) { + if (isatty(STDIN_FILENO)) { + std::cout << "reading request message from stdin..." << std::endl; + } + std::stringstream input_stream; + input_stream << std::cin.rdbuf(); + request_text = input_stream.str(); + } + + if (!request_text.empty()) { if (!FLAGS_proto_file.empty()) { parser.reset(new grpc::testing::ProtoFileParser( FLAGS_proto_path, FLAGS_proto_file, method_name)); @@ -178,6 +183,12 @@ int main(int argc, char** argv) { if (parser->HasError()) { return 1; } + + if (!FLAGS_input_binary_file.empty()) { + std::cout + << "warning: request given in argv, ignoring --input_binary_file" + << std::endl; + } } if (parser) { @@ -226,7 +237,7 @@ int main(int argc, char** argv) { } } else { std::cout << "Rpc failed with status code " << s.error_code() - << " error message " << s.error_message() << std::endl; + << ", error message: " << s.error_message() << std::endl; } return 0; -- cgit v1.2.3 From 9cb9445155804fb65af100b9747d467254fb7ca6 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Wed, 20 Jul 2016 16:39:31 -0700 Subject: Addressed review comments --- doc/command_line_tool.md | 29 +++++++++++++++------- test/cpp/util/grpc_cli.cc | 13 +++++----- test/cpp/util/proto_file_parser.cc | 2 +- .../util/proto_reflection_descriptor_database.cc | 4 +-- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/command_line_tool.md b/doc/command_line_tool.md index 89a70548b8..79a131c041 100644 --- a/doc/command_line_tool.md +++ b/doc/command_line_tool.md @@ -15,6 +15,7 @@ The command line tool can do the following things: - Send unary rpc. - Attach metadata and display received metadata. - Handle common authentication to server. +- Infer request/response types from server reflection result. - Find the request/response types from a given proto file. - Read proto request in text form. - Read request in wire form (for protobuf messages, this means serialized binary form). @@ -24,7 +25,6 @@ The command line tool can do the following things: The command line tool should support the following things: - List server services and methods through server reflection. -- Infer request/response types from server reflection result. - Fine-grained auth control (such as, use this oauth token to talk to the server). - Send streaming rpc. @@ -46,24 +46,35 @@ https://github.com/grpc/grpc/blob/master/test/cpp/util/grpc_cli.cc Send a rpc to a helloworld server at `localhost:50051`: ``` -$ bins/opt/grpc_cli call localhost:50051 SayHello examples/protos/helloworld.proto \ - "name: 'world'" --enable_ssl=false +$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \ + --enable_ssl=false ``` On success, the tool will print out ``` Rpc succeeded with OK status -Response: +Response: message: "Hello world" ``` The `localhost:50051` part indicates the server you are connecting to. `SayHello` is (part of) the -gRPC method string. Then there is the path to the proto file containing the service definition, -if it is not under current directory, you can use `--proto_path` to specify a new search root. -`"name: 'world'"` is the text format of the request proto message. -We are not using ssl here by `--enable_ssl=false`. For information on more -flags, look at the comments of `grpc_cli.cc`. +gRPC method string. Then `"name: 'world'"` is the text format of the request proto message. We are +not using ssl here by `--enable_ssl=false`. For information on more flags, look at the comments of `grpc_cli.cc`. + +### Use local proto files + +If the server does not have the server reflection service, you will need to provide local proto +files containing the service definition. The tool will try to find request/response types from +them. + +``` +$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \ + --protofiles=examples/protos/helloworld.proto --enable_ssl=false +``` + +If the proto files is not under current directory, you can use `--proto_path` to specify a new +search root. ### Send non-proto rpc diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index fdb1a7c2a0..53529da782 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -35,14 +35,14 @@ A command line tool to talk to a grpc server. Example of talking to grpc interop server: grpc_cli call localhost:50051 UnaryCall "response_size:10" \ - --proto_file=src/proto/grpc/testing/test.proto --enable_ssl=false + --protofiles=src/proto/grpc/testing/test.proto --enable_ssl=false Options: - 1. --proto_file, use this flag to provide a proto file if the server does + 1. --protofiles, use this flag to provide a proto file if the server does does not have the reflection service. 2. --proto_path, if your proto file is not under current working directory, use this flag to provide a search root. It should work similar to the - counterpart in protoc. This option is valid only when proto_file is + counterpart in protoc. This option is valid only when protofiles is provided. 3. --metadata specifies metadata to be sent to the server, such as: --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2" @@ -90,7 +90,8 @@ DEFINE_string(output_binary_file, "", DEFINE_string(metadata, "", "Metadata to send to server, in the form of key1:val1:key2:val2"); DEFINE_string(proto_path, ".", "Path to look for the proto file."); -DEFINE_string(proto_file, "", "Name of the proto file."); +// TODO(zyc): support a list of input proto files +DEFINE_string(protofiles, "", "Name of the proto file."); void ParseMetadataFlag( std::multimap* client_metadata) { @@ -173,9 +174,9 @@ int main(int argc, char** argv) { } if (!request_text.empty()) { - if (!FLAGS_proto_file.empty()) { + if (!FLAGS_protofiles.empty()) { parser.reset(new grpc::testing::ProtoFileParser( - FLAGS_proto_path, FLAGS_proto_file, method_name)); + FLAGS_proto_path, FLAGS_protofiles, method_name)); } else { parser.reset(new grpc::testing::ProtoFileParser(channel, method_name)); } diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc index b1bf0471e1..5b0d925e1c 100644 --- a/test/cpp/util/proto_file_parser.cc +++ b/test/cpp/util/proto_file_parser.cc @@ -112,7 +112,7 @@ ProtoFileParser::ProtoFileParser(std::shared_ptr channel, LogError( "Failed to get services from the server, " "it may not have the reflection service.\n" - "Please try to use the --proto_file option to provide a proto file."); + "Please try to use the --protofiles option to provide a proto file."); } if (has_error_) { return; diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc index 48998551a5..2d847012a2 100644 --- a/test/cpp/util/proto_reflection_descriptor_database.cc +++ b/test/cpp/util/proto_reflection_descriptor_database.cc @@ -54,8 +54,8 @@ ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( : stub_(ServerReflection::NewStub(channel)) {} ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() { - if (!stream_) { - GetStream()->WritesDone(); + if (stream_) { + stream_->WritesDone(); Status status = stream_->Finish(); if (!status.ok()) { gpr_log(GPR_ERROR, -- cgit v1.2.3