diff options
author | Jan Tattermusch <jtattermusch@users.noreply.github.com> | 2016-06-13 14:16:06 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-13 14:16:06 -0700 |
commit | 136307756c409e624ab098655f673e10530a1ccb (patch) | |
tree | 5ad3ab26356fad3621aa56d45aab4326cafbb947 /test/cpp | |
parent | 74823b99cf621c55b213331700fe25846ed9ed45 (diff) | |
parent | eb25a07a48d84f3426a9cc03f35faaa0b9a0c7c2 (diff) |
Merge pull request #6438 from y-zeng/reflection_separate_lib
Proto server reflection
Diffstat (limited to 'test/cpp')
-rw-r--r-- | test/cpp/end2end/proto_server_reflection_test.cc | 166 | ||||
-rw-r--r-- | test/cpp/util/proto_reflection_descriptor_database.cc | 316 | ||||
-rw-r--r-- | test/cpp/util/proto_reflection_descriptor_database.h | 131 |
3 files changed, 613 insertions, 0 deletions
diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc new file mode 100644 index 0000000000..f8fc39b553 --- /dev/null +++ b/test/cpp/end2end/proto_server_reflection_test.cc @@ -0,0 +1,166 @@ +/* + * + * Copyright 2016, 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 <google/protobuf/descriptor.h> +#include <grpc++/channel.h> +#include <grpc++/client_context.h> +#include <grpc++/create_channel.h> +#include <grpc++/ext/proto_server_reflection_plugin.h> +#include <grpc++/security/credentials.h> +#include <grpc++/security/server_credentials.h> +#include <grpc++/server.h> +#include <grpc++/server_builder.h> +#include <grpc++/server_context.h> +#include <grpc/grpc.h> +#include <gtest/gtest.h> + +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" +#include "test/cpp/end2end/test_service_impl.h" +#include "test/cpp/util/proto_reflection_descriptor_database.h" + +namespace grpc { +namespace testing { + +class ProtoServerReflectionTest : public ::testing::Test { + public: + ProtoServerReflectionTest() {} + + void SetUp() GRPC_OVERRIDE { + port_ = grpc_pick_unused_port_or_die(); + ref_desc_pool_ = google::protobuf::DescriptorPool::generated_pool(); + + ServerBuilder builder; + grpc::string server_address = "localhost:" + to_string(port_); + builder.AddListeningPort(server_address, InsecureServerCredentials()); + server_ = builder.BuildAndStart(); + } + + void ResetStub() { + string target = "dns:localhost:" + to_string(port_); + std::shared_ptr<Channel> channel = + CreateChannel(target, InsecureChannelCredentials()); + stub_ = grpc::testing::EchoTestService::NewStub(channel); + desc_db_.reset(new ProtoReflectionDescriptorDatabase(channel)); + desc_pool_.reset(new google::protobuf::DescriptorPool(desc_db_.get())); + } + + string to_string(const int number) { + std::stringstream strs; + strs << number; + return strs.str(); + } + + void CompareService(const grpc::string& service) { + const google::protobuf::ServiceDescriptor* service_desc = + desc_pool_->FindServiceByName(service); + const google::protobuf::ServiceDescriptor* ref_service_desc = + ref_desc_pool_->FindServiceByName(service); + EXPECT_TRUE(service_desc != nullptr); + EXPECT_TRUE(ref_service_desc != nullptr); + EXPECT_EQ(service_desc->DebugString(), ref_service_desc->DebugString()); + + const google::protobuf::FileDescriptor* file_desc = service_desc->file(); + if (known_files_.find(file_desc->package() + "/" + file_desc->name()) != + known_files_.end()) { + EXPECT_EQ(file_desc->DebugString(), + ref_service_desc->file()->DebugString()); + known_files_.insert(file_desc->package() + "/" + file_desc->name()); + } + + for (int i = 0; i < service_desc->method_count(); ++i) { + CompareMethod(service_desc->method(i)->full_name()); + } + } + + void CompareMethod(const grpc::string& method) { + const google::protobuf::MethodDescriptor* method_desc = + desc_pool_->FindMethodByName(method); + const google::protobuf::MethodDescriptor* ref_method_desc = + ref_desc_pool_->FindMethodByName(method); + EXPECT_TRUE(method_desc != nullptr); + EXPECT_TRUE(ref_method_desc != nullptr); + EXPECT_EQ(method_desc->DebugString(), ref_method_desc->DebugString()); + + CompareType(method_desc->input_type()->full_name()); + CompareType(method_desc->output_type()->full_name()); + } + + void CompareType(const grpc::string& type) { + if (known_types_.find(type) != known_types_.end()) { + return; + } + + const google::protobuf::Descriptor* desc = + desc_pool_->FindMessageTypeByName(type); + const google::protobuf::Descriptor* ref_desc = + ref_desc_pool_->FindMessageTypeByName(type); + EXPECT_TRUE(desc != nullptr); + EXPECT_TRUE(ref_desc != nullptr); + EXPECT_EQ(desc->DebugString(), ref_desc->DebugString()); + } + + protected: + std::unique_ptr<Server> server_; + std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; + std::unique_ptr<ProtoReflectionDescriptorDatabase> desc_db_; + std::unique_ptr<google::protobuf::DescriptorPool> desc_pool_; + std::unordered_set<string> known_files_; + std::unordered_set<string> known_types_; + const google::protobuf::DescriptorPool* ref_desc_pool_; + int port_; + reflection::ProtoServerReflectionPlugin plugin_; +}; + +TEST_F(ProtoServerReflectionTest, CheckResponseWithLocalDescriptorPool) { + ResetStub(); + + std::vector<std::string> services; + desc_db_->GetServices(&services); + // The service list has at least one service (reflection servcie). + EXPECT_TRUE(services.size() > 0); + + for (auto it = services.begin(); it != services.end(); ++it) { + CompareService(*it); + } +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc new file mode 100644 index 0000000000..6907d97bd5 --- /dev/null +++ b/test/cpp/util/proto_reflection_descriptor_database.cc @@ -0,0 +1,316 @@ +/* + * + * Copyright 2016, 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/util/proto_reflection_descriptor_database.h" + +#include <vector> + +#include <grpc/support/log.h> + +using grpc::reflection::v1alpha::ServerReflection; +using grpc::reflection::v1alpha::ServerReflectionRequest; +using grpc::reflection::v1alpha::ServerReflectionResponse; +using grpc::reflection::v1alpha::ListServiceResponse; +using grpc::reflection::v1alpha::ErrorResponse; + +namespace grpc { + +ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( + std::unique_ptr<ServerReflection::Stub> stub) + : stub_(std::move(stub)) {} + +ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( + std::shared_ptr<grpc::Channel> channel) + : stub_(ServerReflection::NewStub(channel)) {} + +ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {} + +bool ProtoReflectionDescriptorDatabase::FindFileByName( + const string& filename, google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileByName(filename, output)) { + return true; + } + + if (known_files_.find(filename) != known_files_.end()) { + return false; + } + + ServerReflectionRequest request; + request.set_file_by_filename(filename); + ServerReflectionResponse response; + + DoOneRequest(request, response); + + if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) { + AddFileFromResponse(response.file_descriptor_response()); + } else if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kErrorResponse) { + const ErrorResponse error = response.error_response(); + if (error.error_code() == StatusCode::NOT_FOUND) { + gpr_log(GPR_INFO, "NOT_FOUND from server for FindFileByName(%s)", + filename.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindFileByName(%s)\n\tError code: %d\n" + "\tError Message: %s", + filename.c_str(), error.error_code(), + error.error_message().c_str()); + } + } else { + gpr_log( + GPR_INFO, + "Error on FindFileByName(%s) response type\n" + "\tExpecting: %d\n\tReceived: %d", + filename.c_str(), + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse, + response.message_response_case()); + } + + return cached_db_.FindFileByName(filename, output); +} + +bool ProtoReflectionDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileContainingSymbol(symbol_name, output)) { + return true; + } + + if (missing_symbols_.find(symbol_name) != missing_symbols_.end()) { + return false; + } + + ServerReflectionRequest request; + request.set_file_containing_symbol(symbol_name); + ServerReflectionResponse response; + + DoOneRequest(request, response); + + if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) { + AddFileFromResponse(response.file_descriptor_response()); + } else if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kErrorResponse) { + const ErrorResponse error = response.error_response(); + if (error.error_code() == StatusCode::NOT_FOUND) { + missing_symbols_.insert(symbol_name); + gpr_log(GPR_INFO, + "NOT_FOUND from server for FindFileContainingSymbol(%s)", + symbol_name.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindFileContainingSymbol(%s)\n" + "\tError code: %d\n\tError Message: %s", + symbol_name.c_str(), error.error_code(), + error.error_message().c_str()); + } + } else { + gpr_log( + GPR_INFO, + "Error on FindFileContainingSymbol(%s) response type\n" + "\tExpecting: %d\n\tReceived: %d", + symbol_name.c_str(), + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse, + response.message_response_case()); + } + return cached_db_.FindFileContainingSymbol(symbol_name, output); +} + +bool ProtoReflectionDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, int field_number, + google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileContainingExtension(containing_type, field_number, + output)) { + return true; + } + + if (missing_extensions_.find(containing_type) != missing_extensions_.end() && + missing_extensions_[containing_type].find(field_number) != + missing_extensions_[containing_type].end()) { + gpr_log(GPR_INFO, "nested map."); + return false; + } + + ServerReflectionRequest request; + request.mutable_file_containing_extension()->set_containing_type( + containing_type); + request.mutable_file_containing_extension()->set_extension_number( + field_number); + ServerReflectionResponse response; + + DoOneRequest(request, response); + + if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) { + AddFileFromResponse(response.file_descriptor_response()); + } else if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kErrorResponse) { + const ErrorResponse error = response.error_response(); + if (error.error_code() == StatusCode::NOT_FOUND) { + if (missing_extensions_.find(containing_type) == + missing_extensions_.end()) { + missing_extensions_[containing_type] = {}; + } + missing_extensions_[containing_type].insert(field_number); + gpr_log(GPR_INFO, + "NOT_FOUND from server for FindFileContainingExtension(%s, %d)", + containing_type.c_str(), field_number); + } else { + gpr_log(GPR_INFO, + "Error on FindFileContainingExtension(%s, %d)\n" + "\tError code: %d\n\tError Message: %s", + containing_type.c_str(), field_number, error.error_code(), + error.error_message().c_str()); + } + } else { + gpr_log( + GPR_INFO, + "Error on FindFileContainingExtension(%s, %d) response type\n" + "\tExpecting: %d\n\tReceived: %d", + containing_type.c_str(), field_number, + ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse, + response.message_response_case()); + } + + return cached_db_.FindFileContainingExtension(containing_type, field_number, + output); +} + +bool ProtoReflectionDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, std::vector<int>* output) { + if (cached_extension_numbers_.find(extendee_type) != + cached_extension_numbers_.end()) { + *output = cached_extension_numbers_[extendee_type]; + return true; + } + + ServerReflectionRequest request; + request.set_all_extension_numbers_of_type(extendee_type); + ServerReflectionResponse response; + + DoOneRequest(request, response); + + if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase:: + kAllExtensionNumbersResponse) { + auto number = response.all_extension_numbers_response().extension_number(); + *output = std::vector<int>(number.begin(), number.end()); + cached_extension_numbers_[extendee_type] = *output; + return true; + } else if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kErrorResponse) { + const ErrorResponse error = response.error_response(); + if (error.error_code() == StatusCode::NOT_FOUND) { + gpr_log(GPR_INFO, "NOT_FOUND from server for FindAllExtensionNumbers(%s)", + extendee_type.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindAllExtensionNumbersExtension(%s)\n" + "\tError code: %d\n\tError Message: %s", + extendee_type.c_str(), error.error_code(), + error.error_message().c_str()); + } + } + return false; +} + +bool ProtoReflectionDescriptorDatabase::GetServices( + std::vector<std::string>* output) { + ServerReflectionRequest request; + request.set_list_services(""); + ServerReflectionResponse response; + + DoOneRequest(request, response); + + if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kListServicesResponse) { + const ListServiceResponse ls_response = response.list_services_response(); + for (int i = 0; i < ls_response.service_size(); ++i) { + (*output).push_back(ls_response.service(i).name()); + } + return true; + } else if (response.message_response_case() == + ServerReflectionResponse::MessageResponseCase::kErrorResponse) { + const ErrorResponse error = response.error_response(); + gpr_log(GPR_INFO, + "Error on GetServices()\n\tError code: %d\n" + "\tError Message: %s", + error.error_code(), error.error_message().c_str()); + } else { + gpr_log( + GPR_INFO, + "Error on GetServices() response type\n\tExpecting: %d\n\tReceived: %d", + ServerReflectionResponse::MessageResponseCase::kListServicesResponse, + response.message_response_case()); + } + return false; +} + +const google::protobuf::FileDescriptorProto +ProtoReflectionDescriptorDatabase::ParseFileDescriptorProtoResponse( + const std::string& byte_fd_proto) { + google::protobuf::FileDescriptorProto file_desc_proto; + file_desc_proto.ParseFromString(byte_fd_proto); + return file_desc_proto; +} + +void ProtoReflectionDescriptorDatabase::AddFileFromResponse( + const grpc::reflection::v1alpha::FileDescriptorResponse& response) { + for (int i = 0; i < response.file_descriptor_proto_size(); ++i) { + const google::protobuf::FileDescriptorProto file_proto = + ParseFileDescriptorProtoResponse(response.file_descriptor_proto(i)); + if (known_files_.find(file_proto.name()) == known_files_.end()) { + known_files_.insert(file_proto.name()); + cached_db_.Add(file_proto); + } + } +} + +const std::shared_ptr<ProtoReflectionDescriptorDatabase::ClientStream> +ProtoReflectionDescriptorDatabase::GetStream() { + if (stream_ == nullptr) { + stream_ = stub_->ServerReflectionInfo(&ctx_); + } + return stream_; +} + +void ProtoReflectionDescriptorDatabase::DoOneRequest( + const ServerReflectionRequest& request, + ServerReflectionResponse& response) { + stream_mutex_.lock(); + GetStream()->Write(request); + GetStream()->Read(&response); + stream_mutex_.unlock(); +} + +} // namespace grpc diff --git a/test/cpp/util/proto_reflection_descriptor_database.h b/test/cpp/util/proto_reflection_descriptor_database.h new file mode 100644 index 0000000000..99c00675bb --- /dev/null +++ b/test/cpp/util/proto_reflection_descriptor_database.h @@ -0,0 +1,131 @@ +/* + * + * Copyright 2016, 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_PROTO_SERVER_REFLECTION_DATABSE_H +#define GRPC_TEST_CPP_PROTO_SERVER_REFLECTION_DATABSE_H + +#include <mutex> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor_database.h> +#include <grpc++/ext/reflection.grpc.pb.h> +#include <grpc++/grpc++.h> + +namespace grpc { + +// ProtoReflectionDescriptorDatabase takes a stub of ServerReflection and +// provides the methods defined by DescriptorDatabase interfaces. It can be used +// to feed a DescriptorPool instance. +class ProtoReflectionDescriptorDatabase + : public google::protobuf::DescriptorDatabase { + public: + explicit ProtoReflectionDescriptorDatabase( + std::unique_ptr<reflection::v1alpha::ServerReflection::Stub> stub); + + explicit ProtoReflectionDescriptorDatabase( + std::shared_ptr<grpc::Channel> channel); + + virtual ~ProtoReflectionDescriptorDatabase(); + + // The following four methods implement DescriptorDatabase interfaces. + // + // Find a file by file name. Fills in in *output and returns true if found. + // Otherwise, returns false, leaving the contents of *output undefined. + bool FindFileByName(const string& filename, + google::protobuf::FileDescriptorProto* output) + GRPC_OVERRIDE; + + // Find the file that declares the given fully-qualified symbol name. + // If found, fills in *output and returns true, otherwise returns false + // and leaves *output undefined. + bool FindFileContainingSymbol(const string& symbol_name, + google::protobuf::FileDescriptorProto* output) + GRPC_OVERRIDE; + + // Find the file which defines an extension extending the given message type + // with the given field number. If found, fills in *output and returns true, + // otherwise returns false and leaves *output undefined. containing_type + // must be a fully-qualified type name. + bool FindFileContainingExtension( + const string& containing_type, int field_number, + google::protobuf::FileDescriptorProto* output) GRPC_OVERRIDE; + + // Finds the tag numbers used by all known extensions of + // extendee_type, and appends them to output in an undefined + // order. This method is best-effort: it's not guaranteed that the + // database will find all extensions, and it's not guaranteed that + // FindFileContainingExtension will return true on all of the found + // numbers. Returns true if the search was successful, otherwise + // returns false and leaves output unchanged. + bool FindAllExtensionNumbers(const string& extendee_type, + std::vector<int>* output) GRPC_OVERRIDE; + + // Provide a list of full names of registered services + bool GetServices(std::vector<std::string>* output); + + private: + typedef ClientReaderWriter< + grpc::reflection::v1alpha::ServerReflectionRequest, + grpc::reflection::v1alpha::ServerReflectionResponse> + ClientStream; + + const google::protobuf::FileDescriptorProto ParseFileDescriptorProtoResponse( + const std::string& byte_fd_proto); + + void AddFileFromResponse( + const grpc::reflection::v1alpha::FileDescriptorResponse& response); + + const std::shared_ptr<ClientStream> GetStream(); + + void DoOneRequest( + const grpc::reflection::v1alpha::ServerReflectionRequest& request, + grpc::reflection::v1alpha::ServerReflectionResponse& response); + + std::shared_ptr<ClientStream> stream_; + grpc::ClientContext ctx_; + std::unique_ptr<grpc::reflection::v1alpha::ServerReflection::Stub> stub_; + std::unordered_set<string> known_files_; + std::unordered_set<string> missing_symbols_; + std::unordered_map<string, std::unordered_set<int>> missing_extensions_; + std::unordered_map<string, std::vector<int>> cached_extension_numbers_; + std::mutex stream_mutex_; + + google::protobuf::SimpleDescriptorDatabase cached_db_; +}; + +} // namespace grpc + +#endif // GRPC_TEST_CPP_METRICS_SERVER_H |