aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/grpc/test/cpp/util
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/grpc/test/cpp/util
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/grpc/test/cpp/util')
-rw-r--r--contrib/libs/grpc/test/cpp/util/.yandex_meta/licenses.list.txt32
-rw-r--r--contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.cc57
-rw-r--r--contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.h42
-rw-r--r--contrib/libs/grpc/test/cpp/util/byte_buffer_test.cc134
-rw-r--r--contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.cc115
-rw-r--r--contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.h37
-rw-r--r--contrib/libs/grpc/test/cpp/util/channelz_sampler.cc588
-rw-r--r--contrib/libs/grpc/test/cpp/util/channelz_sampler_test.cc176
-rw-r--r--contrib/libs/grpc/test/cpp/util/cli_call.cc229
-rw-r--r--contrib/libs/grpc/test/cpp/util/cli_call.h109
-rw-r--r--contrib/libs/grpc/test/cpp/util/cli_call_test.cc128
-rw-r--r--contrib/libs/grpc/test/cpp/util/cli_credentials.cc245
-rw-r--r--contrib/libs/grpc/test/cpp/util/cli_credentials.h55
-rw-r--r--contrib/libs/grpc/test/cpp/util/config_grpc_cli.h70
-rw-r--r--contrib/libs/grpc/test/cpp/util/create_test_channel.cc252
-rw-r--r--contrib/libs/grpc/test/cpp/util/create_test_channel.h99
-rw-r--r--contrib/libs/grpc/test/cpp/util/error_details_test.cc125
-rw-r--r--contrib/libs/grpc/test/cpp/util/grpc_cli.cc90
-rw-r--r--contrib/libs/grpc/test/cpp/util/grpc_tool.cc985
-rw-r--r--contrib/libs/grpc/test/cpp/util/grpc_tool.h39
-rw-r--r--contrib/libs/grpc/test/cpp/util/grpc_tool_test.cc1344
-rw-r--r--contrib/libs/grpc/test/cpp/util/metrics_server.cc117
-rw-r--r--contrib/libs/grpc/test/cpp/util/metrics_server.h98
-rw-r--r--contrib/libs/grpc/test/cpp/util/proto_file_parser.cc323
-rw-r--r--contrib/libs/grpc/test/cpp/util/proto_file_parser.h129
-rw-r--r--contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.cc333
-rw-r--r--contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.h111
-rw-r--r--contrib/libs/grpc/test/cpp/util/service_describer.cc92
-rw-r--r--contrib/libs/grpc/test/cpp/util/service_describer.h42
-rw-r--r--contrib/libs/grpc/test/cpp/util/slice_test.cc144
-rw-r--r--contrib/libs/grpc/test/cpp/util/string_ref_helper.cc29
-rw-r--r--contrib/libs/grpc/test/cpp/util/string_ref_helper.h32
-rw-r--r--contrib/libs/grpc/test/cpp/util/string_ref_test.cc205
-rw-r--r--contrib/libs/grpc/test/cpp/util/subprocess.cc44
-rw-r--r--contrib/libs/grpc/test/cpp/util/subprocess.h47
-rw-r--r--contrib/libs/grpc/test/cpp/util/test_config.h30
-rw-r--r--contrib/libs/grpc/test/cpp/util/test_config_cc.cc37
-rw-r--r--contrib/libs/grpc/test/cpp/util/test_credentials_provider.cc181
-rw-r--r--contrib/libs/grpc/test/cpp/util/test_credentials_provider.h85
-rw-r--r--contrib/libs/grpc/test/cpp/util/time_test.cc72
-rw-r--r--contrib/libs/grpc/test/cpp/util/ya.make39
41 files changed, 7141 insertions, 0 deletions
diff --git a/contrib/libs/grpc/test/cpp/util/.yandex_meta/licenses.list.txt b/contrib/libs/grpc/test/cpp/util/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..d2dadabed9
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/.yandex_meta/licenses.list.txt
@@ -0,0 +1,32 @@
+====================Apache-2.0====================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+
+====================COPYRIGHT====================
+ * Copyright 2015 gRPC authors.
+
+
+====================COPYRIGHT====================
+ * Copyright 2015-2016 gRPC authors.
+
+
+====================COPYRIGHT====================
+ * Copyright 2016 gRPC authors.
+
+
+====================COPYRIGHT====================
+ * Copyright 2017 gRPC authors.
+
+
+====================COPYRIGHT====================
+ * Copyright 2018 gRPC authors.
diff --git a/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.cc b/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.cc
new file mode 100644
index 0000000000..5971b53075
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.cc
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+namespace grpc {
+namespace testing {
+
+bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message) {
+ std::vector<Slice> slices;
+ (void)buffer->Dump(&slices);
+ TString buf;
+ buf.reserve(buffer->Length());
+ for (auto s = slices.begin(); s != slices.end(); s++) {
+ buf.append(reinterpret_cast<const char*>(s->begin()), s->size());
+ }
+ return message->ParseFromString(buf);
+}
+
+std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
+ grpc::protobuf::Message* message) {
+ TString buf;
+ message->SerializeToString(&buf);
+ Slice slice(buf);
+ return std::unique_ptr<ByteBuffer>(new ByteBuffer(&slice, 1));
+}
+
+bool SerializeToByteBufferInPlace(grpc::protobuf::Message* message,
+ ByteBuffer* buffer) {
+ TString buf;
+ if (!message->SerializeToString(&buf)) {
+ return false;
+ }
+ buffer->Clear();
+ Slice slice(buf);
+ ByteBuffer tmp(&slice, 1);
+ buffer->Swap(&tmp);
+ return true;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.h b/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.h
new file mode 100644
index 0000000000..3d01fb2468
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/byte_buffer_proto_helper.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
+#define GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
+
+#include <memory>
+
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include <grpcpp/support/byte_buffer.h>
+
+namespace grpc {
+namespace testing {
+
+bool ParseFromByteBuffer(ByteBuffer* buffer,
+ ::grpc::protobuf::Message* message);
+
+std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
+ ::grpc::protobuf::Message* message);
+
+bool SerializeToByteBufferInPlace(::grpc::protobuf::Message* message,
+ ByteBuffer* buffer);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
diff --git a/contrib/libs/grpc/test/cpp/util/byte_buffer_test.cc b/contrib/libs/grpc/test/cpp/util/byte_buffer_test.cc
new file mode 100644
index 0000000000..c63f351a8f
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/byte_buffer_test.cc
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc++/support/byte_buffer.h>
+#include <grpcpp/impl/grpc_library.h>
+
+#include <cstring>
+#include <vector>
+
+#include <grpc/grpc.h>
+#include <grpc/slice.h>
+#include <grpcpp/support/slice.h>
+#include <gtest/gtest.h>
+
+#include "test/core/util/test_config.h"
+
+namespace grpc {
+
+static internal::GrpcLibraryInitializer g_gli_initializer;
+
+namespace {
+
+const char* kContent1 = "hello xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char* kContent2 = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy world";
+
+class ByteBufferTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() { grpc_init(); }
+
+ static void TearDownTestCase() { grpc_shutdown(); }
+};
+
+TEST_F(ByteBufferTest, CopyCtor) {
+ ByteBuffer buffer1;
+ EXPECT_FALSE(buffer1.Valid());
+ const ByteBuffer& buffer2 = buffer1;
+ EXPECT_FALSE(buffer2.Valid());
+}
+
+TEST_F(ByteBufferTest, CreateFromSingleSlice) {
+ Slice s(kContent1);
+ ByteBuffer buffer(&s, 1);
+ EXPECT_EQ(strlen(kContent1), buffer.Length());
+}
+
+TEST_F(ByteBufferTest, CreateFromVector) {
+ std::vector<Slice> slices;
+ slices.emplace_back(kContent1);
+ slices.emplace_back(kContent2);
+ ByteBuffer buffer(&slices[0], 2);
+ EXPECT_EQ(strlen(kContent1) + strlen(kContent2), buffer.Length());
+}
+
+TEST_F(ByteBufferTest, Clear) {
+ Slice s(kContent1);
+ ByteBuffer buffer(&s, 1);
+ buffer.Clear();
+ EXPECT_EQ(static_cast<size_t>(0), buffer.Length());
+}
+
+TEST_F(ByteBufferTest, Length) {
+ std::vector<Slice> slices;
+ slices.emplace_back(kContent1);
+ slices.emplace_back(kContent2);
+ ByteBuffer buffer(&slices[0], 2);
+ EXPECT_EQ(strlen(kContent1) + strlen(kContent2), buffer.Length());
+}
+
+bool SliceEqual(const Slice& a, grpc_slice b) {
+ if (a.size() != GRPC_SLICE_LENGTH(b)) {
+ return false;
+ }
+ for (size_t i = 0; i < a.size(); i++) {
+ if (a.begin()[i] != GRPC_SLICE_START_PTR(b)[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+TEST_F(ByteBufferTest, Dump) {
+ grpc_slice hello = grpc_slice_from_copied_string(kContent1);
+ grpc_slice world = grpc_slice_from_copied_string(kContent2);
+ std::vector<Slice> slices;
+ slices.push_back(Slice(hello, Slice::STEAL_REF));
+ slices.push_back(Slice(world, Slice::STEAL_REF));
+ ByteBuffer buffer(&slices[0], 2);
+ slices.clear();
+ (void)buffer.Dump(&slices);
+ EXPECT_TRUE(SliceEqual(slices[0], hello));
+ EXPECT_TRUE(SliceEqual(slices[1], world));
+}
+
+TEST_F(ByteBufferTest, SerializationMakesCopy) {
+ grpc_slice hello = grpc_slice_from_copied_string(kContent1);
+ grpc_slice world = grpc_slice_from_copied_string(kContent2);
+ std::vector<Slice> slices;
+ slices.push_back(Slice(hello, Slice::STEAL_REF));
+ slices.push_back(Slice(world, Slice::STEAL_REF));
+ ByteBuffer send_buffer;
+ bool owned = false;
+ ByteBuffer buffer(&slices[0], 2);
+ slices.clear();
+ auto status = SerializationTraits<ByteBuffer, void>::Serialize(
+ buffer, &send_buffer, &owned);
+ EXPECT_TRUE(status.ok());
+ EXPECT_TRUE(owned);
+ EXPECT_TRUE(send_buffer.Valid());
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
diff --git a/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.cc b/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.cc
new file mode 100644
index 0000000000..d4b4026774
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.cc
@@ -0,0 +1,115 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "test/cpp/util/channel_trace_proto_helper.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include <gtest/gtest.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/json/json.h"
+#include "src/proto/grpc/channelz/channelz.pb.h"
+
+namespace grpc {
+
+namespace {
+
+// Generic helper that takes in a json string, converts it to a proto, and
+// then back to json. This ensures that the json string was correctly formatted
+// according to https://developers.google.com/protocol-buffers/docs/proto3#json
+template <typename Message>
+void VaidateProtoJsonTranslation(const TString& json_str) {
+ Message msg;
+ grpc::protobuf::json::JsonParseOptions parse_options;
+ // If the following line is failing, then uncomment the last line of the
+ // comment, and uncomment the lines that print the two strings. You can
+ // then compare the output, and determine what fields are missing.
+ //
+ // parse_options.ignore_unknown_fields = true;
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, &msg, parse_options);
+ EXPECT_TRUE(s.ok());
+ TString proto_json_str;
+ grpc::protobuf::json::JsonPrintOptions print_options;
+ // We usually do not want this to be true, however it can be helpful to
+ // uncomment and see the output produced then all fields are printed.
+ // print_options.always_print_primitive_fields = true;
+ s = grpc::protobuf::json::MessageToJsonString(msg, &proto_json_str);
+ EXPECT_TRUE(s.ok());
+ // Parse JSON and re-dump to string, to make sure formatting is the
+ // same as what would be generated by our JSON library.
+ grpc_error* error = GRPC_ERROR_NONE;
+ grpc_core::Json parsed_json =
+ grpc_core::Json::Parse(proto_json_str.c_str(), &error);
+ ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
+ ASSERT_EQ(parsed_json.type(), grpc_core::Json::Type::OBJECT);
+ proto_json_str = parsed_json.Dump();
+ // uncomment these to compare the json strings.
+ // gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str());
+ // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str());
+ EXPECT_EQ(json_str, proto_json_str);
+}
+
+} // namespace
+
+namespace testing {
+
+void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_c_str);
+}
+
+void ValidateChannelProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(json_c_str);
+}
+
+void ValidateGetTopChannelsResponseProtoJsonTranslation(
+ const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetTopChannelsResponse>(
+ json_c_str);
+}
+
+void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetChannelResponse>(
+ json_c_str);
+}
+
+void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetServerResponse>(
+ json_c_str);
+}
+
+void ValidateSubchannelProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Subchannel>(json_c_str);
+}
+
+void ValidateServerProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Server>(json_c_str);
+}
+
+void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetServersResponse>(
+ json_c_str);
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.h b/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.h
new file mode 100644
index 0000000000..664e899deb
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/channel_trace_proto_helper.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
+#define GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
+
+namespace grpc {
+namespace testing {
+
+void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str);
+void ValidateChannelProtoJsonTranslation(const char* json_c_str);
+void ValidateGetTopChannelsResponseProtoJsonTranslation(const char* json_c_str);
+void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str);
+void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str);
+void ValidateSubchannelProtoJsonTranslation(const char* json_c_str);
+void ValidateServerProtoJsonTranslation(const char* json_c_str);
+void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
diff --git a/contrib/libs/grpc/test/cpp/util/channelz_sampler.cc b/contrib/libs/grpc/test/cpp/util/channelz_sampler.cc
new file mode 100644
index 0000000000..e6bde68556
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/channelz_sampler.cc
@@ -0,0 +1,588 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <unistd.h>
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <ostream>
+#include <queue>
+#include <util/generic/string.h>
+
+#include "y_absl/strings/str_format.h"
+#include "y_absl/strings/str_join.h"
+#include "gflags/gflags.h"
+#include "google/protobuf/text_format.h"
+#include "grpc/grpc.h"
+#include "grpc/support/port_platform.h"
+#include "grpcpp/channel.h"
+#include "grpcpp/client_context.h"
+#include "grpcpp/create_channel.h"
+#include "grpcpp/ext/channelz_service_plugin.h"
+#include "grpcpp/grpcpp.h"
+#include "grpcpp/security/credentials.h"
+#include "grpcpp/security/server_credentials.h"
+#include "grpcpp/server.h"
+#include "grpcpp/server_builder.h"
+#include "grpcpp/server_context.h"
+#include "src/core/lib/json/json.h"
+#include "src/cpp/server/channelz/channelz_service.h"
+#include "src/proto/grpc/channelz/channelz.pb.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/test_config.h"
+#include "test/cpp/util/test_credentials_provider.h"
+
+DEFINE_string(server_address, "", "channelz server address");
+DEFINE_string(custom_credentials_type, "", "custom credentials type");
+DEFINE_int64(sampling_times, 1, "number of sampling");
+DEFINE_int64(sampling_interval_seconds, 0, "sampling interval in seconds");
+DEFINE_string(output_json, "", "output filename in json format");
+
+namespace {
+using grpc::ClientContext;
+using grpc::Status;
+using grpc::StatusCode;
+using grpc::channelz::v1::GetChannelRequest;
+using grpc::channelz::v1::GetChannelResponse;
+using grpc::channelz::v1::GetServerRequest;
+using grpc::channelz::v1::GetServerResponse;
+using grpc::channelz::v1::GetServerSocketsRequest;
+using grpc::channelz::v1::GetServerSocketsResponse;
+using grpc::channelz::v1::GetServersRequest;
+using grpc::channelz::v1::GetServersResponse;
+using grpc::channelz::v1::GetSocketRequest;
+using grpc::channelz::v1::GetSocketResponse;
+using grpc::channelz::v1::GetSubchannelRequest;
+using grpc::channelz::v1::GetSubchannelResponse;
+using grpc::channelz::v1::GetTopChannelsRequest;
+using grpc::channelz::v1::GetTopChannelsResponse;
+} // namespace
+
+class ChannelzSampler final {
+ public:
+ // Get server_id of a server
+ int64_t GetServerID(const grpc::channelz::v1::Server& server) {
+ return server.ref().server_id();
+ }
+
+ // Get channel_id of a channel
+ inline int64_t GetChannelID(const grpc::channelz::v1::Channel& channel) {
+ return channel.ref().channel_id();
+ }
+
+ // Get subchannel_id of a subchannel
+ inline int64_t GetSubchannelID(
+ const grpc::channelz::v1::Subchannel& subchannel) {
+ return subchannel.ref().subchannel_id();
+ }
+
+ // Get socket_id of a socket
+ inline int64_t GetSocketID(const grpc::channelz::v1::Socket& socket) {
+ return socket.ref().socket_id();
+ }
+
+ // Get name of a server
+ inline TString GetServerName(const grpc::channelz::v1::Server& server) {
+ return server.ref().name();
+ }
+
+ // Get name of a channel
+ inline TString GetChannelName(
+ const grpc::channelz::v1::Channel& channel) {
+ return channel.ref().name();
+ }
+
+ // Get name of a subchannel
+ inline TString GetSubchannelName(
+ const grpc::channelz::v1::Subchannel& subchannel) {
+ return subchannel.ref().name();
+ }
+
+ // Get name of a socket
+ inline TString GetSocketName(const grpc::channelz::v1::Socket& socket) {
+ return socket.ref().name();
+ }
+
+ // Get a channel based on channel_id
+ grpc::channelz::v1::Channel GetChannelRPC(int64_t channel_id) {
+ GetChannelRequest get_channel_request;
+ get_channel_request.set_channel_id(channel_id);
+ GetChannelResponse get_channel_response;
+ ClientContext get_channel_context;
+ get_channel_context.set_deadline(
+ grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
+ Status status = channelz_stub_->GetChannel(
+ &get_channel_context, get_channel_request, &get_channel_response);
+ if (!status.ok()) {
+ gpr_log(GPR_ERROR, "GetChannelRPC failed: %s",
+ get_channel_context.debug_error_string().c_str());
+ GPR_ASSERT(0);
+ }
+ return get_channel_response.channel();
+ }
+
+ // Get a subchannel based on subchannel_id
+ grpc::channelz::v1::Subchannel GetSubchannelRPC(int64_t subchannel_id) {
+ GetSubchannelRequest get_subchannel_request;
+ get_subchannel_request.set_subchannel_id(subchannel_id);
+ GetSubchannelResponse get_subchannel_response;
+ ClientContext get_subchannel_context;
+ get_subchannel_context.set_deadline(
+ grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
+ Status status = channelz_stub_->GetSubchannel(&get_subchannel_context,
+ get_subchannel_request,
+ &get_subchannel_response);
+ if (!status.ok()) {
+ gpr_log(GPR_ERROR, "GetSubchannelRPC failed: %s",
+ get_subchannel_context.debug_error_string().c_str());
+ GPR_ASSERT(0);
+ }
+ return get_subchannel_response.subchannel();
+ }
+
+ // get a socket based on socket_id
+ grpc::channelz::v1::Socket GetSocketRPC(int64_t socket_id) {
+ GetSocketRequest get_socket_request;
+ get_socket_request.set_socket_id(socket_id);
+ GetSocketResponse get_socket_response;
+ ClientContext get_socket_context;
+ get_socket_context.set_deadline(
+ grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
+ Status status = channelz_stub_->GetSocket(
+ &get_socket_context, get_socket_request, &get_socket_response);
+ if (!status.ok()) {
+ gpr_log(GPR_ERROR, "GetSocketRPC failed: %s",
+ get_socket_context.debug_error_string().c_str());
+ GPR_ASSERT(0);
+ }
+ return get_socket_response.socket();
+ }
+
+ // get the descedent channels/subchannels/sockets of a channel
+ // push descedent channels/subchannels to queue for layer traverse
+ // store descedent channels/subchannels/sockets for dumping data
+ void GetChannelDescedence(
+ const grpc::channelz::v1::Channel& channel,
+ std::queue<grpc::channelz::v1::Channel>& channel_queue,
+ std::queue<grpc::channelz::v1::Subchannel>& subchannel_queue) {
+ std::cout << " Channel ID" << GetChannelID(channel) << "_"
+ << GetChannelName(channel) << " descendence - ";
+ if (channel.channel_ref_size() > 0 || channel.subchannel_ref_size() > 0) {
+ if (channel.channel_ref_size() > 0) {
+ std::cout << "channel: ";
+ for (const auto& _channelref : channel.channel_ref()) {
+ int64_t ch_id = _channelref.channel_id();
+ std::cout << "ID" << ch_id << "_" << _channelref.name() << " ";
+ grpc::channelz::v1::Channel ch = GetChannelRPC(ch_id);
+ channel_queue.push(ch);
+ if (CheckID(ch_id)) {
+ all_channels_.push_back(ch);
+ StoreChannelInJson(ch);
+ }
+ }
+ if (channel.subchannel_ref_size() > 0) {
+ std::cout << ", ";
+ }
+ }
+ if (channel.subchannel_ref_size() > 0) {
+ std::cout << "subchannel: ";
+ for (const auto& _subchannelref : channel.subchannel_ref()) {
+ int64_t subch_id = _subchannelref.subchannel_id();
+ std::cout << "ID" << subch_id << "_" << _subchannelref.name() << " ";
+ grpc::channelz::v1::Subchannel subch = GetSubchannelRPC(subch_id);
+ subchannel_queue.push(subch);
+ if (CheckID(subch_id)) {
+ all_subchannels_.push_back(subch);
+ StoreSubchannelInJson(subch);
+ }
+ }
+ }
+ } else if (channel.socket_ref_size() > 0) {
+ std::cout << "socket: ";
+ for (const auto& _socketref : channel.socket_ref()) {
+ int64_t so_id = _socketref.socket_id();
+ std::cout << "ID" << so_id << "_" << _socketref.name() << " ";
+ grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
+ if (CheckID(so_id)) {
+ all_sockets_.push_back(so);
+ StoreSocketInJson(so);
+ }
+ }
+ }
+ std::cout << std::endl;
+ }
+
+ // get the descedent channels/subchannels/sockets of a subchannel
+ // push descedent channels/subchannels to queue for layer traverse
+ // store descedent channels/subchannels/sockets for dumping data
+ void GetSubchannelDescedence(
+ grpc::channelz::v1::Subchannel& subchannel,
+ std::queue<grpc::channelz::v1::Channel>& channel_queue,
+ std::queue<grpc::channelz::v1::Subchannel>& subchannel_queue) {
+ std::cout << " Subchannel ID" << GetSubchannelID(subchannel) << "_"
+ << GetSubchannelName(subchannel) << " descendence - ";
+ if (subchannel.channel_ref_size() > 0 ||
+ subchannel.subchannel_ref_size() > 0) {
+ if (subchannel.channel_ref_size() > 0) {
+ std::cout << "channel: ";
+ for (const auto& _channelref : subchannel.channel_ref()) {
+ int64_t ch_id = _channelref.channel_id();
+ std::cout << "ID" << ch_id << "_" << _channelref.name() << " ";
+ grpc::channelz::v1::Channel ch = GetChannelRPC(ch_id);
+ channel_queue.push(ch);
+ if (CheckID(ch_id)) {
+ all_channels_.push_back(ch);
+ StoreChannelInJson(ch);
+ }
+ }
+ if (subchannel.subchannel_ref_size() > 0) {
+ std::cout << ", ";
+ }
+ }
+ if (subchannel.subchannel_ref_size() > 0) {
+ std::cout << "subchannel: ";
+ for (const auto& _subchannelref : subchannel.subchannel_ref()) {
+ int64_t subch_id = _subchannelref.subchannel_id();
+ std::cout << "ID" << subch_id << "_" << _subchannelref.name() << " ";
+ grpc::channelz::v1::Subchannel subch = GetSubchannelRPC(subch_id);
+ subchannel_queue.push(subch);
+ if (CheckID(subch_id)) {
+ all_subchannels_.push_back(subch);
+ StoreSubchannelInJson(subch);
+ }
+ }
+ }
+ } else if (subchannel.socket_ref_size() > 0) {
+ std::cout << "socket: ";
+ for (const auto& _socketref : subchannel.socket_ref()) {
+ int64_t so_id = _socketref.socket_id();
+ std::cout << "ID" << so_id << "_" << _socketref.name() << " ";
+ grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
+ if (CheckID(so_id)) {
+ all_sockets_.push_back(so);
+ StoreSocketInJson(so);
+ }
+ }
+ }
+ std::cout << std::endl;
+ }
+
+ // Set up the channelz sampler client
+ // Initialize json as an array
+ void Setup(const TString& custom_credentials_type,
+ const TString& server_address) {
+ json_ = grpc_core::Json::Array();
+ rpc_timeout_seconds_ = 20;
+ grpc::ChannelArguments channel_args;
+ std::shared_ptr<grpc::ChannelCredentials> channel_creds =
+ grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
+ custom_credentials_type, &channel_args);
+ if (!channel_creds) {
+ gpr_log(GPR_ERROR,
+ "Wrong user credential type: %s. Allowed credential types: "
+ "INSECURE_CREDENTIALS, ssl, alts, google_default_credentials.",
+ custom_credentials_type.c_str());
+ GPR_ASSERT(0);
+ }
+ std::shared_ptr<grpc::Channel> channel =
+ CreateChannel(server_address, channel_creds);
+ channelz_stub_ = grpc::channelz::v1::Channelz::NewStub(channel);
+ }
+
+ // Get all servers, keep querying until getting all
+ // Store servers for dumping data
+ // Need to check id repeating for servers
+ void GetServersRPC() {
+ int64_t server_start_id = 0;
+ while (true) {
+ GetServersRequest get_servers_request;
+ GetServersResponse get_servers_response;
+ ClientContext get_servers_context;
+ get_servers_context.set_deadline(
+ grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
+ get_servers_request.set_start_server_id(server_start_id);
+ Status status = channelz_stub_->GetServers(
+ &get_servers_context, get_servers_request, &get_servers_response);
+ if (!status.ok()) {
+ if (status.error_code() == StatusCode::UNIMPLEMENTED) {
+ gpr_log(GPR_ERROR,
+ "Error status UNIMPLEMENTED. Please check and make sure "
+ "channelz has been registered on the server being queried.");
+ } else {
+ gpr_log(GPR_ERROR,
+ "GetServers RPC with GetServersRequest.server_start_id=%d, "
+ "failed: %s",
+ int(server_start_id),
+ get_servers_context.debug_error_string().c_str());
+ }
+ GPR_ASSERT(0);
+ }
+ for (const auto& _server : get_servers_response.server()) {
+ all_servers_.push_back(_server);
+ StoreServerInJson(_server);
+ }
+ if (!get_servers_response.end()) {
+ server_start_id = GetServerID(all_servers_.back()) + 1;
+ } else {
+ break;
+ }
+ }
+ std::cout << "Number of servers = " << all_servers_.size() << std::endl;
+ }
+
+ // Get sockets that belongs to servers
+ // Store sockets for dumping data
+ void GetSocketsOfServers() {
+ for (const auto& _server : all_servers_) {
+ std::cout << "Server ID" << GetServerID(_server) << "_"
+ << GetServerName(_server) << " listen_socket - ";
+ for (const auto& _socket : _server.listen_socket()) {
+ int64_t so_id = _socket.socket_id();
+ std::cout << "ID" << so_id << "_" << _socket.name() << " ";
+ if (CheckID(so_id)) {
+ grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
+ all_sockets_.push_back(so);
+ StoreSocketInJson(so);
+ }
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ // Get all top channels, keep querying until getting all
+ // Store channels for dumping data
+ // No need to check id repeating for top channels
+ void GetTopChannelsRPC() {
+ int64_t channel_start_id = 0;
+ while (true) {
+ GetTopChannelsRequest get_top_channels_request;
+ GetTopChannelsResponse get_top_channels_response;
+ ClientContext get_top_channels_context;
+ get_top_channels_context.set_deadline(
+ grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
+ get_top_channels_request.set_start_channel_id(channel_start_id);
+ Status status = channelz_stub_->GetTopChannels(
+ &get_top_channels_context, get_top_channels_request,
+ &get_top_channels_response);
+ if (!status.ok()) {
+ gpr_log(GPR_ERROR,
+ "GetTopChannels RPC with "
+ "GetTopChannelsRequest.channel_start_id=%d failed: %s",
+ int(channel_start_id),
+ get_top_channels_context.debug_error_string().c_str());
+ GPR_ASSERT(0);
+ }
+ for (const auto& _topchannel : get_top_channels_response.channel()) {
+ top_channels_.push_back(_topchannel);
+ all_channels_.push_back(_topchannel);
+ StoreChannelInJson(_topchannel);
+ }
+ if (!get_top_channels_response.end()) {
+ channel_start_id = GetChannelID(top_channels_.back()) + 1;
+ } else {
+ break;
+ }
+ }
+ std::cout << std::endl
+ << "Number of top channels = " << top_channels_.size()
+ << std::endl;
+ }
+
+ // layer traverse for each top channel
+ void TraverseTopChannels() {
+ for (const auto& _topchannel : top_channels_) {
+ int tree_depth = 0;
+ std::queue<grpc::channelz::v1::Channel> channel_queue;
+ std::queue<grpc::channelz::v1::Subchannel> subchannel_queue;
+ std::cout << "Tree depth = " << tree_depth << std::endl;
+ GetChannelDescedence(_topchannel, channel_queue, subchannel_queue);
+ while (!channel_queue.empty() || !subchannel_queue.empty()) {
+ ++tree_depth;
+ std::cout << "Tree depth = " << tree_depth << std::endl;
+ int ch_q_size = channel_queue.size();
+ int subch_q_size = subchannel_queue.size();
+ for (int i = 0; i < ch_q_size; ++i) {
+ grpc::channelz::v1::Channel ch = channel_queue.front();
+ channel_queue.pop();
+ GetChannelDescedence(ch, channel_queue, subchannel_queue);
+ }
+ for (int i = 0; i < subch_q_size; ++i) {
+ grpc::channelz::v1::Subchannel subch = subchannel_queue.front();
+ subchannel_queue.pop();
+ GetSubchannelDescedence(subch, channel_queue, subchannel_queue);
+ }
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ // dump data of all entities to stdout
+ void DumpStdout() {
+ TString data_str;
+ for (const auto& _channel : all_channels_) {
+ std::cout << "channel ID" << GetChannelID(_channel) << "_"
+ << GetChannelName(_channel) << " data:" << std::endl;
+ // TODO(mohanli): TextFormat::PrintToString records time as seconds and
+ // nanos. Need a more human readable way.
+ ::google::protobuf::TextFormat::PrintToString(_channel.data(), &data_str);
+ printf("%s\n", data_str.c_str());
+ }
+ for (const auto& _subchannel : all_subchannels_) {
+ std::cout << "subchannel ID" << GetSubchannelID(_subchannel) << "_"
+ << GetSubchannelName(_subchannel) << " data:" << std::endl;
+ ::google::protobuf::TextFormat::PrintToString(_subchannel.data(),
+ &data_str);
+ printf("%s\n", data_str.c_str());
+ }
+ for (const auto& _server : all_servers_) {
+ std::cout << "server ID" << GetServerID(_server) << "_"
+ << GetServerName(_server) << " data:" << std::endl;
+ ::google::protobuf::TextFormat::PrintToString(_server.data(), &data_str);
+ printf("%s\n", data_str.c_str());
+ }
+ for (const auto& _socket : all_sockets_) {
+ std::cout << "socket ID" << GetSocketID(_socket) << "_"
+ << GetSocketName(_socket) << " data:" << std::endl;
+ ::google::protobuf::TextFormat::PrintToString(_socket.data(), &data_str);
+ printf("%s\n", data_str.c_str());
+ }
+ }
+
+ // Store a channel in Json
+ void StoreChannelInJson(const grpc::channelz::v1::Channel& channel) {
+ TString id = grpc::to_string(GetChannelID(channel));
+ TString type = "Channel";
+ TString description;
+ ::google::protobuf::TextFormat::PrintToString(channel.data(), &description);
+ grpc_core::Json description_json = grpc_core::Json(description);
+ StoreEntityInJson(id, type, description_json);
+ }
+
+ // Store a subchannel in Json
+ void StoreSubchannelInJson(const grpc::channelz::v1::Subchannel& subchannel) {
+ TString id = grpc::to_string(GetSubchannelID(subchannel));
+ TString type = "Subchannel";
+ TString description;
+ ::google::protobuf::TextFormat::PrintToString(subchannel.data(),
+ &description);
+ grpc_core::Json description_json = grpc_core::Json(description);
+ StoreEntityInJson(id, type, description_json);
+ }
+
+ // Store a server in Json
+ void StoreServerInJson(const grpc::channelz::v1::Server& server) {
+ TString id = grpc::to_string(GetServerID(server));
+ TString type = "Server";
+ TString description;
+ ::google::protobuf::TextFormat::PrintToString(server.data(), &description);
+ grpc_core::Json description_json = grpc_core::Json(description);
+ StoreEntityInJson(id, type, description_json);
+ }
+
+ // Store a socket in Json
+ void StoreSocketInJson(const grpc::channelz::v1::Socket& socket) {
+ TString id = grpc::to_string(GetSocketID(socket));
+ TString type = "Socket";
+ TString description;
+ ::google::protobuf::TextFormat::PrintToString(socket.data(), &description);
+ grpc_core::Json description_json = grpc_core::Json(description);
+ StoreEntityInJson(id, type, description_json);
+ }
+
+ // Store an entity in Json
+ void StoreEntityInJson(TString& id, TString& type,
+ const grpc_core::Json& description) {
+ TString start, finish;
+ gpr_timespec ago = gpr_time_sub(
+ now_,
+ gpr_time_from_seconds(FLAGS_sampling_interval_seconds, GPR_TIMESPAN));
+ std::stringstream ss;
+ const time_t time_now = now_.tv_sec;
+ ss << std::put_time(std::localtime(&time_now), "%F %T");
+ finish = ss.str(); // example: "2019-02-01 12:12:18"
+ ss.str("");
+ const time_t time_ago = ago.tv_sec;
+ ss << std::put_time(std::localtime(&time_ago), "%F %T");
+ start = ss.str();
+ grpc_core::Json obj =
+ grpc_core::Json::Object{{"Task", y_absl::StrFormat("%s_ID%s", type, id)},
+ {"Start", start},
+ {"Finish", finish},
+ {"ID", id},
+ {"Type", type},
+ {"Description", description}};
+ json_.mutable_array()->push_back(obj);
+ }
+
+ // Dump data in json
+ TString DumpJson() { return json_.Dump(); }
+
+ // Check if one entity has been recorded
+ bool CheckID(int64_t id) {
+ if (id_set_.count(id) == 0) {
+ id_set_.insert(id);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Record current time
+ void RecordNow() { now_ = gpr_now(GPR_CLOCK_REALTIME); }
+
+ private:
+ std::unique_ptr<grpc::channelz::v1::Channelz::Stub> channelz_stub_;
+ std::vector<grpc::channelz::v1::Channel> top_channels_;
+ std::vector<grpc::channelz::v1::Server> all_servers_;
+ std::vector<grpc::channelz::v1::Channel> all_channels_;
+ std::vector<grpc::channelz::v1::Subchannel> all_subchannels_;
+ std::vector<grpc::channelz::v1::Socket> all_sockets_;
+ std::unordered_set<int64_t> id_set_;
+ grpc_core::Json json_;
+ int64_t rpc_timeout_seconds_;
+ gpr_timespec now_;
+};
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ grpc::testing::InitTest(&argc, &argv, true);
+ std::ofstream output_file(FLAGS_output_json);
+ for (int i = 0; i < FLAGS_sampling_times; ++i) {
+ ChannelzSampler channelz_sampler;
+ channelz_sampler.Setup(FLAGS_custom_credentials_type, FLAGS_server_address);
+ std::cout << "Wait for sampling interval "
+ << FLAGS_sampling_interval_seconds << "s..." << std::endl;
+ const gpr_timespec kDelay = gpr_time_add(
+ gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_seconds(FLAGS_sampling_interval_seconds, GPR_TIMESPAN));
+ gpr_sleep_until(kDelay);
+ std::cout << "##### " << i << "th sampling #####" << std::endl;
+ channelz_sampler.RecordNow();
+ channelz_sampler.GetServersRPC();
+ channelz_sampler.GetSocketsOfServers();
+ channelz_sampler.GetTopChannelsRPC();
+ channelz_sampler.TraverseTopChannels();
+ channelz_sampler.DumpStdout();
+ if (!FLAGS_output_json.empty()) {
+ output_file << channelz_sampler.DumpJson() << "\n" << std::flush;
+ }
+ }
+ output_file.close();
+ return 0;
+}
diff --git a/contrib/libs/grpc/test/cpp/util/channelz_sampler_test.cc b/contrib/libs/grpc/test/cpp/util/channelz_sampler_test.cc
new file mode 100644
index 0000000000..d81dbb0d05
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/channelz_sampler_test.cc
@@ -0,0 +1,176 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <util/generic/string.h>
+#include <thread>
+
+#include "grpc/grpc.h"
+#include "grpc/support/alloc.h"
+#include "grpc/support/port_platform.h"
+#include "grpcpp/channel.h"
+#include "grpcpp/client_context.h"
+#include "grpcpp/create_channel.h"
+#include "grpcpp/ext/channelz_service_plugin.h"
+#include "grpcpp/grpcpp.h"
+#include "grpcpp/security/credentials.h"
+#include "grpcpp/security/server_credentials.h"
+#include "grpcpp/server.h"
+#include "grpcpp/server_builder.h"
+#include "grpcpp/server_context.h"
+#include "gtest/gtest.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/cpp/server/channelz/channelz_service.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/subprocess.h"
+#include "test/cpp/util/test_credentials_provider.h"
+
+static TString g_root;
+
+namespace {
+using grpc::ClientContext;
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+} // namespace
+
+// Test variables
+TString server_address("0.0.0.0:10000");
+TString custom_credentials_type("INSECURE_CREDENTIALS");
+TString sampling_times = "2";
+TString sampling_interval_seconds = "3";
+TString output_json("output.json");
+
+// Creata an echo server
+class EchoServerImpl final : public grpc::testing::TestService::Service {
+ Status EmptyCall(::grpc::ServerContext* context,
+ const grpc::testing::Empty* request,
+ grpc::testing::Empty* response) {
+ return Status::OK;
+ }
+};
+
+// Run client in a thread
+void RunClient(const TString& client_id, gpr_event* done_ev) {
+ grpc::ChannelArguments channel_args;
+ std::shared_ptr<grpc::ChannelCredentials> channel_creds =
+ grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
+ custom_credentials_type, &channel_args);
+ std::unique_ptr<grpc::testing::TestService::Stub> stub =
+ grpc::testing::TestService::NewStub(
+ grpc::CreateChannel(server_address, channel_creds));
+ gpr_log(GPR_INFO, "Client %s is echoing!", client_id.c_str());
+ while (true) {
+ if (gpr_event_wait(done_ev, grpc_timeout_seconds_to_deadline(1)) !=
+ nullptr) {
+ return;
+ }
+ grpc::testing::Empty request;
+ grpc::testing::Empty response;
+ ClientContext context;
+ Status status = stub->EmptyCall(&context, request, &response);
+ if (!status.ok()) {
+ gpr_log(GPR_ERROR, "Client echo failed.");
+ GPR_ASSERT(0);
+ }
+ }
+}
+
+// Create the channelz to test the connection to the server
+bool WaitForConnection(int wait_server_seconds) {
+ grpc::ChannelArguments channel_args;
+ std::shared_ptr<grpc::ChannelCredentials> channel_creds =
+ grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
+ custom_credentials_type, &channel_args);
+ auto channel = grpc::CreateChannel(server_address, channel_creds);
+ return channel->WaitForConnected(
+ grpc_timeout_seconds_to_deadline(wait_server_seconds));
+}
+
+// Test the channelz sampler
+TEST(ChannelzSamplerTest, SimpleTest) {
+ // start server
+ ::grpc::channelz::experimental::InitChannelzService();
+ EchoServerImpl service;
+ grpc::ServerBuilder builder;
+ auto server_creds =
+ grpc::testing::GetCredentialsProvider()->GetServerCredentials(
+ custom_credentials_type);
+ builder.AddListeningPort(server_address, server_creds);
+ builder.RegisterService(&service);
+ std::unique_ptr<Server> server(builder.BuildAndStart());
+ gpr_log(GPR_INFO, "Server listening on %s", server_address.c_str());
+ const int kWaitForServerSeconds = 10;
+ ASSERT_TRUE(WaitForConnection(kWaitForServerSeconds));
+ // client threads
+ gpr_event done_ev1, done_ev2;
+ gpr_event_init(&done_ev1);
+ gpr_event_init(&done_ev2);
+ std::thread client_thread_1(RunClient, "1", &done_ev1);
+ std::thread client_thread_2(RunClient, "2", &done_ev2);
+ // Run the channelz sampler
+ grpc::SubProcess* test_driver = new grpc::SubProcess(
+ {g_root + "/channelz_sampler", "--server_address=" + server_address,
+ "--custom_credentials_type=" + custom_credentials_type,
+ "--sampling_times=" + sampling_times,
+ "--sampling_interval_seconds=" + sampling_interval_seconds,
+ "--output_json=" + output_json});
+ int status = test_driver->Join();
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status)) {
+ gpr_log(GPR_ERROR,
+ "Channelz sampler test test-runner exited with code %d",
+ WEXITSTATUS(status));
+ GPR_ASSERT(0); // log the line number of the assertion failure
+ }
+ } else if (WIFSIGNALED(status)) {
+ gpr_log(GPR_ERROR, "Channelz sampler test test-runner ended from signal %d",
+ WTERMSIG(status));
+ GPR_ASSERT(0);
+ } else {
+ gpr_log(GPR_ERROR,
+ "Channelz sampler test test-runner ended with unknown status %d",
+ status);
+ GPR_ASSERT(0);
+ }
+ delete test_driver;
+ gpr_event_set(&done_ev1, (void*)1);
+ gpr_event_set(&done_ev2, (void*)1);
+ client_thread_1.join();
+ client_thread_2.join();
+}
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ TString me = argv[0];
+ auto lslash = me.rfind('/');
+ if (lslash != TString::npos) {
+ g_root = me.substr(0, lslash);
+ } else {
+ g_root = ".";
+ }
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
diff --git a/contrib/libs/grpc/test/cpp/util/cli_call.cc b/contrib/libs/grpc/test/cpp/util/cli_call.cc
new file mode 100644
index 0000000000..5b3631667f
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/cli_call.cc
@@ -0,0 +1,229 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/cli_call.h"
+
+#include <grpc/grpc.h>
+#include <grpc/slice.h>
+#include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/support/byte_buffer.h>
+
+#include <cmath>
+#include <iostream>
+#include <utility>
+
+namespace grpc {
+namespace testing {
+namespace {
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
+} // namespace
+
+Status CliCall::Call(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& method, const TString& request,
+ TString* response,
+ const OutgoingMetadataContainer& metadata,
+ IncomingMetadataContainer* server_initial_metadata,
+ IncomingMetadataContainer* server_trailing_metadata) {
+ CliCall call(channel, method, metadata);
+ call.Write(request);
+ call.WritesDone();
+ if (!call.Read(response, server_initial_metadata)) {
+ fprintf(stderr, "Failed to read response.\n");
+ }
+ return call.Finish(server_trailing_metadata);
+}
+
+CliCall::CliCall(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& method,
+ const OutgoingMetadataContainer& metadata, CliArgs args)
+ : stub_(new grpc::GenericStub(channel)) {
+ gpr_mu_init(&write_mu_);
+ gpr_cv_init(&write_cv_);
+ if (!metadata.empty()) {
+ for (OutgoingMetadataContainer::const_iterator iter = metadata.begin();
+ iter != metadata.end(); ++iter) {
+ ctx_.AddMetadata(iter->first, iter->second);
+ }
+ }
+
+ // Set deadline if timeout > 0 (default value -1 if no timeout specified)
+ if (args.timeout > 0) {
+ int64_t timeout_in_ns = ceil(args.timeout * 1e9);
+
+ // Convert timeout (in nanoseconds) to a deadline
+ auto deadline =
+ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_nanos(timeout_in_ns, GPR_TIMESPAN));
+ ctx_.set_deadline(deadline);
+ } else if (args.timeout != -1) {
+ fprintf(
+ stderr,
+ "WARNING: Non-positive timeout value, skipping setting deadline.\n");
+ }
+
+ call_ = stub_->PrepareCall(&ctx_, method, &cq_);
+ call_->StartCall(tag(1));
+ void* got_tag;
+ bool ok;
+ cq_.Next(&got_tag, &ok);
+ GPR_ASSERT(ok);
+}
+
+CliCall::~CliCall() {
+ gpr_cv_destroy(&write_cv_);
+ gpr_mu_destroy(&write_mu_);
+}
+
+void CliCall::Write(const TString& request) {
+ void* got_tag;
+ bool ok;
+
+ gpr_slice s = gpr_slice_from_copied_buffer(request.data(), request.size());
+ grpc::Slice req_slice(s, grpc::Slice::STEAL_REF);
+ grpc::ByteBuffer send_buffer(&req_slice, 1);
+ call_->Write(send_buffer, tag(2));
+ cq_.Next(&got_tag, &ok);
+ GPR_ASSERT(ok);
+}
+
+bool CliCall::Read(TString* response,
+ IncomingMetadataContainer* server_initial_metadata) {
+ void* got_tag;
+ bool ok;
+
+ grpc::ByteBuffer recv_buffer;
+ call_->Read(&recv_buffer, tag(3));
+
+ if (!cq_.Next(&got_tag, &ok) || !ok) {
+ return false;
+ }
+ std::vector<grpc::Slice> slices;
+ GPR_ASSERT(recv_buffer.Dump(&slices).ok());
+
+ response->clear();
+ for (size_t i = 0; i < slices.size(); i++) {
+ response->append(reinterpret_cast<const char*>(slices[i].begin()),
+ slices[i].size());
+ }
+ if (server_initial_metadata) {
+ *server_initial_metadata = ctx_.GetServerInitialMetadata();
+ }
+ return true;
+}
+
+void CliCall::WritesDone() {
+ void* got_tag;
+ bool ok;
+
+ call_->WritesDone(tag(4));
+ cq_.Next(&got_tag, &ok);
+ GPR_ASSERT(ok);
+}
+
+void CliCall::WriteAndWait(const TString& request) {
+ grpc::Slice req_slice(request);
+ grpc::ByteBuffer send_buffer(&req_slice, 1);
+
+ gpr_mu_lock(&write_mu_);
+ call_->Write(send_buffer, tag(2));
+ write_done_ = false;
+ while (!write_done_) {
+ gpr_cv_wait(&write_cv_, &write_mu_, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ gpr_mu_unlock(&write_mu_);
+}
+
+void CliCall::WritesDoneAndWait() {
+ gpr_mu_lock(&write_mu_);
+ call_->WritesDone(tag(4));
+ write_done_ = false;
+ while (!write_done_) {
+ gpr_cv_wait(&write_cv_, &write_mu_, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ gpr_mu_unlock(&write_mu_);
+}
+
+bool CliCall::ReadAndMaybeNotifyWrite(
+ TString* response, IncomingMetadataContainer* server_initial_metadata) {
+ void* got_tag;
+ bool ok;
+ grpc::ByteBuffer recv_buffer;
+
+ call_->Read(&recv_buffer, tag(3));
+ bool cq_result = cq_.Next(&got_tag, &ok);
+
+ while (got_tag != tag(3)) {
+ gpr_mu_lock(&write_mu_);
+ write_done_ = true;
+ gpr_cv_signal(&write_cv_);
+ gpr_mu_unlock(&write_mu_);
+
+ cq_result = cq_.Next(&got_tag, &ok);
+ if (got_tag == tag(2)) {
+ GPR_ASSERT(ok);
+ }
+ }
+
+ if (!cq_result || !ok) {
+ // If the RPC is ended on the server side, we should still wait for the
+ // pending write on the client side to be done.
+ if (!ok) {
+ gpr_mu_lock(&write_mu_);
+ if (!write_done_) {
+ cq_.Next(&got_tag, &ok);
+ GPR_ASSERT(got_tag != tag(2));
+ write_done_ = true;
+ gpr_cv_signal(&write_cv_);
+ }
+ gpr_mu_unlock(&write_mu_);
+ }
+ return false;
+ }
+
+ std::vector<grpc::Slice> slices;
+ GPR_ASSERT(recv_buffer.Dump(&slices).ok());
+ response->clear();
+ for (size_t i = 0; i < slices.size(); i++) {
+ response->append(reinterpret_cast<const char*>(slices[i].begin()),
+ slices[i].size());
+ }
+ if (server_initial_metadata) {
+ *server_initial_metadata = ctx_.GetServerInitialMetadata();
+ }
+ return true;
+}
+
+Status CliCall::Finish(IncomingMetadataContainer* server_trailing_metadata) {
+ void* got_tag;
+ bool ok;
+ grpc::Status status;
+
+ call_->Finish(&status, tag(5));
+ cq_.Next(&got_tag, &ok);
+ GPR_ASSERT(ok);
+ if (server_trailing_metadata) {
+ *server_trailing_metadata = ctx_.GetServerTrailingMetadata();
+ }
+
+ return status;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/cli_call.h b/contrib/libs/grpc/test/cpp/util/cli_call.h
new file mode 100644
index 0000000000..79d00d99f4
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/cli_call.h
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CLI_CALL_H
+#define GRPC_TEST_CPP_UTIL_CLI_CALL_H
+
+#include <grpcpp/channel.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/string_ref.h>
+
+#include <map>
+
+namespace grpc {
+
+class ClientContext;
+
+struct CliArgs {
+ double timeout = -1;
+};
+
+namespace testing {
+
+// CliCall handles the sending and receiving of generic messages given the name
+// of the remote method. This class is only used by GrpcTool. Its thread-safe
+// and thread-unsafe methods should not be used together.
+class CliCall final {
+ public:
+ typedef std::multimap<TString, TString> OutgoingMetadataContainer;
+ typedef std::multimap<grpc::string_ref, grpc::string_ref>
+ IncomingMetadataContainer;
+
+ CliCall(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& method, const OutgoingMetadataContainer& metadata,
+ CliArgs args);
+ CliCall(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& method, const OutgoingMetadataContainer& metadata)
+ : CliCall(channel, method, metadata, CliArgs{}) {}
+
+ ~CliCall();
+
+ // Perform an unary generic RPC.
+ static Status Call(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& method, const TString& request,
+ TString* response,
+ const OutgoingMetadataContainer& metadata,
+ IncomingMetadataContainer* server_initial_metadata,
+ IncomingMetadataContainer* server_trailing_metadata);
+
+ // Send a generic request message in a synchronous manner. NOT thread-safe.
+ void Write(const TString& request);
+
+ // Send a generic request message in a synchronous manner. NOT thread-safe.
+ void WritesDone();
+
+ // Receive a generic response message in a synchronous manner.NOT thread-safe.
+ bool Read(TString* response,
+ IncomingMetadataContainer* server_initial_metadata);
+
+ // Thread-safe write. Must be used with ReadAndMaybeNotifyWrite. Send out a
+ // generic request message and wait for ReadAndMaybeNotifyWrite to finish it.
+ void WriteAndWait(const TString& request);
+
+ // Thread-safe WritesDone. Must be used with ReadAndMaybeNotifyWrite. Send out
+ // WritesDone for gereneric request messages and wait for
+ // ReadAndMaybeNotifyWrite to finish it.
+ void WritesDoneAndWait();
+
+ // Thread-safe Read. Blockingly receive a generic response message. Notify
+ // writes if they are finished when this read is waiting for a resposne.
+ bool ReadAndMaybeNotifyWrite(
+ TString* response,
+ IncomingMetadataContainer* server_initial_metadata);
+
+ // Finish the RPC.
+ Status Finish(IncomingMetadataContainer* server_trailing_metadata);
+
+ TString peer() const { return ctx_.peer(); }
+
+ private:
+ std::unique_ptr<grpc::GenericStub> stub_;
+ grpc::ClientContext ctx_;
+ std::unique_ptr<grpc::GenericClientAsyncReaderWriter> call_;
+ grpc::CompletionQueue cq_;
+ gpr_mu write_mu_;
+ gpr_cv write_cv_; // Protected by write_mu_;
+ bool write_done_; // Portected by write_mu_;
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_CLI_CALL_H
diff --git a/contrib/libs/grpc/test/cpp/util/cli_call_test.cc b/contrib/libs/grpc/test/cpp/util/cli_call_test.cc
new file mode 100644
index 0000000000..4f0544b2e5
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/cli_call_test.cc
@@ -0,0 +1,128 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/cli_call.h"
+
+#include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.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/util/string_ref_helper.h"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+
+namespace grpc {
+namespace testing {
+
+class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+ Status Echo(ServerContext* context, const EchoRequest* request,
+ EchoResponse* response) override {
+ if (!context->client_metadata().empty()) {
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = context->client_metadata().begin();
+ iter != context->client_metadata().end(); ++iter) {
+ context->AddInitialMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ }
+ context->AddTrailingMetadata("trailing_key", "trailing_value");
+ response->set_message(request->message());
+ return Status::OK;
+ }
+};
+
+class CliCallTest : public ::testing::Test {
+ protected:
+ CliCallTest() {}
+
+ void SetUp() override {
+ int port = grpc_pick_unused_port_or_die();
+ server_address_ << "localhost:" << port;
+ // Setup server
+ ServerBuilder builder;
+ builder.AddListeningPort(server_address_.str(),
+ InsecureServerCredentials());
+ builder.RegisterService(&service_);
+ server_ = builder.BuildAndStart();
+ }
+
+ void TearDown() override { server_->Shutdown(); }
+
+ void ResetStub() {
+ channel_ = grpc::CreateChannel(server_address_.str(),
+ InsecureChannelCredentials());
+ stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+ }
+
+ std::shared_ptr<Channel> channel_;
+ std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+ std::unique_ptr<Server> server_;
+ std::ostringstream server_address_;
+ TestServiceImpl service_;
+};
+
+// Send a rpc with a normal stub and then a CliCall. Verify they match.
+TEST_F(CliCallTest, SimpleRpc) {
+ ResetStub();
+ // Normal stub.
+ EchoRequest request;
+ EchoResponse response;
+ 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.ok());
+
+ const TString kMethod("/grpc.testing.EchoTestService/Echo");
+ TString request_bin, response_bin, expected_response_bin;
+ EXPECT_TRUE(request.SerializeToString(&request_bin));
+ EXPECT_TRUE(response.SerializeToString(&expected_response_bin));
+ std::multimap<TString, TString> client_metadata;
+ std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
+ server_trailing_metadata;
+ client_metadata.insert(std::pair<TString, TString>("key1", "val1"));
+ Status s2 = CliCall::Call(channel_, kMethod, request_bin, &response_bin,
+ client_metadata, &server_initial_metadata,
+ &server_trailing_metadata);
+ EXPECT_TRUE(s2.ok());
+
+ EXPECT_EQ(expected_response_bin, response_bin);
+ EXPECT_EQ(context.GetServerInitialMetadata(), server_initial_metadata);
+ EXPECT_EQ(context.GetServerTrailingMetadata(), server_trailing_metadata);
+}
+
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/libs/grpc/test/cpp/util/cli_credentials.cc b/contrib/libs/grpc/test/cpp/util/cli_credentials.cc
new file mode 100644
index 0000000000..efd548eb9b
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/cli_credentials.cc
@@ -0,0 +1,245 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/cli_credentials.h"
+
+#include <gflags/gflags.h>
+#include <grpc/slice.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/slice.h>
+
+#include "src/core/lib/iomgr/load_file.h"
+
+DEFINE_bool(
+ enable_ssl, false,
+ "Whether to use ssl/tls. Deprecated. Use --channel_creds_type=ssl.");
+DEFINE_bool(use_auth, false,
+ "Whether to create default google credentials. Deprecated. Use "
+ "--channel_creds_type=gdc.");
+DEFINE_string(
+ access_token, "",
+ "The access token that will be sent to the server to authenticate RPCs. "
+ "Deprecated. Use --call_creds=access_token=<token>.");
+DEFINE_string(
+ ssl_target, "",
+ "If not empty, treat the server host name as this for ssl/tls certificate "
+ "validation.");
+DEFINE_string(
+ ssl_client_cert, "",
+ "If not empty, load this PEM formatted client certificate file. Requires "
+ "use of --ssl_client_key.");
+DEFINE_string(
+ ssl_client_key, "",
+ "If not empty, load this PEM formatted private key. Requires use of "
+ "--ssl_client_cert");
+DEFINE_string(
+ local_connect_type, "local_tcp",
+ "The type of local connections for which local channel credentials will "
+ "be applied. Should be local_tcp or uds.");
+DEFINE_string(
+ channel_creds_type, "",
+ "The channel creds type: insecure, ssl, gdc (Google Default Credentials), "
+ "alts, or local.");
+DEFINE_string(
+ call_creds, "",
+ "Call credentials to use: none (default), or access_token=<token>. If "
+ "provided, the call creds are composited on top of channel creds.");
+
+namespace grpc {
+namespace testing {
+
+namespace {
+
+const char ACCESS_TOKEN_PREFIX[] = "access_token=";
+constexpr int ACCESS_TOKEN_PREFIX_LEN =
+ sizeof(ACCESS_TOKEN_PREFIX) / sizeof(*ACCESS_TOKEN_PREFIX) - 1;
+
+bool IsAccessToken(const TString& auth) {
+ return auth.length() > ACCESS_TOKEN_PREFIX_LEN &&
+ auth.compare(0, ACCESS_TOKEN_PREFIX_LEN, ACCESS_TOKEN_PREFIX) == 0;
+}
+
+TString AccessToken(const TString& auth) {
+ if (!IsAccessToken(auth)) {
+ return "";
+ }
+ return TString(auth.c_str(), ACCESS_TOKEN_PREFIX_LEN);
+}
+
+} // namespace
+
+TString CliCredentials::GetDefaultChannelCredsType() const {
+ // Compatibility logic for --enable_ssl.
+ if (FLAGS_enable_ssl) {
+ fprintf(stderr,
+ "warning: --enable_ssl is deprecated. Use "
+ "--channel_creds_type=ssl.\n");
+ return "ssl";
+ }
+ // Compatibility logic for --use_auth.
+ if (FLAGS_access_token.empty() && FLAGS_use_auth) {
+ fprintf(stderr,
+ "warning: --use_auth is deprecated. Use "
+ "--channel_creds_type=gdc.\n");
+ return "gdc";
+ }
+ return "insecure";
+}
+
+TString CliCredentials::GetDefaultCallCreds() const {
+ if (!FLAGS_access_token.empty()) {
+ fprintf(stderr,
+ "warning: --access_token is deprecated. Use "
+ "--call_creds=access_token=<token>.\n");
+ return TString("access_token=") + FLAGS_access_token;
+ }
+ return "none";
+}
+
+std::shared_ptr<grpc::ChannelCredentials>
+CliCredentials::GetChannelCredentials() const {
+ if (FLAGS_channel_creds_type.compare("insecure") == 0) {
+ return grpc::InsecureChannelCredentials();
+ } else if (FLAGS_channel_creds_type.compare("ssl") == 0) {
+ grpc::SslCredentialsOptions ssl_creds_options;
+ // TODO(@Capstan): This won't affect Google Default Credentials using SSL.
+ if (!FLAGS_ssl_client_cert.empty()) {
+ grpc_slice cert_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_cert.c_str(), 1, &cert_slice));
+ ssl_creds_options.pem_cert_chain =
+ grpc::StringFromCopiedSlice(cert_slice);
+ grpc_slice_unref(cert_slice);
+ }
+ if (!FLAGS_ssl_client_key.empty()) {
+ grpc_slice key_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_key.c_str(), 1, &key_slice));
+ ssl_creds_options.pem_private_key =
+ grpc::StringFromCopiedSlice(key_slice);
+ grpc_slice_unref(key_slice);
+ }
+ return grpc::SslCredentials(ssl_creds_options);
+ } else if (FLAGS_channel_creds_type.compare("gdc") == 0) {
+ return grpc::GoogleDefaultCredentials();
+ } else if (FLAGS_channel_creds_type.compare("alts") == 0) {
+ return grpc::experimental::AltsCredentials(
+ grpc::experimental::AltsCredentialsOptions());
+ } else if (FLAGS_channel_creds_type.compare("local") == 0) {
+ if (FLAGS_local_connect_type.compare("local_tcp") == 0) {
+ return grpc::experimental::LocalCredentials(LOCAL_TCP);
+ } else if (FLAGS_local_connect_type.compare("uds") == 0) {
+ return grpc::experimental::LocalCredentials(UDS);
+ } else {
+ fprintf(stderr,
+ "--local_connect_type=%s invalid; must be local_tcp or uds.\n",
+ FLAGS_local_connect_type.c_str());
+ }
+ }
+ fprintf(stderr,
+ "--channel_creds_type=%s invalid; must be insecure, ssl, gdc, "
+ "alts, or local.\n",
+ FLAGS_channel_creds_type.c_str());
+ return std::shared_ptr<grpc::ChannelCredentials>();
+}
+
+std::shared_ptr<grpc::CallCredentials> CliCredentials::GetCallCredentials()
+ const {
+ if (IsAccessToken(FLAGS_call_creds.c_str())) {
+ return grpc::AccessTokenCredentials(AccessToken(FLAGS_call_creds.c_str()));
+ }
+ if (FLAGS_call_creds.compare("none") == 0) {
+ // Nothing to do; creds, if any, are baked into the channel.
+ return std::shared_ptr<grpc::CallCredentials>();
+ }
+ fprintf(stderr,
+ "--call_creds=%s invalid; must be none "
+ "or access_token=<token>.\n",
+ FLAGS_call_creds.c_str());
+ return std::shared_ptr<grpc::CallCredentials>();
+}
+
+std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials()
+ const {
+ if (FLAGS_call_creds.empty()) {
+ FLAGS_call_creds = GetDefaultCallCreds();
+ } else if (!FLAGS_access_token.empty() && !IsAccessToken(FLAGS_call_creds.c_str())) {
+ fprintf(stderr,
+ "warning: ignoring --access_token because --call_creds "
+ "already set to %s.\n",
+ FLAGS_call_creds.c_str());
+ }
+ if (FLAGS_channel_creds_type.empty()) {
+ FLAGS_channel_creds_type = GetDefaultChannelCredsType();
+ } else if (FLAGS_enable_ssl && FLAGS_channel_creds_type.compare("ssl") != 0) {
+ fprintf(stderr,
+ "warning: ignoring --enable_ssl because "
+ "--channel_creds_type already set to %s.\n",
+ FLAGS_channel_creds_type.c_str());
+ } else if (FLAGS_use_auth && FLAGS_channel_creds_type.compare("gdc") != 0) {
+ fprintf(stderr,
+ "warning: ignoring --use_auth because "
+ "--channel_creds_type already set to %s.\n",
+ FLAGS_channel_creds_type.c_str());
+ }
+ // Legacy transport upgrade logic for insecure requests.
+ if (IsAccessToken(FLAGS_call_creds.c_str()) &&
+ FLAGS_channel_creds_type.compare("insecure") == 0) {
+ fprintf(stderr,
+ "warning: --channel_creds_type=insecure upgraded to ssl because "
+ "an access token was provided.\n");
+ FLAGS_channel_creds_type = "ssl";
+ }
+ std::shared_ptr<grpc::ChannelCredentials> channel_creds =
+ GetChannelCredentials();
+ // Composite any call-type credentials on top of the base channel.
+ std::shared_ptr<grpc::CallCredentials> call_creds = GetCallCredentials();
+ return (channel_creds == nullptr || call_creds == nullptr)
+ ? channel_creds
+ : grpc::CompositeChannelCredentials(channel_creds, call_creds);
+}
+
+const TString CliCredentials::GetCredentialUsage() const {
+ return " --enable_ssl ; Set whether to use ssl "
+ "(deprecated)\n"
+ " --use_auth ; Set whether to create default google"
+ " credentials\n"
+ " ; (deprecated)\n"
+ " --access_token ; Set the access token in metadata,"
+ " overrides --use_auth\n"
+ " ; (deprecated)\n"
+ " --ssl_target ; Set server host for ssl validation\n"
+ " --ssl_client_cert ; Client cert for ssl\n"
+ " --ssl_client_key ; Client private key for ssl\n"
+ " --local_connect_type ; Set to local_tcp or uds\n"
+ " --channel_creds_type ; Set to insecure, ssl, gdc, alts, or "
+ "local\n"
+ " --call_creds ; Set to none, or"
+ " access_token=<token>\n";
+}
+
+const TString CliCredentials::GetSslTargetNameOverride() const {
+ bool use_ssl = FLAGS_channel_creds_type.compare("ssl") == 0 ||
+ FLAGS_channel_creds_type.compare("gdc") == 0;
+ return use_ssl ? FLAGS_ssl_target : "";
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/cli_credentials.h b/contrib/libs/grpc/test/cpp/util/cli_credentials.h
new file mode 100644
index 0000000000..3e695692fa
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/cli_credentials.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
+#define GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
+
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+namespace testing {
+
+class CliCredentials {
+ public:
+ virtual ~CliCredentials() {}
+ std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const;
+ virtual const TString GetCredentialUsage() const;
+ virtual const TString GetSslTargetNameOverride() const;
+
+ protected:
+ // Returns the appropriate channel_creds_type value for the set of legacy
+ // flag arguments.
+ virtual TString GetDefaultChannelCredsType() const;
+ // Returns the appropriate call_creds value for the set of legacy flag
+ // arguments.
+ virtual TString GetDefaultCallCreds() const;
+ // Returns the base transport channel credentials. Child classes can override
+ // to support additional channel_creds_types unknown to this base class.
+ virtual std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials()
+ const;
+ // Returns call credentials to composite onto the base transport channel
+ // credentials. Child classes can override to support additional
+ // authentication flags unknown to this base class.
+ virtual std::shared_ptr<grpc::CallCredentials> GetCallCredentials() const;
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
diff --git a/contrib/libs/grpc/test/cpp/util/config_grpc_cli.h b/contrib/libs/grpc/test/cpp/util/config_grpc_cli.h
new file mode 100644
index 0000000000..358884196d
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/config_grpc_cli.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
+#define GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
+
+#include <grpcpp/impl/codegen/config_protobuf.h>
+
+#ifndef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY
+#include <google/protobuf/dynamic_message.h>
+#define GRPC_CUSTOM_DYNAMICMESSAGEFACTORY \
+ ::google::protobuf::DynamicMessageFactory
+#endif
+
+#ifndef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE
+#include <google/protobuf/descriptor.h>
+#define GRPC_CUSTOM_DESCRIPTORPOOLDATABASE \
+ ::google::protobuf::DescriptorPoolDatabase
+#define GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE \
+ ::google::protobuf::MergedDescriptorDatabase
+#endif
+
+#ifndef GRPC_CUSTOM_TEXTFORMAT
+#include <google/protobuf/text_format.h>
+#define GRPC_CUSTOM_TEXTFORMAT ::google::protobuf::TextFormat
+#endif
+
+#ifndef GRPC_CUSTOM_DISKSOURCETREE
+#include <google/protobuf/compiler/importer.h>
+#define GRPC_CUSTOM_DISKSOURCETREE ::google::protobuf::compiler::DiskSourceTree
+#define GRPC_CUSTOM_IMPORTER ::google::protobuf::compiler::Importer
+#define GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR \
+ ::google::protobuf::compiler::MultiFileErrorCollector
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY DynamicMessageFactory;
+
+typedef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE DescriptorPoolDatabase;
+typedef GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE MergedDescriptorDatabase;
+
+typedef GRPC_CUSTOM_TEXTFORMAT TextFormat;
+
+namespace compiler {
+typedef GRPC_CUSTOM_DISKSOURCETREE DiskSourceTree;
+typedef GRPC_CUSTOM_IMPORTER Importer;
+typedef GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR MultiFileErrorCollector;
+} // namespace compiler
+
+} // namespace protobuf
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
diff --git a/contrib/libs/grpc/test/cpp/util/create_test_channel.cc b/contrib/libs/grpc/test/cpp/util/create_test_channel.cc
new file mode 100644
index 0000000000..86d8e22af1
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/create_test_channel.cc
@@ -0,0 +1,252 @@
+/*
+ *
+ * Copyright 2015-2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/create_test_channel.h"
+
+#include <gflags/gflags.h>
+
+#include <grpc/support/log.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+
+#include "test/cpp/util/test_credentials_provider.h"
+
+DEFINE_string(
+ grpc_test_use_grpclb_with_child_policy, "",
+ "If non-empty, set a static service config on channels created by "
+ "grpc::CreateTestChannel, that configures the grpclb LB policy "
+ "with a child policy being the value of this flag (e.g. round_robin "
+ "or pick_first).");
+
+namespace grpc {
+
+namespace {
+
+const char kProdTlsCredentialsType[] = "prod_ssl";
+
+class SslCredentialProvider : public testing::CredentialTypeProvider {
+ public:
+ std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+ grpc::ChannelArguments* /*args*/) override {
+ return grpc::SslCredentials(SslCredentialsOptions());
+ }
+ std::shared_ptr<ServerCredentials> GetServerCredentials() override {
+ return nullptr;
+ }
+};
+
+gpr_once g_once_init_add_prod_ssl_provider = GPR_ONCE_INIT;
+// Register ssl with non-test roots type to the credentials provider.
+void AddProdSslType() {
+ testing::GetCredentialsProvider()->AddSecureType(
+ kProdTlsCredentialsType, std::unique_ptr<testing::CredentialTypeProvider>(
+ new SslCredentialProvider));
+}
+
+void MaybeSetCustomChannelArgs(grpc::ChannelArguments* args) {
+ if (FLAGS_grpc_test_use_grpclb_with_child_policy.size() > 0) {
+ args->SetString("grpc.service_config",
+ "{\"loadBalancingConfig\":[{\"grpclb\":{\"childPolicy\":[{"
+ "\"" +
+ FLAGS_grpc_test_use_grpclb_with_child_policy +
+ "\":{}}]}}]}");
+ }
+}
+
+} // namespace
+
+// When cred_type is 'ssl', if server is empty, override_hostname is used to
+// create channel. Otherwise, connect to server and override hostname if
+// override_hostname is provided.
+// When cred_type is not 'ssl', override_hostname is ignored.
+// Set use_prod_root to true to use the SSL root for connecting to google.
+// In this case, path to the roots pem file must be set via environment variable
+// GRPC_DEFAULT_SSL_ROOTS_FILE_PATH.
+// Otherwise, root for test SSL cert will be used.
+// creds will be used to create a channel when cred_type is 'ssl'.
+// Use examples:
+// CreateTestChannel(
+// "1.1.1.1:12345", "ssl", "override.hostname.com", false, creds);
+// CreateTestChannel("test.google.com:443", "ssl", "", true, creds);
+// same as above
+// CreateTestChannel("", "ssl", "test.google.com:443", true, creds);
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& cred_type,
+ const TString& override_hostname, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ const ChannelArguments& args) {
+ return CreateTestChannel(server, cred_type, override_hostname, use_prod_roots,
+ creds, args,
+ /*interceptor_creators=*/{});
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ const ChannelArguments& args) {
+ return CreateTestChannel(server, override_hostname, security_type,
+ use_prod_roots, creds, args,
+ /*interceptor_creators=*/{});
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds) {
+ return CreateTestChannel(server, override_hostname, security_type,
+ use_prod_roots, creds, ChannelArguments());
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots) {
+ return CreateTestChannel(server, override_hostname, security_type,
+ use_prod_roots, std::shared_ptr<CallCredentials>());
+}
+
+// Shortcut for end2end and interop tests.
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, testing::transport_security security_type) {
+ return CreateTestChannel(server, "foo.test.google.fr", security_type, false);
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& credential_type,
+ const std::shared_ptr<CallCredentials>& creds) {
+ ChannelArguments channel_args;
+ MaybeSetCustomChannelArgs(&channel_args);
+ std::shared_ptr<ChannelCredentials> channel_creds =
+ testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
+ &channel_args);
+ GPR_ASSERT(channel_creds != nullptr);
+ if (creds.get()) {
+ channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds);
+ }
+ return ::grpc::CreateCustomChannel(server, channel_creds, channel_args);
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& cred_type,
+ const TString& override_hostname, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds, const ChannelArguments& args,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators) {
+ ChannelArguments channel_args(args);
+ MaybeSetCustomChannelArgs(&channel_args);
+ std::shared_ptr<ChannelCredentials> channel_creds;
+ if (cred_type.empty()) {
+ if (interceptor_creators.empty()) {
+ return ::grpc::CreateCustomChannel(server, InsecureChannelCredentials(),
+ channel_args);
+ } else {
+ return experimental::CreateCustomChannelWithInterceptors(
+ server, InsecureChannelCredentials(), channel_args,
+ std::move(interceptor_creators));
+ }
+ } else if (cred_type == testing::kTlsCredentialsType) { // cred_type == "ssl"
+ if (use_prod_roots) {
+ gpr_once_init(&g_once_init_add_prod_ssl_provider, &AddProdSslType);
+ channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
+ kProdTlsCredentialsType, &channel_args);
+ if (!server.empty() && !override_hostname.empty()) {
+ channel_args.SetSslTargetNameOverride(override_hostname);
+ }
+ } else {
+ // override_hostname is discarded as the provider handles it.
+ channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
+ testing::kTlsCredentialsType, &channel_args);
+ }
+ GPR_ASSERT(channel_creds != nullptr);
+
+ const TString& connect_to = server.empty() ? override_hostname : server;
+ if (creds.get()) {
+ channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds);
+ }
+ if (interceptor_creators.empty()) {
+ return ::grpc::CreateCustomChannel(connect_to, channel_creds,
+ channel_args);
+ } else {
+ return experimental::CreateCustomChannelWithInterceptors(
+ connect_to, channel_creds, channel_args,
+ std::move(interceptor_creators));
+ }
+ } else {
+ channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
+ cred_type, &channel_args);
+ GPR_ASSERT(channel_creds != nullptr);
+
+ if (interceptor_creators.empty()) {
+ return ::grpc::CreateCustomChannel(server, channel_creds, channel_args);
+ } else {
+ return experimental::CreateCustomChannelWithInterceptors(
+ server, channel_creds, channel_args, std::move(interceptor_creators));
+ }
+ }
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds, const ChannelArguments& args,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators) {
+ TString credential_type =
+ security_type == testing::ALTS
+ ? testing::kAltsCredentialsType
+ : (security_type == testing::TLS ? testing::kTlsCredentialsType
+ : testing::kInsecureCredentialsType);
+ return CreateTestChannel(server, credential_type, override_hostname,
+ use_prod_roots, creds, args,
+ std::move(interceptor_creators));
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators) {
+ return CreateTestChannel(server, override_hostname, security_type,
+ use_prod_roots, creds, ChannelArguments(),
+ std::move(interceptor_creators));
+}
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& credential_type,
+ const std::shared_ptr<CallCredentials>& creds,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators) {
+ ChannelArguments channel_args;
+ MaybeSetCustomChannelArgs(&channel_args);
+ std::shared_ptr<ChannelCredentials> channel_creds =
+ testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
+ &channel_args);
+ GPR_ASSERT(channel_creds != nullptr);
+ if (creds.get()) {
+ channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds);
+ }
+ return experimental::CreateCustomChannelWithInterceptors(
+ server, channel_creds, channel_args, std::move(interceptor_creators));
+}
+
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/create_test_channel.h b/contrib/libs/grpc/test/cpp/util/create_test_channel.h
new file mode 100644
index 0000000000..ed4ce6c11b
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/create_test_channel.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2015-2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H
+#define GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H
+
+#include <memory>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+class Channel;
+
+namespace testing {
+
+typedef enum { INSECURE = 0, TLS, ALTS } transport_security;
+
+} // namespace testing
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, testing::transport_security security_type);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ const ChannelArguments& args);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& cred_type,
+ const TString& override_hostname, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ const ChannelArguments& args);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& credential_type,
+ const std::shared_ptr<CallCredentials>& creds);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& override_hostname,
+ testing::transport_security security_type, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds, const ChannelArguments& args,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& cred_type,
+ const TString& override_hostname, bool use_prod_roots,
+ const std::shared_ptr<CallCredentials>& creds, const ChannelArguments& args,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators);
+
+std::shared_ptr<Channel> CreateTestChannel(
+ const TString& server, const TString& credential_type,
+ const std::shared_ptr<CallCredentials>& creds,
+ std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators);
+
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H
diff --git a/contrib/libs/grpc/test/cpp/util/error_details_test.cc b/contrib/libs/grpc/test/cpp/util/error_details_test.cc
new file mode 100644
index 0000000000..630ab1d98f
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/error_details_test.cc
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpcpp/support/error_details.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/status/status.pb.h"
+#include "src/proto/grpc/testing/echo_messages.pb.h"
+#include "test/core/util/test_config.h"
+
+namespace grpc {
+namespace {
+
+TEST(ExtractTest, Success) {
+ google::rpc::Status expected;
+ expected.set_code(13); // INTERNAL
+ expected.set_message("I am an error message");
+ testing::EchoRequest expected_details;
+ expected_details.set_message(TString(100, '\0'));
+ expected.add_details()->PackFrom(expected_details);
+
+ google::rpc::Status to;
+ TString error_details = expected.SerializeAsString();
+ Status from(static_cast<StatusCode>(expected.code()), expected.message(),
+ error_details);
+ EXPECT_TRUE(ExtractErrorDetails(from, &to).ok());
+ EXPECT_EQ(expected.code(), to.code());
+ EXPECT_EQ(expected.message(), to.message());
+ EXPECT_EQ(1, to.details_size());
+ testing::EchoRequest details;
+ to.details(0).UnpackTo(&details);
+ EXPECT_EQ(expected_details.message(), details.message());
+}
+
+TEST(ExtractTest, NullInput) {
+ EXPECT_EQ(StatusCode::FAILED_PRECONDITION,
+ ExtractErrorDetails(Status(), nullptr).error_code());
+}
+
+TEST(ExtractTest, Unparsable) {
+ TString error_details("I am not a status object");
+ Status from(StatusCode::INTERNAL, "", error_details);
+ google::rpc::Status to;
+ EXPECT_EQ(StatusCode::INVALID_ARGUMENT,
+ ExtractErrorDetails(from, &to).error_code());
+}
+
+TEST(SetTest, Success) {
+ google::rpc::Status expected;
+ expected.set_code(13); // INTERNAL
+ expected.set_message("I am an error message");
+ testing::EchoRequest expected_details;
+ expected_details.set_message(TString(100, '\0'));
+ expected.add_details()->PackFrom(expected_details);
+
+ Status to;
+ Status s = SetErrorDetails(expected, &to);
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(expected.code(), to.error_code());
+ EXPECT_EQ(expected.message(), to.error_message());
+ EXPECT_EQ(expected.SerializeAsString(), to.error_details());
+}
+
+TEST(SetTest, NullInput) {
+ EXPECT_EQ(StatusCode::FAILED_PRECONDITION,
+ SetErrorDetails(google::rpc::Status(), nullptr).error_code());
+}
+
+TEST(SetTest, OutOfScopeErrorCode) {
+ google::rpc::Status expected;
+ expected.set_code(17); // Out of scope (UNAUTHENTICATED is 16).
+ expected.set_message("I am an error message");
+ testing::EchoRequest expected_details;
+ expected_details.set_message(TString(100, '\0'));
+ expected.add_details()->PackFrom(expected_details);
+
+ Status to;
+ Status s = SetErrorDetails(expected, &to);
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(StatusCode::UNKNOWN, to.error_code());
+ EXPECT_EQ(expected.message(), to.error_message());
+ EXPECT_EQ(expected.SerializeAsString(), to.error_details());
+}
+
+TEST(SetTest, ValidScopeErrorCode) {
+ for (int c = StatusCode::OK; c <= StatusCode::UNAUTHENTICATED; c++) {
+ google::rpc::Status expected;
+ expected.set_code(c);
+ expected.set_message("I am an error message");
+ testing::EchoRequest expected_details;
+ expected_details.set_message(TString(100, '\0'));
+ expected.add_details()->PackFrom(expected_details);
+
+ Status to;
+ Status s = SetErrorDetails(expected, &to);
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(c, to.error_code());
+ EXPECT_EQ(expected.message(), to.error_message());
+ EXPECT_EQ(expected.SerializeAsString(), to.error_details());
+ }
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/libs/grpc/test/cpp/util/grpc_cli.cc b/contrib/libs/grpc/test/cpp/util/grpc_cli.cc
new file mode 100644
index 0000000000..45c6b94f84
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/grpc_cli.cc
@@ -0,0 +1,90 @@
+/*
+
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ A command line tool to talk to a grpc server.
+ Run `grpc_cli help` command to see its usage information.
+
+ Example of talking to grpc interop server:
+ grpc_cli call localhost:50051 UnaryCall "response_size:10" \
+ --protofiles=src/proto/grpc/testing/test.proto --enable_ssl=false
+
+ Options:
+ 1. --protofiles, use this flag to provide proto files 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 protofiles is
+ provided.
+ 3. --metadata specifies metadata to be sent to the server, such as:
+ --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2"
+ 4. --enable_ssl, whether to use tls.
+ 5. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call
+ 6. --infile, input filename (defaults to stdin)
+ 7. --outfile, output filename (defaults to stdout)
+ 8. --binary_input, use the serialized request as input. The serialized
+ request can be generated by calling something like:
+ protoc --proto_path=src/proto/grpc/testing/ \
+ --encode=grpc.testing.SimpleRequest \
+ src/proto/grpc/testing/messages.proto \
+ < 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.
+ 9. --binary_output, use binary format response as output, it can
+ be later decoded using protoc:
+ protoc --proto_path=src/proto/grpc/testing/ \
+ --decode=grpc.testing.SimpleResponse \
+ src/proto/grpc/testing/messages.proto \
+ < output.bin > output.txt
+ 10. --default_service_config, optional default service config to use
+ on the channel. Note that this may be ignored if the name resolver
+ returns a service config.
+ 11. --display_peer_address, on CallMethod commands, log the peer socket
+ address of the connection that each RPC is made on to stderr.
+*/
+
+#include <fstream>
+#include <functional>
+#include <iostream>
+
+#include <gflags/gflags.h>
+#include <grpcpp/support/config.h>
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/grpc_tool.h"
+#include "test/cpp/util/test_config.h"
+
+DEFINE_string(outfile, "", "Output file (default is stdout)");
+
+static bool SimplePrint(const TString& outfile, const TString& output) {
+ if (outfile.empty()) {
+ std::cout << output << std::flush;
+ } else {
+ std::ofstream output_file(outfile, std::ios::app | std::ios::binary);
+ output_file << output << std::flush;
+ output_file.close();
+ }
+ return true;
+}
+
+int main(int argc, char** argv) {
+ grpc::testing::InitTest(&argc, &argv, true);
+
+ return grpc::testing::GrpcToolMainLib(
+ argc, (const char**)argv, grpc::testing::CliCredentials(),
+ std::bind(SimplePrint, TString(FLAGS_outfile.c_str()), std::placeholders::_1));
+}
diff --git a/contrib/libs/grpc/test/cpp/util/grpc_tool.cc b/contrib/libs/grpc/test/cpp/util/grpc_tool.cc
new file mode 100644
index 0000000000..30f3024e25
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/grpc_tool.cc
@@ -0,0 +1,985 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/grpc_tool.h"
+
+#include <gflags/gflags.h>
+#include <grpc/grpc.h>
+#include <grpc/support/port_platform.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/string_ref.h>
+
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <util/generic/string.h>
+#include <thread>
+
+#include "test/cpp/util/cli_call.h"
+#include "test/cpp/util/proto_file_parser.h"
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
+#include "test/cpp/util/service_describer.h"
+
+#if GPR_WINDOWS
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+namespace grpc {
+namespace testing {
+
+DEFINE_bool(l, false, "Use a long listing format");
+DEFINE_bool(remotedb, true, "Use server types to parse and format messages");
+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(protofiles, "", "Name of the proto file.");
+DEFINE_bool(binary_input, false, "Input in binary format");
+DEFINE_bool(binary_output, false, "Output in binary format");
+DEFINE_string(
+ default_service_config, "",
+ "Default service config to use on the channel, if non-empty. Note "
+ "that this will be ignored if the name resolver returns a service "
+ "config.");
+DEFINE_bool(
+ display_peer_address, false,
+ "Log the peer socket address of the connection that each RPC is made "
+ "on to stderr.");
+DEFINE_bool(json_input, false, "Input in json format");
+DEFINE_bool(json_output, false, "Output in json format");
+DEFINE_string(infile, "", "Input file (default is stdin)");
+DEFINE_bool(batch, false,
+ "Input contains multiple requests. Please do not use this to send "
+ "more than a few RPCs. gRPC CLI has very different performance "
+ "characteristics compared with normal RPC calls which make it "
+ "unsuitable for loadtesting or significant production traffic.");
+DEFINE_double(timeout, -1,
+ "Specify timeout in seconds, used to set the deadline for all "
+ "RPCs. The default value of -1 means no deadline has been set.");
+
+namespace {
+
+class GrpcTool {
+ public:
+ explicit GrpcTool();
+ virtual ~GrpcTool() {}
+
+ bool Help(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool CallMethod(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool ListServices(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool PrintType(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ // TODO(zyc): implement the following methods
+ // bool ListServices(int argc, const char** argv, GrpcToolOutputCallback
+ // callback);
+ // bool PrintTypeId(int argc, const char** argv, GrpcToolOutputCallback
+ // callback);
+ bool ParseMessage(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool ToText(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool ToJson(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+ bool ToBinary(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+
+ void SetPrintCommandMode(int exit_status) {
+ print_command_usage_ = true;
+ usage_exit_status_ = exit_status;
+ }
+
+ private:
+ void CommandUsage(const TString& usage) const;
+ bool print_command_usage_;
+ int usage_exit_status_;
+ const TString cred_usage_;
+};
+
+template <typename T>
+std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
+ GrpcToolOutputCallback)>
+BindWith5Args(T&& func) {
+ return std::bind(std::forward<T>(func), std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3,
+ std::placeholders::_4, std::placeholders::_5);
+}
+
+template <typename T>
+size_t ArraySize(T& a) {
+ return ((sizeof(a) / sizeof(*(a))) /
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+void ParseMetadataFlag(
+ std::multimap<TString, TString>* client_metadata) {
+ if (FLAGS_metadata.empty()) {
+ return;
+ }
+ std::vector<TString> fields;
+ const char delim = ':';
+ const char escape = '\\';
+ size_t cur = -1;
+ std::stringstream ss;
+ while (++cur < FLAGS_metadata.length()) {
+ switch (FLAGS_metadata.at(cur)) {
+ case escape:
+ if (cur < FLAGS_metadata.length() - 1) {
+ char c = FLAGS_metadata.at(++cur);
+ if (c == delim || c == escape) {
+ ss << c;
+ continue;
+ }
+ }
+ fprintf(stderr, "Failed to parse metadata flag.\n");
+ exit(1);
+ case delim:
+ fields.push_back(ss.str());
+ ss.str("");
+ ss.clear();
+ break;
+ default:
+ ss << FLAGS_metadata.at(cur);
+ }
+ }
+ fields.push_back(ss.str());
+ if (fields.size() % 2) {
+ fprintf(stderr, "Failed to parse metadata flag.\n");
+ exit(1);
+ }
+ for (size_t i = 0; i < fields.size(); i += 2) {
+ client_metadata->insert(
+ std::pair<TString, TString>(fields[i], fields[i + 1]));
+ }
+}
+
+template <typename T>
+void PrintMetadata(const T& m, const TString& message) {
+ if (m.empty()) {
+ return;
+ }
+ fprintf(stderr, "%s\n", message.c_str());
+ TString pair;
+ for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
+ pair.clear();
+ pair.append(iter->first.data(), iter->first.size());
+ pair.append(" : ");
+ pair.append(iter->second.data(), iter->second.size());
+ fprintf(stderr, "%s\n", pair.c_str());
+ }
+}
+
+void ReadResponse(CliCall* call, const TString& method_name,
+ GrpcToolOutputCallback callback, ProtoFileParser* parser,
+ gpr_mu* parser_mu, bool print_mode) {
+ TString serialized_response_proto;
+ std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata;
+
+ for (bool receive_initial_metadata = true; call->ReadAndMaybeNotifyWrite(
+ &serialized_response_proto,
+ receive_initial_metadata ? &server_initial_metadata : nullptr);
+ receive_initial_metadata = false) {
+ fprintf(stderr, "got response.\n");
+ if (!FLAGS_binary_output) {
+ gpr_mu_lock(parser_mu);
+ serialized_response_proto = parser->GetFormattedStringFromMethod(
+ method_name, serialized_response_proto, false /* is_request */,
+ FLAGS_json_output);
+ if (parser->HasError() && print_mode) {
+ fprintf(stderr, "Failed to parse response.\n");
+ }
+ gpr_mu_unlock(parser_mu);
+ }
+ if (receive_initial_metadata) {
+ PrintMetadata(server_initial_metadata,
+ "Received initial metadata from server:");
+ }
+ if (!callback(serialized_response_proto) && print_mode) {
+ fprintf(stderr, "Failed to output response.\n");
+ }
+ }
+}
+
+std::shared_ptr<grpc::Channel> CreateCliChannel(
+ const TString& server_address, const CliCredentials& cred) {
+ grpc::ChannelArguments args;
+ if (!cred.GetSslTargetNameOverride().empty()) {
+ args.SetSslTargetNameOverride(cred.GetSslTargetNameOverride());
+ }
+ if (!FLAGS_default_service_config.empty()) {
+ args.SetString(GRPC_ARG_SERVICE_CONFIG,
+ FLAGS_default_service_config.c_str());
+ }
+ return ::grpc::CreateCustomChannel(server_address, cred.GetCredentials(),
+ args);
+}
+
+struct Command {
+ const char* command;
+ std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
+ GrpcToolOutputCallback)>
+ function;
+ int min_args;
+ int max_args;
+};
+
+const Command ops[] = {
+ {"help", BindWith5Args(&GrpcTool::Help), 0, INT_MAX},
+ {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+ {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+ {"call", BindWith5Args(&GrpcTool::CallMethod), 2, 3},
+ {"type", BindWith5Args(&GrpcTool::PrintType), 2, 2},
+ {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
+ {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
+ {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
+ {"tojson", BindWith5Args(&GrpcTool::ToJson), 2, 3},
+};
+
+void Usage(const TString& msg) {
+ fprintf(
+ stderr,
+ "%s\n"
+ " grpc_cli ls ... ; List services\n"
+ " grpc_cli call ... ; Call method\n"
+ " grpc_cli type ... ; Print type\n"
+ " grpc_cli parse ... ; Parse message\n"
+ " grpc_cli totext ... ; Convert binary message to text\n"
+ " grpc_cli tojson ... ; Convert binary message to json\n"
+ " grpc_cli tobinary ... ; Convert text message to binary\n"
+ " grpc_cli help ... ; Print this message, or per-command usage\n"
+ "\n",
+ msg.c_str());
+
+ exit(1);
+}
+
+const Command* FindCommand(const TString& name) {
+ for (int i = 0; i < (int)ArraySize(ops); i++) {
+ if (name == ops[i].command) {
+ return &ops[i];
+ }
+ }
+ return nullptr;
+}
+} // namespace
+
+int GrpcToolMainLib(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ if (argc < 2) {
+ Usage("No command specified");
+ }
+
+ TString command = argv[1];
+ argc -= 2;
+ argv += 2;
+
+ const Command* cmd = FindCommand(command);
+ if (cmd != nullptr) {
+ GrpcTool grpc_tool;
+ if (argc < cmd->min_args || argc > cmd->max_args) {
+ // Force the command to print its usage message
+ fprintf(stderr, "\nWrong number of arguments for %s\n", command.c_str());
+ grpc_tool.SetPrintCommandMode(1);
+ return cmd->function(&grpc_tool, -1, nullptr, cred, callback);
+ }
+ const bool ok = cmd->function(&grpc_tool, argc, argv, cred, callback);
+ return ok ? 0 : 1;
+ } else {
+ Usage("Invalid command '" + TString(command.c_str()) + "'");
+ }
+ return 1;
+}
+
+GrpcTool::GrpcTool() : print_command_usage_(false), usage_exit_status_(0) {}
+
+void GrpcTool::CommandUsage(const TString& usage) const {
+ if (print_command_usage_) {
+ fprintf(stderr, "\n%s%s\n", usage.c_str(),
+ (usage.empty() || usage[usage.size() - 1] != '\n') ? "\n" : "");
+ exit(usage_exit_status_);
+ }
+}
+
+bool GrpcTool::Help(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Print help\n"
+ " grpc_cli help [subcommand]\n");
+
+ if (argc == 0) {
+ Usage("");
+ } else {
+ const Command* cmd = FindCommand(argv[0]);
+ if (cmd == nullptr) {
+ Usage("Unknown command '" + TString(argv[0]) + "'");
+ }
+ SetPrintCommandMode(0);
+ cmd->function(this, -1, nullptr, cred, callback);
+ }
+ return true;
+}
+
+bool GrpcTool::ListServices(int argc, const char** argv,
+ const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "List services\n"
+ " grpc_cli ls <address> [<service>[/<method>]]\n"
+ " <address> ; host:port\n"
+ " <service> ; Exported service name\n"
+ " <method> ; Method name\n"
+ " --l ; Use a long listing format\n"
+ " --outfile ; Output filename (defaults to stdout)\n" +
+ cred.GetCredentialUsage());
+
+ TString server_address(argv[0]);
+ std::shared_ptr<grpc::Channel> channel =
+ CreateCliChannel(server_address, cred);
+ grpc::ProtoReflectionDescriptorDatabase desc_db(channel);
+ grpc::protobuf::DescriptorPool desc_pool(&desc_db);
+
+ std::vector<TString> service_list;
+ if (!desc_db.GetServices(&service_list)) {
+ fprintf(stderr, "Received an error when querying services endpoint.\n");
+ return false;
+ }
+
+ // If no service is specified, dump the list of services.
+ TString output;
+ if (argc < 2) {
+ // List all services, if --l is passed, then include full description,
+ // otherwise include a summarized list only.
+ if (FLAGS_l) {
+ output = DescribeServiceList(service_list, desc_pool);
+ } else {
+ for (auto it = service_list.begin(); it != service_list.end(); it++) {
+ auto const& service = *it;
+ output.append(service);
+ output.append("\n");
+ }
+ }
+ } else {
+ std::string service_name;
+ std::string method_name;
+ std::stringstream ss(argv[1]);
+
+ // Remove leading slashes.
+ while (ss.peek() == '/') {
+ ss.get();
+ }
+
+ // Parse service and method names. Support the following patterns:
+ // Service
+ // Service Method
+ // Service.Method
+ // Service/Method
+ if (argc == 3) {
+ std::getline(ss, service_name, '/');
+ method_name = argv[2];
+ } else {
+ if (std::getline(ss, service_name, '/')) {
+ std::getline(ss, method_name);
+ }
+ }
+
+ const grpc::protobuf::ServiceDescriptor* service =
+ desc_pool.FindServiceByName(google::protobuf::string(service_name));
+ if (service != nullptr) {
+ if (method_name.empty()) {
+ output = FLAGS_l ? DescribeService(service) : SummarizeService(service);
+ } else {
+ method_name.insert(0, ".");
+ method_name.insert(0, service_name);
+ const grpc::protobuf::MethodDescriptor* method =
+ desc_pool.FindMethodByName(google::protobuf::string(method_name));
+ if (method != nullptr) {
+ output = FLAGS_l ? DescribeMethod(method) : SummarizeMethod(method);
+ } else {
+ fprintf(stderr, "Method %s not found in service %s.\n",
+ method_name.c_str(), service_name.c_str());
+ return false;
+ }
+ }
+ } else {
+ if (!method_name.empty()) {
+ fprintf(stderr, "Service %s not found.\n", service_name.c_str());
+ return false;
+ } else {
+ const grpc::protobuf::MethodDescriptor* method =
+ desc_pool.FindMethodByName(google::protobuf::string(service_name));
+ if (method != nullptr) {
+ output = FLAGS_l ? DescribeMethod(method) : SummarizeMethod(method);
+ } else {
+ fprintf(stderr, "Service or method %s not found.\n",
+ service_name.c_str());
+ return false;
+ }
+ }
+ }
+ }
+ return callback(output);
+}
+
+bool GrpcTool::PrintType(int /*argc*/, const char** argv,
+ const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Print type\n"
+ " grpc_cli type <address> <type>\n"
+ " <address> ; host:port\n"
+ " <type> ; Protocol buffer type name\n" +
+ cred.GetCredentialUsage());
+
+ TString server_address(argv[0]);
+ std::shared_ptr<grpc::Channel> channel =
+ CreateCliChannel(server_address, cred);
+ grpc::ProtoReflectionDescriptorDatabase desc_db(channel);
+ grpc::protobuf::DescriptorPool desc_pool(&desc_db);
+
+ TString output;
+ const grpc::protobuf::Descriptor* descriptor =
+ desc_pool.FindMessageTypeByName(argv[1]);
+ if (descriptor != nullptr) {
+ output = descriptor->DebugString();
+ } else {
+ fprintf(stderr, "Type %s not found.\n", argv[1]);
+ return false;
+ }
+ return callback(output);
+}
+
+bool GrpcTool::CallMethod(int argc, const char** argv,
+ const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Call method\n"
+ " grpc_cli call <address> <service>[.<method>] <request>\n"
+ " <address> ; host:port\n"
+ " <service> ; Exported service name\n"
+ " <method> ; Method name\n"
+ " <request> ; Text protobuffer (overrides infile)\n"
+ " --protofiles ; Comma separated proto files used as a"
+ " fallback when parsing request/response\n"
+ " --proto_path ; The search path of proto files, valid"
+ " only when --protofiles is given\n"
+ " --noremotedb ; Don't attempt to use reflection service"
+ " at all\n"
+ " --metadata ; The metadata to be sent to the server\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n"
+ " --binary_input ; Input in binary format\n"
+ " --binary_output ; Output in binary format\n"
+ " --json_input ; Input in json format\n"
+ " --json_output ; Output in json format\n"
+ " --timeout ; Specify timeout (in seconds), used to "
+ "set the deadline for RPCs. The default value of -1 means no "
+ "deadline has been set.\n" +
+ cred.GetCredentialUsage());
+
+ std::stringstream output_ss;
+ TString request_text;
+ TString server_address(argv[0]);
+ TString method_name(argv[1]);
+ TString formatted_method_name;
+ std::unique_ptr<ProtoFileParser> parser;
+ TString serialized_request_proto;
+ CliArgs cli_args;
+ cli_args.timeout = FLAGS_timeout;
+ bool print_mode = false;
+
+ std::shared_ptr<grpc::Channel> channel =
+ CreateCliChannel(server_address, cred);
+
+ if (!FLAGS_binary_input || !FLAGS_binary_output) {
+ parser.reset(
+ new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
+ FLAGS_proto_path.c_str(), FLAGS_protofiles.c_str()));
+ if (parser->HasError()) {
+ fprintf(
+ stderr,
+ "Failed to find remote reflection service and local proto files.\n");
+ return false;
+ }
+ }
+
+ if (FLAGS_binary_input) {
+ formatted_method_name = method_name;
+ } else {
+ formatted_method_name = parser->GetFormattedMethodName(method_name);
+ if (parser->HasError()) {
+ fprintf(stderr, "Failed to find method %s in proto files.\n",
+ method_name.c_str());
+ }
+ }
+
+ if (argc == 3) {
+ request_text = argv[2];
+ }
+
+ if (parser->IsStreaming(method_name, true /* is_request */)) {
+ std::istream* input_stream;
+ std::ifstream input_file;
+
+ if (FLAGS_batch) {
+ fprintf(stderr, "Batch mode for streaming RPC is not supported.\n");
+ return false;
+ }
+
+ std::multimap<TString, TString> client_metadata;
+ ParseMetadataFlag(&client_metadata);
+ PrintMetadata(client_metadata, "Sending client initial metadata:");
+
+ CliCall call(channel, formatted_method_name, client_metadata, cli_args);
+ if (FLAGS_display_peer_address) {
+ fprintf(stderr, "New call for method_name:%s has peer address:|%s|\n",
+ formatted_method_name.c_str(), call.peer().c_str());
+ }
+
+ if (FLAGS_infile.empty()) {
+ if (isatty(fileno(stdin))) {
+ print_mode = true;
+ fprintf(stderr, "reading streaming request message from stdin...\n");
+ }
+ input_stream = &std::cin;
+ } else {
+ input_file.open(FLAGS_infile, std::ios::in | std::ios::binary);
+ input_stream = &input_file;
+ }
+
+ gpr_mu parser_mu;
+ gpr_mu_init(&parser_mu);
+ std::thread read_thread(ReadResponse, &call, method_name, callback,
+ parser.get(), &parser_mu, print_mode);
+
+ std::stringstream request_ss;
+ std::string line;
+ while (!request_text.empty() ||
+ (!input_stream->eof() && getline(*input_stream, line))) {
+ if (!request_text.empty()) {
+ if (FLAGS_binary_input) {
+ serialized_request_proto = request_text;
+ request_text.clear();
+ } else {
+ gpr_mu_lock(&parser_mu);
+ serialized_request_proto = parser->GetSerializedProtoFromMethod(
+ method_name, request_text, true /* is_request */,
+ FLAGS_json_input);
+ request_text.clear();
+ if (parser->HasError()) {
+ if (print_mode) {
+ fprintf(stderr, "Failed to parse request.\n");
+ }
+ gpr_mu_unlock(&parser_mu);
+ continue;
+ }
+ gpr_mu_unlock(&parser_mu);
+ }
+
+ call.WriteAndWait(serialized_request_proto);
+ if (print_mode) {
+ fprintf(stderr, "Request sent.\n");
+ }
+ } else {
+ if (line.length() == 0) {
+ request_text = request_ss.str();
+ request_ss.str(TString());
+ request_ss.clear();
+ } else {
+ request_ss << line << ' ';
+ }
+ }
+ }
+ if (input_file.is_open()) {
+ input_file.close();
+ }
+
+ call.WritesDoneAndWait();
+ read_thread.join();
+ gpr_mu_destroy(&parser_mu);
+
+ std::multimap<grpc::string_ref, grpc::string_ref> server_trailing_metadata;
+ Status status = call.Finish(&server_trailing_metadata);
+ PrintMetadata(server_trailing_metadata,
+ "Received trailing metadata from server:");
+
+ if (status.ok()) {
+ fprintf(stderr, "Stream RPC succeeded with OK status\n");
+ return true;
+ } else {
+ fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
+ status.error_code(), status.error_message().c_str());
+ return false;
+ }
+
+ } else { // parser->IsStreaming(method_name, true /* is_request */)
+ if (FLAGS_batch) {
+ if (parser->IsStreaming(method_name, false /* is_request */)) {
+ fprintf(stderr, "Batch mode for streaming RPC is not supported.\n");
+ return false;
+ }
+
+ std::istream* input_stream;
+ std::ifstream input_file;
+
+ if (FLAGS_infile.empty()) {
+ if (isatty(fileno(stdin))) {
+ print_mode = true;
+ fprintf(stderr, "reading request messages from stdin...\n");
+ }
+ input_stream = &std::cin;
+ } else {
+ input_file.open(FLAGS_infile, std::ios::in | std::ios::binary);
+ input_stream = &input_file;
+ }
+
+ std::multimap<TString, TString> client_metadata;
+ ParseMetadataFlag(&client_metadata);
+ if (print_mode) {
+ PrintMetadata(client_metadata, "Sending client initial metadata:");
+ }
+
+ std::stringstream request_ss;
+ std::string line;
+ while (!request_text.empty() ||
+ (!input_stream->eof() && getline(*input_stream, line))) {
+ if (!request_text.empty()) {
+ if (FLAGS_binary_input) {
+ serialized_request_proto = request_text;
+ request_text.clear();
+ } else {
+ serialized_request_proto = parser->GetSerializedProtoFromMethod(
+ method_name, request_text, true /* is_request */,
+ FLAGS_json_input);
+ request_text.clear();
+ if (parser->HasError()) {
+ if (print_mode) {
+ fprintf(stderr, "Failed to parse request.\n");
+ }
+ continue;
+ }
+ }
+
+ TString serialized_response_proto;
+ std::multimap<grpc::string_ref, grpc::string_ref>
+ server_initial_metadata, server_trailing_metadata;
+ CliCall call(channel, formatted_method_name, client_metadata,
+ cli_args);
+ if (FLAGS_display_peer_address) {
+ fprintf(stderr,
+ "New call for method_name:%s has peer address:|%s|\n",
+ formatted_method_name.c_str(), call.peer().c_str());
+ }
+ call.Write(serialized_request_proto);
+ call.WritesDone();
+ if (!call.Read(&serialized_response_proto,
+ &server_initial_metadata)) {
+ fprintf(stderr, "Failed to read response.\n");
+ }
+ Status status = call.Finish(&server_trailing_metadata);
+
+ if (status.ok()) {
+ if (print_mode) {
+ fprintf(stderr, "Rpc succeeded with OK status.\n");
+ PrintMetadata(server_initial_metadata,
+ "Received initial metadata from server:");
+ PrintMetadata(server_trailing_metadata,
+ "Received trailing metadata from server:");
+ }
+
+ if (FLAGS_binary_output) {
+ if (!callback(serialized_response_proto)) {
+ break;
+ }
+ } else {
+ TString response_text = parser->GetFormattedStringFromMethod(
+ method_name, serialized_response_proto,
+ false /* is_request */, FLAGS_json_output);
+
+ if (parser->HasError() && print_mode) {
+ fprintf(stderr, "Failed to parse response.\n");
+ } else {
+ if (!callback(response_text)) {
+ break;
+ }
+ }
+ }
+ } else {
+ if (print_mode) {
+ fprintf(stderr,
+ "Rpc failed with status code %d, error message: %s\n",
+ status.error_code(), status.error_message().c_str());
+ }
+ }
+ } else {
+ if (line.length() == 0) {
+ request_text = request_ss.str();
+ request_ss.str(TString());
+ request_ss.clear();
+ } else {
+ request_ss << line << ' ';
+ }
+ }
+ }
+
+ if (input_file.is_open()) {
+ input_file.close();
+ }
+
+ return true;
+ }
+
+ if (argc == 3) {
+ if (!FLAGS_infile.empty()) {
+ fprintf(stderr, "warning: request given in argv, ignoring --infile\n");
+ }
+ } else {
+ std::stringstream input_stream;
+ if (FLAGS_infile.empty()) {
+ if (isatty(fileno(stdin))) {
+ fprintf(stderr, "reading request message from stdin...\n");
+ }
+ input_stream << std::cin.rdbuf();
+ } else {
+ std::ifstream input_file(FLAGS_infile, std::ios::in | std::ios::binary);
+ input_stream << input_file.rdbuf();
+ input_file.close();
+ }
+ request_text = input_stream.str();
+ }
+
+ if (FLAGS_binary_input) {
+ serialized_request_proto = request_text;
+ } else {
+ serialized_request_proto = parser->GetSerializedProtoFromMethod(
+ method_name, request_text, true /* is_request */, FLAGS_json_input);
+ if (parser->HasError()) {
+ fprintf(stderr, "Failed to parse request.\n");
+ return false;
+ }
+ }
+ fprintf(stderr, "connecting to %s\n", server_address.c_str());
+
+ TString serialized_response_proto;
+ std::multimap<TString, TString> client_metadata;
+ std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
+ server_trailing_metadata;
+ ParseMetadataFlag(&client_metadata);
+ PrintMetadata(client_metadata, "Sending client initial metadata:");
+
+ CliCall call(channel, formatted_method_name, client_metadata, cli_args);
+ if (FLAGS_display_peer_address) {
+ fprintf(stderr, "New call for method_name:%s has peer address:|%s|\n",
+ formatted_method_name.c_str(), call.peer().c_str());
+ }
+ call.Write(serialized_request_proto);
+ call.WritesDone();
+
+ for (bool receive_initial_metadata = true; call.Read(
+ &serialized_response_proto,
+ receive_initial_metadata ? &server_initial_metadata : nullptr);
+ receive_initial_metadata = false) {
+ if (!FLAGS_binary_output) {
+ serialized_response_proto = parser->GetFormattedStringFromMethod(
+ method_name, serialized_response_proto, false /* is_request */,
+ FLAGS_json_output);
+ if (parser->HasError()) {
+ fprintf(stderr, "Failed to parse response.\n");
+ return false;
+ }
+ }
+
+ if (receive_initial_metadata) {
+ PrintMetadata(server_initial_metadata,
+ "Received initial metadata from server:");
+ }
+ if (!callback(serialized_response_proto)) {
+ return false;
+ }
+ }
+ Status status = call.Finish(&server_trailing_metadata);
+ PrintMetadata(server_trailing_metadata,
+ "Received trailing metadata from server:");
+ if (status.ok()) {
+ fprintf(stderr, "Rpc succeeded with OK status\n");
+ return true;
+ } else {
+ fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
+ status.error_code(), status.error_message().c_str());
+ return false;
+ }
+ }
+ GPR_UNREACHABLE_CODE(return false);
+}
+
+bool GrpcTool::ParseMessage(int argc, const char** argv,
+ const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Parse message\n"
+ " grpc_cli parse <address> <type> [<message>]\n"
+ " <address> ; host:port\n"
+ " <type> ; Protocol buffer type name\n"
+ " <message> ; Text protobuffer (overrides --infile)\n"
+ " --protofiles ; Comma separated proto files used as a"
+ " fallback when parsing request/response\n"
+ " --proto_path ; The search path of proto files, valid"
+ " only when --protofiles is given\n"
+ " --noremotedb ; Don't attempt to use reflection service"
+ " at all\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n"
+ " --binary_input ; Input in binary format\n"
+ " --binary_output ; Output in binary format\n"
+ " --json_input ; Input in json format\n"
+ " --json_output ; Output in json format\n" +
+ cred.GetCredentialUsage());
+
+ std::stringstream output_ss;
+ TString message_text;
+ TString server_address(argv[0]);
+ TString type_name(argv[1]);
+ std::unique_ptr<grpc::testing::ProtoFileParser> parser;
+ TString serialized_request_proto;
+
+ if (argc == 3) {
+ message_text = argv[2];
+ if (!FLAGS_infile.empty()) {
+ fprintf(stderr, "warning: message given in argv, ignoring --infile.\n");
+ }
+ } else {
+ std::stringstream input_stream;
+ if (FLAGS_infile.empty()) {
+ if (isatty(fileno(stdin))) {
+ fprintf(stderr, "reading request message from stdin...\n");
+ }
+ input_stream << std::cin.rdbuf();
+ } else {
+ std::ifstream input_file(FLAGS_infile, std::ios::in | std::ios::binary);
+ input_stream << input_file.rdbuf();
+ input_file.close();
+ }
+ message_text = input_stream.str();
+ }
+
+ if (!FLAGS_binary_input || !FLAGS_binary_output) {
+ std::shared_ptr<grpc::Channel> channel =
+ CreateCliChannel(server_address, cred);
+ parser.reset(
+ new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
+ FLAGS_proto_path.c_str(), FLAGS_protofiles.c_str()));
+ if (parser->HasError()) {
+ fprintf(
+ stderr,
+ "Failed to find remote reflection service and local proto files.\n");
+ return false;
+ }
+ }
+
+ if (FLAGS_binary_input) {
+ serialized_request_proto = message_text;
+ } else {
+ serialized_request_proto = parser->GetSerializedProtoFromMessageType(
+ type_name, message_text, FLAGS_json_input);
+ if (parser->HasError()) {
+ fprintf(stderr, "Failed to serialize the message.\n");
+ return false;
+ }
+ }
+
+ if (FLAGS_binary_output) {
+ output_ss << serialized_request_proto;
+ } else {
+ TString output_text;
+ output_text = parser->GetFormattedStringFromMessageType(
+ type_name, serialized_request_proto, FLAGS_json_output);
+ if (parser->HasError()) {
+ fprintf(stderr, "Failed to deserialize the message.\n");
+ return false;
+ }
+
+ output_ss << output_text << std::endl;
+ }
+
+ return callback(output_ss.str());
+}
+
+bool GrpcTool::ToText(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Convert binary message to text\n"
+ " grpc_cli totext <protofiles> <type>\n"
+ " <protofiles> ; Comma separated list of proto files\n"
+ " <type> ; Protocol buffer type name\n"
+ " --proto_path ; The search path of proto files\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n");
+
+ FLAGS_protofiles = argv[0];
+ FLAGS_remotedb = false;
+ FLAGS_binary_input = true;
+ FLAGS_binary_output = false;
+ return ParseMessage(argc, argv, cred, callback);
+}
+
+bool GrpcTool::ToJson(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Convert binary message to json\n"
+ " grpc_cli tojson <protofiles> <type>\n"
+ " <protofiles> ; Comma separated list of proto files\n"
+ " <type> ; Protocol buffer type name\n"
+ " --proto_path ; The search path of proto files\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n");
+
+ FLAGS_protofiles = argv[0];
+ FLAGS_remotedb = false;
+ FLAGS_binary_input = true;
+ FLAGS_binary_output = false;
+ FLAGS_json_output = true;
+ return ParseMessage(argc, argv, cred, callback);
+}
+
+bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Convert text message to binary\n"
+ " grpc_cli tobinary <protofiles> <type> [<message>]\n"
+ " <protofiles> ; Comma separated list of proto files\n"
+ " <type> ; Protocol buffer type name\n"
+ " --proto_path ; The search path of proto files\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n");
+
+ FLAGS_protofiles = argv[0];
+ FLAGS_remotedb = false;
+ FLAGS_binary_input = false;
+ FLAGS_binary_output = true;
+ return ParseMessage(argc, argv, cred, callback);
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/grpc_tool.h b/contrib/libs/grpc/test/cpp/util/grpc_tool.h
new file mode 100644
index 0000000000..5bb43430d3
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/grpc_tool.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
+#define GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
+
+#include <functional>
+
+#include <grpcpp/support/config.h>
+
+#include "test/cpp/util/cli_credentials.h"
+
+namespace grpc {
+namespace testing {
+
+typedef std::function<bool(const TString&)> GrpcToolOutputCallback;
+
+int GrpcToolMainLib(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
diff --git a/contrib/libs/grpc/test/cpp/util/grpc_tool_test.cc b/contrib/libs/grpc/test/cpp/util/grpc_tool_test.cc
new file mode 100644
index 0000000000..ff610daadd
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/grpc_tool_test.cc
@@ -0,0 +1,1344 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/grpc_tool.h"
+
+#include <gflags/gflags.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <sstream>
+
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/iomgr/load_file.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "src/proto/grpc/testing/echo.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
+#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
+#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+
+#define USAGE_REGEX "( grpc_cli .+\n){2,10}"
+
+#define ECHO_TEST_SERVICE_SUMMARY \
+ "Echo\n" \
+ "Echo1\n" \
+ "Echo2\n" \
+ "CheckDeadlineUpperBound\n" \
+ "CheckDeadlineSet\n" \
+ "CheckClientInitialMetadata\n" \
+ "RequestStream\n" \
+ "ResponseStream\n" \
+ "BidiStream\n" \
+ "Unimplemented\n"
+
+#define ECHO_TEST_SERVICE_DESCRIPTION \
+ "filename: src/proto/grpc/testing/echo.proto\n" \
+ "package: grpc.testing;\n" \
+ "service EchoTestService {\n" \
+ " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n" \
+ " rpc Echo1(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n" \
+ " rpc Echo2(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n" \
+ " rpc CheckDeadlineUpperBound(grpc.testing.SimpleRequest) returns " \
+ "(grpc.testing.StringValue) {}\n" \
+ " rpc CheckDeadlineSet(grpc.testing.SimpleRequest) returns " \
+ "(grpc.testing.StringValue) {}\n" \
+ " rpc CheckClientInitialMetadata(grpc.testing.SimpleRequest) returns " \
+ "(grpc.testing.SimpleResponse) {}\n" \
+ " rpc RequestStream(stream grpc.testing.EchoRequest) returns " \
+ "(grpc.testing.EchoResponse) {}\n" \
+ " rpc ResponseStream(grpc.testing.EchoRequest) returns (stream " \
+ "grpc.testing.EchoResponse) {}\n" \
+ " rpc BidiStream(stream grpc.testing.EchoRequest) returns (stream " \
+ "grpc.testing.EchoResponse) {}\n" \
+ " rpc Unimplemented(grpc.testing.EchoRequest) returns " \
+ "(grpc.testing.EchoResponse) {}\n" \
+ "}\n" \
+ "\n"
+
+#define ECHO_METHOD_DESCRIPTION \
+ " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n"
+
+#define ECHO_RESPONSE_MESSAGE_TEXT_FORMAT \
+ "message: \"echo\"\n" \
+ "param {\n" \
+ " host: \"localhost\"\n" \
+ " peer: \"peer\"\n" \
+ "}\n\n"
+
+#define ECHO_RESPONSE_MESSAGE_JSON_FORMAT \
+ "{\n" \
+ " \"message\": \"echo\",\n" \
+ " \"param\": {\n" \
+ " \"host\": \"localhost\",\n" \
+ " \"peer\": \"peer\"\n" \
+ " }\n" \
+ "}\n\n"
+
+DECLARE_string(channel_creds_type);
+DECLARE_string(ssl_target);
+
+namespace grpc {
+namespace testing {
+
+DECLARE_bool(binary_input);
+DECLARE_bool(binary_output);
+DECLARE_bool(json_input);
+DECLARE_bool(json_output);
+DECLARE_bool(l);
+DECLARE_bool(batch);
+DECLARE_string(metadata);
+DECLARE_string(protofiles);
+DECLARE_string(proto_path);
+DECLARE_string(default_service_config);
+DECLARE_double(timeout);
+
+namespace {
+
+const int kServerDefaultResponseStreamsToSend = 3;
+
+class TestCliCredentials final : public grpc::testing::CliCredentials {
+ public:
+ TestCliCredentials(bool secure = false) : secure_(secure) {}
+ std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials()
+ const override {
+ if (!secure_) {
+ return InsecureChannelCredentials();
+ }
+ grpc_slice ca_slice;
+ GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
+ grpc_load_file(CA_CERT_PATH, 1, &ca_slice)));
+ const char* test_root_cert =
+ reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
+ SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
+ std::shared_ptr<grpc::ChannelCredentials> credential_ptr =
+ grpc::SslCredentials(grpc::SslCredentialsOptions(ssl_opts));
+ grpc_slice_unref(ca_slice);
+ return credential_ptr;
+ }
+ const TString GetCredentialUsage() const override { return ""; }
+
+ private:
+ const bool secure_;
+};
+
+bool PrintStream(std::stringstream* ss, const TString& output) {
+ (*ss) << output;
+ return true;
+}
+
+template <typename T>
+size_t ArraySize(T& a) {
+ return ((sizeof(a) / sizeof(*(a))) /
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+ Status Echo(ServerContext* context, const EchoRequest* request,
+ EchoResponse* response) override {
+ if (!context->client_metadata().empty()) {
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = context->client_metadata().begin();
+ iter != context->client_metadata().end(); ++iter) {
+ context->AddInitialMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ }
+ context->AddTrailingMetadata("trailing_key", "trailing_value");
+ response->set_message(request->message());
+ return Status::OK;
+ }
+
+ Status CheckDeadlineSet(ServerContext* context, const SimpleRequest* request,
+ StringValue* response) override {
+ response->set_message(context->deadline() !=
+ std::chrono::system_clock::time_point::max()
+ ? "true"
+ : "false");
+ return Status::OK;
+ }
+
+ // Check if deadline - current time <= timeout
+ // If deadline set, timeout + current time should be an upper bound for it
+ Status CheckDeadlineUpperBound(ServerContext* context,
+ const SimpleRequest* request,
+ StringValue* response) override {
+ auto seconds = std::chrono::duration_cast<std::chrono::seconds>(
+ context->deadline() - std::chrono::system_clock::now());
+
+ // Returning string instead of bool to avoid using embedded messages in
+ // proto3
+ response->set_message(seconds.count() <= FLAGS_timeout ? "true" : "false");
+ return Status::OK;
+ }
+
+ Status RequestStream(ServerContext* context,
+ ServerReader<EchoRequest>* reader,
+ EchoResponse* response) override {
+ EchoRequest request;
+ response->set_message("");
+ if (!context->client_metadata().empty()) {
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = context->client_metadata().begin();
+ iter != context->client_metadata().end(); ++iter) {
+ context->AddInitialMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ }
+ context->AddTrailingMetadata("trailing_key", "trailing_value");
+ while (reader->Read(&request)) {
+ response->mutable_message()->append(request.message());
+ }
+
+ return Status::OK;
+ }
+
+ Status ResponseStream(ServerContext* context, const EchoRequest* request,
+ ServerWriter<EchoResponse>* writer) override {
+ if (!context->client_metadata().empty()) {
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = context->client_metadata().begin();
+ iter != context->client_metadata().end(); ++iter) {
+ context->AddInitialMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ }
+ context->AddTrailingMetadata("trailing_key", "trailing_value");
+
+ EchoResponse response;
+ for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
+ response.set_message(request->message() + ToString(i));
+ writer->Write(response);
+ }
+
+ return Status::OK;
+ }
+
+ Status BidiStream(
+ ServerContext* context,
+ ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
+ EchoRequest request;
+ EchoResponse response;
+ if (!context->client_metadata().empty()) {
+ for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+ iter = context->client_metadata().begin();
+ iter != context->client_metadata().end(); ++iter) {
+ context->AddInitialMetadata(ToString(iter->first),
+ ToString(iter->second));
+ }
+ }
+ context->AddTrailingMetadata("trailing_key", "trailing_value");
+
+ while (stream->Read(&request)) {
+ response.set_message(request.message());
+ stream->Write(response);
+ }
+
+ return Status::OK;
+ }
+};
+
+} // namespace
+
+class GrpcToolTest : public ::testing::Test {
+ protected:
+ GrpcToolTest() {}
+
+ // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
+ // uses atexit() to free chosen ports, and it will spawn a new thread in
+ // resolve_address_posix.c:192 at exit time.
+ const TString SetUpServer(bool secure = false) {
+ std::ostringstream server_address;
+ int port = grpc_pick_unused_port_or_die();
+ server_address << "localhost:" << port;
+ // Setup server
+ ServerBuilder builder;
+ std::shared_ptr<grpc::ServerCredentials> creds;
+ grpc_slice cert_slice, key_slice;
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "load_file", grpc_load_file(SERVER_CERT_PATH, 1, &cert_slice)));
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "load_file", grpc_load_file(SERVER_KEY_PATH, 1, &key_slice)));
+ const char* server_cert =
+ reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
+ const char* server_key =
+ reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
+ SslServerCredentialsOptions::PemKeyCertPair pkcp = {server_key,
+ server_cert};
+ if (secure) {
+ SslServerCredentialsOptions ssl_opts;
+ ssl_opts.pem_root_certs = "";
+ ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+ creds = SslServerCredentials(ssl_opts);
+ } else {
+ creds = InsecureServerCredentials();
+ }
+ builder.AddListeningPort(server_address.str(), creds);
+ builder.RegisterService(&service_);
+ server_ = builder.BuildAndStart();
+ grpc_slice_unref(cert_slice);
+ grpc_slice_unref(key_slice);
+ return server_address.str();
+ }
+
+ void ShutdownServer() { server_->Shutdown(); }
+
+ std::unique_ptr<Server> server_;
+ TestServiceImpl service_;
+ reflection::ProtoServerReflectionPlugin plugin_;
+};
+
+TEST_F(GrpcToolTest, NoCommand) {
+ // Test input "grpc_cli"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli"};
+ // Exit with 1, print usage instruction in stderr
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
+ // No output
+ EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, InvalidCommand) {
+ // Test input "grpc_cli"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli", "abc"};
+ // Exit with 1, print usage instruction in stderr
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
+ // No output
+ EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, HelpCommand) {
+ // Test input "grpc_cli help"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli", "help"};
+ // Exit with 1, print usage instruction in stderr
+ EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), USAGE_REGEX);
+ // No output
+ EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, ListCommand) {
+ // Test input "grpc_cli list localhost:<port>"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
+
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ "grpc.testing.EchoTestService\n"
+ "grpc.reflection.v1alpha.ServerReflection\n"));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ListOneService) {
+ // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
+ "grpc.testing.EchoTestService"};
+ // without -l flag
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_TEST_SERVICE_SUMMARY
+ EXPECT_TRUE(0 ==
+ strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
+
+ // with -l flag
+ output_stream.str(TString());
+ output_stream.clear();
+ FLAGS_l = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
+ EXPECT_TRUE(
+ 0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, TypeCommand) {
+ // Test input "grpc_cli type localhost:<port> grpc.testing.EchoRequest"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
+ "grpc.testing.EchoRequest"};
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ const grpc::protobuf::Descriptor* desc =
+ grpc::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
+ "grpc.testing.EchoRequest");
+ // Expected output: the DebugString of grpc.testing.EchoRequest
+ EXPECT_TRUE(0 ==
+ strcmp(output_stream.str().c_str(), desc->DebugString().c_str()));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ListOneMethod) {
+ // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
+ "grpc.testing.EchoTestService.Echo"};
+ // without -l flag
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "Echo"
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
+
+ // with -l flag
+ output_stream.str(TString());
+ output_stream.clear();
+ FLAGS_l = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_METHOD_DESCRIPTION
+ EXPECT_TRUE(0 ==
+ strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, TypeNotFound) {
+ // Test input "grpc_cli type localhost:<port> grpc.testing.DummyRequest"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
+ "grpc.testing.DummyRequest"};
+
+ EXPECT_TRUE(1 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommand) {
+ // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "message: 'Hello'"};
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello"
+ // }
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello\"\n}"));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandJsonInput) {
+ // Test input "grpc_cli call localhost:<port> Echo "{ \"message\": \"Hello\"}"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{ \"message\": \"Hello\"}"};
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello"
+ // }
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello\"\n}"));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatch) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "message: 'Hello0'"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: "
+ "\"Hello1\"\nmessage: \"Hello2\"\n"));
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello1"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello1\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatchJsonInput) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{\"message\": \"Hello0\"}"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{\"message\": \"Hello1\"}\n\n{\"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ FLAGS_batch = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: "
+ "\"Hello1\"\nmessage: \"Hello2\"\n"));
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+ FLAGS_json_input = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello1"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello1\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatchWithBadRequest) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "message: 'Hello0'"};
+
+ // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("message: 1\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatchJsonInputWithBadRequest) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{ \"message\": \"Hello0\"}"};
+
+ // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"message\": 1 }\n\n { \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_input = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandRequestStream) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "message:
+ // 'Hello0'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "message: 'Hello0'"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: \"Hello0Hello1Hello2\""
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0Hello1Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandRequestStreamJsonInput) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "{ \"message\":
+ // \"Hello0\"}"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "{ \"message\": \"Hello0\" }"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"message\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+
+ // Expected output: "message: \"Hello0Hello1Hello2\""
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0Hello1Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "message:
+ // 'Hello0'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "message: 'Hello0'"};
+
+ // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("bad_field: 'Hello1'\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: \"Hello0Hello2\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequestJsonInput) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "message:
+ // 'Hello0'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "{ \"message\": \"Hello0\" }"};
+
+ // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"bad_field\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+
+ // Expected output: "message: \"Hello0Hello2\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandWithTimeoutDeadlineSet) {
+ // Test input "grpc_cli call CheckDeadlineSet --timeout=5000.25"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "CheckDeadlineSet"};
+
+ // Set timeout to 5000.25 seconds
+ FLAGS_timeout = 5000.25;
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: "true"", deadline set
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"true\""));
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandWithTimeoutDeadlineUpperBound) {
+ // Test input "grpc_cli call CheckDeadlineUpperBound --timeout=900"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "CheckDeadlineUpperBound"};
+
+ // Set timeout to 900 seconds
+ FLAGS_timeout = 900;
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: "true""
+ // deadline not greater than timeout + current time
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"true\""));
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandWithNegativeTimeoutValue) {
+ // Test input "grpc_cli call CheckDeadlineSet --timeout=-5"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "CheckDeadlineSet"};
+
+ // Set timeout to -5 (deadline not set)
+ FLAGS_timeout = -5;
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: "false"", deadline not set
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"false\""));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandWithDefaultTimeoutValue) {
+ // Test input "grpc_cli call CheckDeadlineSet --timeout=-1"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "CheckDeadlineSet"};
+
+ // Set timeout to -1 (default value, deadline not set)
+ FLAGS_timeout = -1;
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: "false"", deadline not set
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"false\""));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandResponseStream) {
+ // Test input: grpc_cli call localhost:<port> ResponseStream "message:
+ // 'Hello'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "ResponseStream", "message: 'Hello'"};
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: \"Hello{n}\""
+ for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
+ TString expected_response_text =
+ "message: \"Hello" + ToString(i) + "\"\n";
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ expected_response_text.c_str()));
+ }
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output: "{\n \"message\": \"Hello{n}\"\n}\n"
+ for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
+ TString expected_response_text =
+ "{\n \"message\": \"Hello" + ToString(i) + "\"\n}\n";
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ expected_response_text.c_str()));
+ }
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBidiStream) {
+ // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "BidiStream", "message: 'Hello0'"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
+ // \"Hello2\"\n\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: "
+ "\"Hello1\"\nmessage: \"Hello2\"\n"));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBidiStreamWithBadRequest) {
+ // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
+ std::stringstream output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "BidiStream", "message: 'Hello0'"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss("message: 1.0\n\n message: 'Hello2'\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
+ // \"Hello2\"\n\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
+ std::cin.rdbuf(orig);
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ParseCommand) {
+ // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
+ // ECHO_RESPONSE_MESSAGE"
+ std::stringstream output_stream;
+ std::stringstream binary_output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
+ "grpc.testing.EchoResponse",
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT};
+
+ FLAGS_binary_input = false;
+ FLAGS_binary_output = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
+
+ // Parse text message to binary message and then parse it back to text message
+ output_stream.str(TString());
+ output_stream.clear();
+ FLAGS_binary_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ TString binary_data = output_stream.str();
+ output_stream.str(TString());
+ output_stream.clear();
+ argv[4] = binary_data.c_str();
+ FLAGS_binary_input = true;
+ FLAGS_binary_output = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(5, argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: ECHO_RESPONSE_MESSAGE
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
+
+ FLAGS_binary_input = false;
+ FLAGS_binary_output = false;
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ParseCommandJsonFormat) {
+ // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
+ // ECHO_RESPONSE_MESSAGE_JSON_FORMAT"
+ std::stringstream output_stream;
+ std::stringstream binary_output_stream;
+
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
+ "grpc.testing.EchoResponse",
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT};
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
+
+ // with json_output
+ output_stream.str(TString());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, TooFewArguments) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli", "call", "Echo"};
+
+ // Exit with 1
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+ // No output
+ EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, TooManyArguments) {
+ // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli", "call", "localhost:10000",
+ "Echo", "Echo", "message: 'Hello'"};
+
+ // Exit with 1
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+ // No output
+ EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, CallCommandWithMetadata) {
+ // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "message: 'Hello'"};
+
+ {
+ std::stringstream output_stream;
+ FLAGS_metadata = "key0:val0:key1:valq:key2:val2";
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
+ TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+ }
+
+ {
+ std::stringstream output_stream;
+ FLAGS_metadata = "key:val\\:val";
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
+ TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+ }
+
+ {
+ std::stringstream output_stream;
+ FLAGS_metadata = "key:val\\\\val";
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
+ TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+ }
+
+ FLAGS_metadata = "";
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandWithBadMetadata) {
+ // Test input "grpc_cli call localhost:10000 Echo "message: 'Hello'"
+ const char* argv[] = {"grpc_cli", "call", "localhost:10000",
+ "grpc.testing.EchoTestService.Echo",
+ "message: 'Hello'"};
+ FLAGS_protofiles = "src/proto/grpc/testing/echo.proto";
+ char* test_srcdir = gpr_getenv("TEST_SRCDIR");
+ if (test_srcdir != nullptr) {
+ FLAGS_proto_path = test_srcdir + TString("/com_github_grpc_grpc");
+ }
+
+ {
+ std::stringstream output_stream;
+ FLAGS_metadata = "key0:val0:key1";
+ // Exit with 1
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
+ }
+
+ {
+ std::stringstream output_stream;
+ FLAGS_metadata = "key:val\\val";
+ // Exit with 1
+ EXPECT_EXIT(
+ GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+ ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
+ }
+
+ FLAGS_metadata = "";
+ FLAGS_protofiles = "";
+
+ gpr_free(test_srcdir);
+}
+
+TEST_F(GrpcToolTest, ListCommand_OverrideSslHostName) {
+ const TString server_address = SetUpServer(true);
+
+ // Test input "grpc_cli ls localhost:<port> --channel_creds_type=ssl
+ // --ssl_target=z.test.google.fr"
+ std::stringstream output_stream;
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
+ FLAGS_l = false;
+ FLAGS_channel_creds_type = "ssl";
+ FLAGS_ssl_target = "z.test.google.fr";
+ EXPECT_TRUE(
+ 0 == GrpcToolMainLib(
+ ArraySize(argv), argv, TestCliCredentials(true),
+ std::bind(PrintStream, &output_stream, std::placeholders::_1)));
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ "grpc.testing.EchoTestService\n"
+ "grpc.reflection.v1alpha.ServerReflection\n"));
+
+ FLAGS_channel_creds_type = "";
+ FLAGS_ssl_target = "";
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ConfiguringDefaultServiceConfig) {
+ // Test input "grpc_cli list localhost:<port>
+ // --default_service_config={\"loadBalancingConfig\":[{\"pick_first\":{}}]}"
+ std::stringstream output_stream;
+ const TString server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
+ // Just check that the tool is still operational when --default_service_config
+ // is configured. This particular service config is in reality redundant with
+ // the channel's default configuration.
+ FLAGS_l = false;
+ FLAGS_default_service_config =
+ "{\"loadBalancingConfig\":[{\"pick_first\":{}}]}";
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_default_service_config = "";
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ "grpc.testing.EchoTestService\n"
+ "grpc.reflection.v1alpha.ServerReflection\n"));
+ ShutdownServer();
+}
+
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/libs/grpc/test/cpp/util/metrics_server.cc b/contrib/libs/grpc/test/cpp/util/metrics_server.cc
new file mode 100644
index 0000000000..0493da053e
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/metrics_server.cc
@@ -0,0 +1,117 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *is % allowed in string
+ */
+
+#include "test/cpp/util/metrics_server.h"
+
+#include <grpc/support/log.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+
+#include "src/proto/grpc/testing/metrics.grpc.pb.h"
+#include "src/proto/grpc/testing/metrics.pb.h"
+
+namespace grpc {
+namespace testing {
+
+QpsGauge::QpsGauge()
+ : start_time_(gpr_now(GPR_CLOCK_REALTIME)), num_queries_(0) {}
+
+void QpsGauge::Reset() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ num_queries_ = 0;
+ start_time_ = gpr_now(GPR_CLOCK_REALTIME);
+}
+
+void QpsGauge::Incr() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ num_queries_++;
+}
+
+long QpsGauge::Get() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ gpr_timespec time_diff =
+ gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time_);
+ long duration_secs = time_diff.tv_sec > 0 ? time_diff.tv_sec : 1;
+ return num_queries_ / duration_secs;
+}
+
+grpc::Status MetricsServiceImpl::GetAllGauges(
+ ServerContext* /*context*/, const EmptyMessage* /*request*/,
+ ServerWriter<GaugeResponse>* writer) {
+ gpr_log(GPR_DEBUG, "GetAllGauges called");
+
+ std::lock_guard<std::mutex> lock(mu_);
+ for (auto it = qps_gauges_.begin(); it != qps_gauges_.end(); it++) {
+ GaugeResponse resp;
+ resp.set_name(it->first); // Gauge name
+ resp.set_long_value(it->second->Get()); // Gauge value
+ writer->Write(resp);
+ }
+
+ return Status::OK;
+}
+
+grpc::Status MetricsServiceImpl::GetGauge(ServerContext* /*context*/,
+ const GaugeRequest* request,
+ GaugeResponse* response) {
+ std::lock_guard<std::mutex> lock(mu_);
+
+ const auto it = qps_gauges_.find(request->name());
+ if (it != qps_gauges_.end()) {
+ response->set_name(it->first);
+ response->set_long_value(it->second->Get());
+ }
+
+ return Status::OK;
+}
+
+std::shared_ptr<QpsGauge> MetricsServiceImpl::CreateQpsGauge(
+ const TString& name, bool* already_present) {
+ std::lock_guard<std::mutex> lock(mu_);
+
+ std::shared_ptr<QpsGauge> qps_gauge(new QpsGauge());
+ const auto p = qps_gauges_.insert(std::make_pair(name, qps_gauge));
+
+ // p.first is an iterator pointing to <name, shared_ptr<QpsGauge>> pair.
+ // p.second is a boolean which is set to 'true' if the QpsGauge is
+ // successfully inserted in the guages_ map and 'false' if it is already
+ // present in the map
+ *already_present = !p.second;
+ return p.first->second;
+}
+
+// Starts the metrics server and returns the grpc::Server instance. Call Wait()
+// on the returned server instance.
+std::unique_ptr<grpc::Server> MetricsServiceImpl::StartServer(int port) {
+ gpr_log(GPR_INFO, "Building metrics server..");
+
+ const TString address = "0.0.0.0:" + ToString(port);
+
+ ServerBuilder builder;
+ builder.AddListeningPort(address, grpc::InsecureServerCredentials());
+ builder.RegisterService(this);
+
+ std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
+ gpr_log(GPR_INFO, "Metrics server %s started. Ready to receive requests..",
+ address.c_str());
+
+ return server;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/metrics_server.h b/contrib/libs/grpc/test/cpp/util/metrics_server.h
new file mode 100644
index 0000000000..10ffa7b4dd
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/metrics_server.h
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *is % allowed in string
+ */
+#ifndef GRPC_TEST_CPP_METRICS_SERVER_H
+#define GRPC_TEST_CPP_METRICS_SERVER_H
+
+#include <map>
+#include <mutex>
+
+#include <grpcpp/server.h>
+
+#include "src/proto/grpc/testing/metrics.grpc.pb.h"
+#include "src/proto/grpc/testing/metrics.pb.h"
+
+/*
+ * This implements a Metrics server defined in
+ * src/proto/grpc/testing/metrics.proto. Any
+ * test service can use this to export Metrics (TODO (sreek): Only Gauges for
+ * now).
+ *
+ * Example:
+ * MetricsServiceImpl metricsImpl;
+ * ..
+ * // Create QpsGauge(s). Note: QpsGauges can be created even after calling
+ * // 'StartServer'.
+ * QpsGauge qps_gauge1 = metricsImpl.CreateQpsGauge("foo", is_present);
+ * // qps_gauge1 can now be used anywhere in the program by first making a
+ * // one-time call qps_gauge1.Reset() and then calling qps_gauge1.Incr()
+ * // every time to increment a query counter
+ *
+ * ...
+ * // Create the metrics server
+ * std::unique_ptr<grpc::Server> server = metricsImpl.StartServer(port);
+ * server->Wait(); // Note: This is blocking.
+ */
+namespace grpc {
+namespace testing {
+
+class QpsGauge {
+ public:
+ QpsGauge();
+
+ // Initialize the internal timer and reset the query count to 0
+ void Reset();
+
+ // Increment the query count by 1
+ void Incr();
+
+ // Return the current qps (i.e query count divided by the time since this
+ // QpsGauge object created (or Reset() was called))
+ long Get();
+
+ private:
+ gpr_timespec start_time_;
+ long num_queries_;
+ std::mutex num_queries_mu_;
+};
+
+class MetricsServiceImpl final : public MetricsService::Service {
+ public:
+ grpc::Status GetAllGauges(ServerContext* context, const EmptyMessage* request,
+ ServerWriter<GaugeResponse>* writer) override;
+
+ grpc::Status GetGauge(ServerContext* context, const GaugeRequest* request,
+ GaugeResponse* response) override;
+
+ // Create a QpsGauge with name 'name'. is_present is set to true if the Gauge
+ // is already present in the map.
+ // NOTE: CreateQpsGauge can be called anytime (i.e before or after calling
+ // StartServer).
+ std::shared_ptr<QpsGauge> CreateQpsGauge(const TString& name,
+ bool* already_present);
+
+ std::unique_ptr<grpc::Server> StartServer(int port);
+
+ private:
+ std::map<string, std::shared_ptr<QpsGauge>> qps_gauges_;
+ std::mutex mu_;
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_METRICS_SERVER_H
diff --git a/contrib/libs/grpc/test/cpp/util/proto_file_parser.cc b/contrib/libs/grpc/test/cpp/util/proto_file_parser.cc
new file mode 100644
index 0000000000..b0912a712c
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/proto_file_parser.cc
@@ -0,0 +1,323 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/proto_file_parser.h"
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <unordered_set>
+
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+// Match the user input method string to the full_name from method descriptor.
+bool MethodNameMatch(const TString& full_name, const TString& input) {
+ TString clean_input = input;
+ std::replace(clean_input.begin(), clean_input.vend(), '/', '.');
+ if (clean_input.size() > full_name.size()) {
+ return false;
+ }
+ return full_name.compare(full_name.size() - clean_input.size(),
+ clean_input.size(), clean_input) == 0;
+}
+} // namespace
+
+class ErrorPrinter : public protobuf::compiler::MultiFileErrorCollector {
+ public:
+ explicit ErrorPrinter(ProtoFileParser* parser) : parser_(parser) {}
+
+ void AddError(const google::protobuf::string& filename, int line, int column,
+ const google::protobuf::string& message) override {
+ std::ostringstream oss;
+ oss << "error " << filename << " " << line << " " << column << " "
+ << message << "\n";
+ parser_->LogError(oss.str());
+ }
+
+ void AddWarning(const google::protobuf::string& filename, int line, int column,
+ const google::protobuf::string& message) override {
+ std::cerr << "warning " << filename << " " << line << " " << column << " "
+ << message << std::endl;
+ }
+
+ private:
+ ProtoFileParser* parser_; // not owned
+};
+
+ProtoFileParser::ProtoFileParser(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& proto_path,
+ const TString& protofiles)
+ : has_error_(false),
+ dynamic_factory_(new protobuf::DynamicMessageFactory()) {
+ std::vector<TString> service_list;
+ if (channel) {
+ reflection_db_.reset(new grpc::ProtoReflectionDescriptorDatabase(channel));
+ reflection_db_->GetServices(&service_list);
+ }
+
+ std::unordered_set<TString> known_services;
+ if (!protofiles.empty()) {
+ source_tree_.MapPath("", google::protobuf::string(proto_path));
+ error_printer_.reset(new ErrorPrinter(this));
+ importer_.reset(
+ new protobuf::compiler::Importer(&source_tree_, error_printer_.get()));
+
+ std::string file_name;
+ std::stringstream ss(protofiles);
+ while (std::getline(ss, file_name, ',')) {
+ const auto* file_desc = importer_->Import(google::protobuf::string(file_name.c_str()));
+ if (file_desc) {
+ for (int i = 0; i < file_desc->service_count(); i++) {
+ service_desc_list_.push_back(file_desc->service(i));
+ known_services.insert(file_desc->service(i)->full_name());
+ }
+ } else {
+ std::cerr << file_name << " not found" << std::endl;
+ }
+ }
+
+ file_db_.reset(new protobuf::DescriptorPoolDatabase(*importer_->pool()));
+ }
+
+ if (!reflection_db_ && !file_db_) {
+ LogError("No available proto database");
+ return;
+ }
+
+ if (!reflection_db_) {
+ desc_db_ = std::move(file_db_);
+ } else if (!file_db_) {
+ desc_db_ = std::move(reflection_db_);
+ } else {
+ desc_db_.reset(new protobuf::MergedDescriptorDatabase(reflection_db_.get(),
+ file_db_.get()));
+ }
+
+ desc_pool_.reset(new protobuf::DescriptorPool(desc_db_.get()));
+
+ for (auto it = service_list.begin(); it != service_list.end(); it++) {
+ if (known_services.find(*it) == known_services.end()) {
+ if (const protobuf::ServiceDescriptor* service_desc =
+ desc_pool_->FindServiceByName(google::protobuf::string(*it))) {
+ service_desc_list_.push_back(service_desc);
+ known_services.insert(*it);
+ }
+ }
+ }
+}
+
+ProtoFileParser::~ProtoFileParser() {}
+
+TString ProtoFileParser::GetFullMethodName(const TString& method) {
+ has_error_ = false;
+
+ if (known_methods_.find(method) != known_methods_.end()) {
+ return known_methods_[method];
+ }
+
+ const protobuf::MethodDescriptor* method_descriptor = nullptr;
+ 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)) {
+ if (method_descriptor) {
+ std::ostringstream error_stream;
+ error_stream << "Ambiguous method names: ";
+ error_stream << method_descriptor->full_name() << " ";
+ error_stream << method_desc->full_name();
+ LogError(error_stream.str());
+ }
+ method_descriptor = method_desc;
+ }
+ }
+ }
+ if (!method_descriptor) {
+ LogError("Method name not found");
+ }
+ if (has_error_) {
+ return "";
+ }
+
+ known_methods_[method] = method_descriptor->full_name();
+
+ return method_descriptor->full_name();
+}
+
+TString ProtoFileParser::GetFormattedMethodName(const TString& method) {
+ has_error_ = false;
+ TString formatted_method_name = GetFullMethodName(method);
+ if (has_error_) {
+ return "";
+ }
+ size_t last_dot = formatted_method_name.find_last_of('.');
+ if (last_dot != TString::npos) {
+ formatted_method_name[last_dot] = '/';
+ }
+ formatted_method_name.insert(formatted_method_name.begin(), '/');
+ return formatted_method_name;
+}
+
+TString ProtoFileParser::GetMessageTypeFromMethod(const TString& method,
+ bool is_request) {
+ has_error_ = false;
+ TString full_method_name = GetFullMethodName(method);
+ if (has_error_) {
+ return "";
+ }
+ const protobuf::MethodDescriptor* method_desc =
+ desc_pool_->FindMethodByName(google::protobuf::string(full_method_name));
+ if (!method_desc) {
+ LogError("Method not found");
+ return "";
+ }
+
+ return is_request ? method_desc->input_type()->full_name()
+ : method_desc->output_type()->full_name();
+}
+
+bool ProtoFileParser::IsStreaming(const TString& method, bool is_request) {
+ has_error_ = false;
+
+ TString full_method_name = GetFullMethodName(method);
+ if (has_error_) {
+ return false;
+ }
+
+ const protobuf::MethodDescriptor* method_desc =
+ desc_pool_->FindMethodByName(google::protobuf::string(full_method_name));
+ if (!method_desc) {
+ LogError("Method not found");
+ return false;
+ }
+
+ return is_request ? method_desc->client_streaming()
+ : method_desc->server_streaming();
+}
+
+TString ProtoFileParser::GetSerializedProtoFromMethod(
+ const TString& method, const TString& formatted_proto,
+ bool is_request, bool is_json_format) {
+ has_error_ = false;
+ TString message_type_name = GetMessageTypeFromMethod(method, is_request);
+ if (has_error_) {
+ return "";
+ }
+ return GetSerializedProtoFromMessageType(message_type_name, formatted_proto,
+ is_json_format);
+}
+
+TString ProtoFileParser::GetFormattedStringFromMethod(
+ const TString& method, const TString& serialized_proto,
+ bool is_request, bool is_json_format) {
+ has_error_ = false;
+ TString message_type_name = GetMessageTypeFromMethod(method, is_request);
+ if (has_error_) {
+ return "";
+ }
+ return GetFormattedStringFromMessageType(message_type_name, serialized_proto,
+ is_json_format);
+}
+
+TString ProtoFileParser::GetSerializedProtoFromMessageType(
+ const TString& message_type_name, const TString& formatted_proto,
+ bool is_json_format) {
+ has_error_ = false;
+ google::protobuf::string serialized;
+ const protobuf::Descriptor* desc =
+ desc_pool_->FindMessageTypeByName(google::protobuf::string(message_type_name));
+ if (!desc) {
+ LogError("Message type not found");
+ return "";
+ }
+ std::unique_ptr<grpc::protobuf::Message> msg(
+ dynamic_factory_->GetPrototype(desc)->New());
+ bool ok;
+ if (is_json_format) {
+ ok = grpc::protobuf::json::JsonStringToMessage(google::protobuf::string(formatted_proto), msg.get())
+ .ok();
+ if (!ok) {
+ LogError("Failed to convert json format to proto.");
+ return "";
+ }
+ } else {
+ ok = protobuf::TextFormat::ParseFromString(google::protobuf::string(formatted_proto), msg.get());
+ if (!ok) {
+ LogError("Failed to convert text format to proto.");
+ return "";
+ }
+ }
+
+ ok = msg->SerializeToString(&serialized);
+ if (!ok) {
+ LogError("Failed to serialize proto.");
+ return "";
+ }
+ return serialized;
+}
+
+TString ProtoFileParser::GetFormattedStringFromMessageType(
+ const TString& message_type_name, const TString& serialized_proto,
+ bool is_json_format) {
+ has_error_ = false;
+ const protobuf::Descriptor* desc =
+ desc_pool_->FindMessageTypeByName(google::protobuf::string(message_type_name));
+ if (!desc) {
+ LogError("Message type not found");
+ return "";
+ }
+ std::unique_ptr<grpc::protobuf::Message> msg(
+ dynamic_factory_->GetPrototype(desc)->New());
+ if (!msg->ParseFromString(google::protobuf::string(serialized_proto))) {
+ LogError("Failed to deserialize proto.");
+ return "";
+ }
+ google::protobuf::string formatted_string;
+
+ if (is_json_format) {
+ grpc::protobuf::json::JsonPrintOptions jsonPrintOptions;
+ jsonPrintOptions.add_whitespace = true;
+ if (!grpc::protobuf::json::MessageToJsonString(
+ *msg.get(), &formatted_string, jsonPrintOptions)
+ .ok()) {
+ LogError("Failed to print proto message to json format");
+ return "";
+ }
+ } else {
+ if (!protobuf::TextFormat::PrintToString(*msg.get(), &formatted_string)) {
+ LogError("Failed to print proto message to text format");
+ return "";
+ }
+ }
+ return formatted_string;
+}
+
+void ProtoFileParser::LogError(const TString& error_msg) {
+ if (!error_msg.empty()) {
+ std::cerr << error_msg << std::endl;
+ }
+ has_error_ = true;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/proto_file_parser.h b/contrib/libs/grpc/test/cpp/util/proto_file_parser.h
new file mode 100644
index 0000000000..c0445641c7
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/proto_file_parser.h
@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_PROTO_FILE_PARSER_H
+#define GRPC_TEST_CPP_UTIL_PROTO_FILE_PARSER_H
+
+#include <memory>
+
+#include <grpcpp/channel.h>
+
+#include "test/cpp/util/config_grpc_cli.h"
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
+
+namespace grpc {
+namespace testing {
+class ErrorPrinter;
+
+// Find method and associated request/response types.
+class ProtoFileParser {
+ public:
+ // The parser will search proto files using the server reflection service
+ // provided on the given channel. The given protofiles in a source tree rooted
+ // from proto_path will also be searched.
+ ProtoFileParser(const std::shared_ptr<grpc::Channel>& channel,
+ const TString& proto_path, const TString& protofiles);
+
+ ~ProtoFileParser();
+
+ // The input method name in the following four functions could be a partial
+ // string such as Service.Method or even just Method. It will log an error if
+ // there is ambiguity.
+ // Full method name is in the form of Service.Method, it's good to be used in
+ // descriptor database queries.
+ TString GetFullMethodName(const TString& method);
+
+ // Formatted method name is in the form of /Service/Method, it's good to be
+ // used as the argument of Stub::Call()
+ TString GetFormattedMethodName(const TString& method);
+
+ /// Converts a text or json string to its binary proto representation for the
+ /// given method's input or return type.
+ /// \param method the name of the method (does not need to be fully qualified
+ /// name)
+ /// \param formatted_proto the text- or json-formatted proto string
+ /// \param is_request if \c true the resolved type is that of the input
+ /// parameter of the method, otherwise it is the output type
+ /// \param is_json_format if \c true the \c formatted_proto is treated as a
+ /// json-formatted proto, otherwise it is treated as a text-formatted
+ /// proto
+ /// \return the serialised binary proto representation of \c formatted_proto
+ TString GetSerializedProtoFromMethod(const TString& method,
+ const TString& formatted_proto,
+ bool is_request,
+ bool is_json_format);
+
+ /// Converts a text or json string to its proto representation for the given
+ /// message type.
+ /// \param formatted_proto the text- or json-formatted proto string
+ /// \return the serialised binary proto representation of \c formatted_proto
+ TString GetSerializedProtoFromMessageType(
+ const TString& message_type_name, const TString& formatted_proto,
+ bool is_json_format);
+
+ /// Converts a binary proto string to its text or json string representation
+ /// for the given method's input or return type.
+ /// \param method the name of the method (does not need to be a fully
+ /// qualified name)
+ /// \param the serialised binary proto representation of type
+ /// \c message_type_name
+ /// \return the text- or json-formatted proto string of \c serialized_proto
+ TString GetFormattedStringFromMethod(const TString& method,
+ const TString& serialized_proto,
+ bool is_request,
+ bool is_json_format);
+
+ /// Converts a binary proto string to its text or json string representation
+ /// for the given message type.
+ /// \param the serialised binary proto representation of type
+ /// \c message_type_name
+ /// \return the text- or json-formatted proto string of \c serialized_proto
+ TString GetFormattedStringFromMessageType(
+ const TString& message_type_name, const TString& serialized_proto,
+ bool is_json_format);
+
+ bool IsStreaming(const TString& method, bool is_request);
+
+ bool HasError() const { return has_error_; }
+
+ void LogError(const TString& error_msg);
+
+ private:
+ TString GetMessageTypeFromMethod(const TString& method,
+ bool is_request);
+
+ bool has_error_;
+ TString request_text_;
+ protobuf::compiler::DiskSourceTree source_tree_;
+ std::unique_ptr<ErrorPrinter> error_printer_;
+ std::unique_ptr<protobuf::compiler::Importer> importer_;
+ std::unique_ptr<grpc::ProtoReflectionDescriptorDatabase> reflection_db_;
+ std::unique_ptr<protobuf::DescriptorPoolDatabase> file_db_;
+ std::unique_ptr<protobuf::DescriptorDatabase> desc_db_;
+ std::unique_ptr<protobuf::DescriptorPool> desc_pool_;
+ std::unique_ptr<protobuf::DynamicMessageFactory> dynamic_factory_;
+ std::unique_ptr<grpc::protobuf::Message> request_prototype_;
+ std::unique_ptr<grpc::protobuf::Message> response_prototype_;
+ std::unordered_map<TString, TString> known_methods_;
+ std::vector<const protobuf::ServiceDescriptor*> service_desc_list_;
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_PROTO_FILE_PARSER_H
diff --git a/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.cc b/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.cc
new file mode 100644
index 0000000000..27a4c1e4cf
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.cc
@@ -0,0 +1,333 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
+
+#include <vector>
+
+#include <grpc/support/log.h>
+
+using grpc::reflection::v1alpha::ErrorResponse;
+using grpc::reflection::v1alpha::ListServiceResponse;
+using grpc::reflection::v1alpha::ServerReflection;
+using grpc::reflection::v1alpha::ServerReflectionRequest;
+using grpc::reflection::v1alpha::ServerReflectionResponse;
+
+namespace grpc {
+
+ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase(
+ std::unique_ptr<ServerReflection::Stub> stub)
+ : stub_(std::move(stub)) {}
+
+ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase(
+ const std::shared_ptr<grpc::Channel>& channel)
+ : stub_(ServerReflection::NewStub(channel)) {}
+
+ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {
+ if (stream_) {
+ stream_->WritesDone();
+ Status status = stream_->Finish();
+ if (!status.ok()) {
+ if (status.error_code() == StatusCode::UNIMPLEMENTED) {
+ fprintf(stderr,
+ "Reflection request not implemented; "
+ "is the ServerReflection service enabled?\n");
+ } else {
+ fprintf(stderr,
+ "ServerReflectionInfo rpc failed. Error code: %d, message: %s, "
+ "debug info: %s\n",
+ static_cast<int>(status.error_code()),
+ status.error_message().c_str(),
+ ctx_.debug_error_string().c_str());
+ }
+ }
+ }
+}
+
+bool ProtoReflectionDescriptorDatabase::FindFileByName(
+ const google::protobuf::string& filename, 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;
+
+ if (!DoOneRequest(request, response)) {
+ return false;
+ }
+
+ 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 google::protobuf::string& symbol_name, 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;
+
+ if (!DoOneRequest(request, response)) {
+ return false;
+ }
+
+ 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 google::protobuf::string& containing_type, int field_number,
+ 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;
+
+ if (!DoOneRequest(request, response)) {
+ return false;
+ }
+
+ 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 google::protobuf::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;
+
+ if (!DoOneRequest(request, response)) {
+ return false;
+ }
+
+ 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<TString>* output) {
+ ServerReflectionRequest request;
+ request.set_list_services("");
+ ServerReflectionResponse response;
+
+ if (!DoOneRequest(request, response)) {
+ return false;
+ }
+
+ 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 protobuf::FileDescriptorProto
+ProtoReflectionDescriptorDatabase::ParseFileDescriptorProtoResponse(
+ const TString& byte_fd_proto) {
+ protobuf::FileDescriptorProto file_desc_proto;
+ file_desc_proto.ParseFromString(google::protobuf::string(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 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_) {
+ stream_ = stub_->ServerReflectionInfo(&ctx_);
+ }
+ return stream_;
+}
+
+bool ProtoReflectionDescriptorDatabase::DoOneRequest(
+ const ServerReflectionRequest& request,
+ ServerReflectionResponse& response) {
+ bool success = false;
+ stream_mutex_.lock();
+ if (GetStream()->Write(request) && GetStream()->Read(&response)) {
+ success = true;
+ }
+ stream_mutex_.unlock();
+ return success;
+}
+
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.h b/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.h
new file mode 100644
index 0000000000..cdd6f0cccd
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/proto_reflection_descriptor_database.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#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 <grpcpp/grpcpp.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.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 protobuf::DescriptorDatabase {
+ public:
+ explicit ProtoReflectionDescriptorDatabase(
+ std::unique_ptr<reflection::v1alpha::ServerReflection::Stub> stub);
+
+ explicit ProtoReflectionDescriptorDatabase(
+ const std::shared_ptr<grpc::Channel>& channel);
+
+ virtual ~ProtoReflectionDescriptorDatabase();
+
+ // The following four methods implement DescriptorDatabase interfaces.
+ //
+ // Find a file by file name. Fills in *output and returns true if found.
+ // Otherwise, returns false, leaving the contents of *output undefined.
+ bool FindFileByName(const google::protobuf::string& filename,
+ protobuf::FileDescriptorProto* output) 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 google::protobuf::string& symbol_name,
+ protobuf::FileDescriptorProto* output) 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 google::protobuf::string& containing_type, int field_number,
+ protobuf::FileDescriptorProto* output) 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 google::protobuf::string& extendee_type,
+ std::vector<int>* output) override;
+
+ // Provide a list of full names of registered services
+ bool GetServices(std::vector<TString>* output);
+
+ private:
+ typedef ClientReaderWriter<
+ grpc::reflection::v1alpha::ServerReflectionRequest,
+ grpc::reflection::v1alpha::ServerReflectionResponse>
+ ClientStream;
+
+ const protobuf::FileDescriptorProto ParseFileDescriptorProtoResponse(
+ const TString& byte_fd_proto);
+
+ void AddFileFromResponse(
+ const grpc::reflection::v1alpha::FileDescriptorResponse& response);
+
+ const std::shared_ptr<ClientStream> GetStream();
+
+ bool 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_;
+
+ protobuf::SimpleDescriptorDatabase cached_db_;
+};
+
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_METRICS_SERVER_H
diff --git a/contrib/libs/grpc/test/cpp/util/service_describer.cc b/contrib/libs/grpc/test/cpp/util/service_describer.cc
new file mode 100644
index 0000000000..2af1104b97
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/service_describer.cc
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/service_describer.h"
+
+#include <iostream>
+#include <sstream>
+#include <util/generic/string.h>
+#include <vector>
+
+namespace grpc {
+namespace testing {
+
+TString DescribeServiceList(std::vector<TString> service_list,
+ grpc::protobuf::DescriptorPool& desc_pool) {
+ std::stringstream result;
+ for (auto it = service_list.begin(); it != service_list.end(); it++) {
+ auto const& service = *it;
+ const grpc::protobuf::ServiceDescriptor* service_desc =
+ desc_pool.FindServiceByName(google::protobuf::string(service));
+ if (service_desc != nullptr) {
+ result << DescribeService(service_desc);
+ }
+ }
+ return result.str();
+}
+
+TString DescribeService(const grpc::protobuf::ServiceDescriptor* service) {
+ TString result;
+ if (service->options().deprecated()) {
+ result.append("DEPRECATED\n");
+ }
+ result.append("filename: " + service->file()->name() + "\n");
+
+ TString package = service->full_name();
+ size_t pos = package.rfind("." + service->name());
+ if (pos != TString::npos) {
+ package.erase(pos);
+ result.append("package: " + package + ";\n");
+ }
+ result.append("service " + service->name() + " {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ result.append(DescribeMethod(service->method(i)));
+ }
+ result.append("}\n\n");
+ return result;
+}
+
+TString DescribeMethod(const grpc::protobuf::MethodDescriptor* method) {
+ std::stringstream result;
+ result << " rpc " << method->name()
+ << (method->client_streaming() ? "(stream " : "(")
+ << method->input_type()->full_name() << ") returns "
+ << (method->server_streaming() ? "(stream " : "(")
+ << method->output_type()->full_name() << ") {}\n";
+ if (method->options().deprecated()) {
+ result << " DEPRECATED";
+ }
+ return result.str();
+}
+
+TString SummarizeService(const grpc::protobuf::ServiceDescriptor* service) {
+ TString result;
+ for (int i = 0; i < service->method_count(); ++i) {
+ result.append(SummarizeMethod(service->method(i)));
+ }
+ return result;
+}
+
+TString SummarizeMethod(const grpc::protobuf::MethodDescriptor* method) {
+ TString result = method->name();
+ result.append("\n");
+ return result;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/service_describer.h b/contrib/libs/grpc/test/cpp/util/service_describer.h
new file mode 100644
index 0000000000..a473f03744
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/service_describer.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
+#define GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
+
+#include <grpcpp/support/config.h>
+#include "test/cpp/util/config_grpc_cli.h"
+
+namespace grpc {
+namespace testing {
+
+TString DescribeServiceList(std::vector<TString> service_list,
+ grpc::protobuf::DescriptorPool& desc_pool);
+
+TString DescribeService(const grpc::protobuf::ServiceDescriptor* service);
+
+TString DescribeMethod(const grpc::protobuf::MethodDescriptor* method);
+
+TString SummarizeService(const grpc::protobuf::ServiceDescriptor* service);
+
+TString SummarizeMethod(const grpc::protobuf::MethodDescriptor* method);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
diff --git a/contrib/libs/grpc/test/cpp/util/slice_test.cc b/contrib/libs/grpc/test/cpp/util/slice_test.cc
new file mode 100644
index 0000000000..d7e945ae38
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/slice_test.cc
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc++/support/slice.h>
+#include <grpcpp/impl/grpc_library.h>
+
+#include <grpc/grpc.h>
+#include <grpc/slice.h>
+#include <gtest/gtest.h>
+
+#include "test/core/util/test_config.h"
+
+namespace grpc {
+
+static internal::GrpcLibraryInitializer g_gli_initializer;
+
+namespace {
+
+const char* kContent = "hello xxxxxxxxxxxxxxxxxxxx world";
+
+class SliceTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() { grpc_init(); }
+
+ static void TearDownTestCase() { grpc_shutdown(); }
+
+ void CheckSliceSize(const Slice& s, const TString& content) {
+ EXPECT_EQ(content.size(), s.size());
+ }
+ void CheckSlice(const Slice& s, const TString& content) {
+ EXPECT_EQ(content.size(), s.size());
+ EXPECT_EQ(content,
+ TString(reinterpret_cast<const char*>(s.begin()), s.size()));
+ }
+};
+
+TEST_F(SliceTest, Empty) {
+ Slice empty_slice;
+ CheckSlice(empty_slice, "");
+}
+
+TEST_F(SliceTest, Sized) {
+ Slice sized_slice(strlen(kContent));
+ CheckSliceSize(sized_slice, kContent);
+}
+
+TEST_F(SliceTest, String) {
+ Slice spp(kContent);
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, Buf) {
+ Slice spp(kContent, strlen(kContent));
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, StaticBuf) {
+ Slice spp(kContent, strlen(kContent), Slice::STATIC_SLICE);
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, SliceNew) {
+ char* x = new char[strlen(kContent) + 1];
+ strcpy(x, kContent);
+ Slice spp(x, strlen(x), [](void* p) { delete[] static_cast<char*>(p); });
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, SliceNewDoNothing) {
+ Slice spp(const_cast<char*>(kContent), strlen(kContent), [](void* /*p*/) {});
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, SliceNewWithUserData) {
+ struct stest {
+ char* x;
+ int y;
+ };
+ auto* t = new stest;
+ t->x = new char[strlen(kContent) + 1];
+ strcpy(t->x, kContent);
+ Slice spp(t->x, strlen(t->x),
+ [](void* p) {
+ auto* t = static_cast<stest*>(p);
+ delete[] t->x;
+ delete t;
+ },
+ t);
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, SliceNewLen) {
+ Slice spp(const_cast<char*>(kContent), strlen(kContent),
+ [](void* /*p*/, size_t l) { EXPECT_EQ(l, strlen(kContent)); });
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, Steal) {
+ grpc_slice s = grpc_slice_from_copied_string(kContent);
+ Slice spp(s, Slice::STEAL_REF);
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, Add) {
+ grpc_slice s = grpc_slice_from_copied_string(kContent);
+ Slice spp(s, Slice::ADD_REF);
+ grpc_slice_unref(s);
+ CheckSlice(spp, kContent);
+}
+
+TEST_F(SliceTest, Cslice) {
+ grpc_slice s = grpc_slice_from_copied_string(kContent);
+ Slice spp(s, Slice::STEAL_REF);
+ CheckSlice(spp, kContent);
+ grpc_slice c_slice = spp.c_slice();
+ EXPECT_EQ(GRPC_SLICE_START_PTR(s), GRPC_SLICE_START_PTR(c_slice));
+ EXPECT_EQ(GRPC_SLICE_END_PTR(s), GRPC_SLICE_END_PTR(c_slice));
+ grpc_slice_unref(c_slice);
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
diff --git a/contrib/libs/grpc/test/cpp/util/string_ref_helper.cc b/contrib/libs/grpc/test/cpp/util/string_ref_helper.cc
new file mode 100644
index 0000000000..e573f5d33a
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/string_ref_helper.cc
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/string_ref_helper.h"
+
+namespace grpc {
+namespace testing {
+
+TString ToString(const grpc::string_ref& r) {
+ return TString(r.data(), r.size());
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/string_ref_helper.h b/contrib/libs/grpc/test/cpp/util/string_ref_helper.h
new file mode 100644
index 0000000000..e9e941f319
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/string_ref_helper.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H
+#define GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H
+
+#include <grpcpp/support/string_ref.h>
+
+namespace grpc {
+namespace testing {
+
+TString ToString(const grpc::string_ref& r);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H
diff --git a/contrib/libs/grpc/test/cpp/util/string_ref_test.cc b/contrib/libs/grpc/test/cpp/util/string_ref_test.cc
new file mode 100644
index 0000000000..8e3259b764
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/string_ref_test.cc
@@ -0,0 +1,205 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpcpp/support/string_ref.h>
+
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#include "test/core/util/test_config.h"
+
+namespace grpc {
+namespace {
+
+const char kTestString[] = "blah";
+const char kTestStringWithEmbeddedNull[] = "blah\0foo";
+const size_t kTestStringWithEmbeddedNullLength = 8;
+const char kTestUnrelatedString[] = "foo";
+
+class StringRefTest : public ::testing::Test {};
+
+TEST_F(StringRefTest, Empty) {
+ string_ref s;
+ EXPECT_EQ(0U, s.length());
+ EXPECT_EQ(nullptr, s.data());
+}
+
+TEST_F(StringRefTest, FromCString) {
+ string_ref s(kTestString);
+ EXPECT_EQ(strlen(kTestString), s.length());
+ EXPECT_EQ(kTestString, s.data());
+}
+
+TEST_F(StringRefTest, FromCStringWithLength) {
+ string_ref s(kTestString, 2);
+ EXPECT_EQ(2U, s.length());
+ EXPECT_EQ(kTestString, s.data());
+}
+
+TEST_F(StringRefTest, FromString) {
+ string copy(kTestString);
+ string_ref s(copy);
+ EXPECT_EQ(copy.data(), s.data());
+ EXPECT_EQ(copy.length(), s.length());
+}
+
+TEST_F(StringRefTest, CopyConstructor) {
+ string_ref s1(kTestString);
+ ;
+ const string_ref& s2(s1);
+ EXPECT_EQ(s1.length(), s2.length());
+ EXPECT_EQ(s1.data(), s2.data());
+}
+
+TEST_F(StringRefTest, FromStringWithEmbeddedNull) {
+ string copy(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ string_ref s(copy);
+ EXPECT_EQ(copy.data(), s.data());
+ EXPECT_EQ(copy.length(), s.length());
+ EXPECT_EQ(kTestStringWithEmbeddedNullLength, s.length());
+}
+
+TEST_F(StringRefTest, Assignment) {
+ string_ref s1(kTestString);
+ ;
+ string_ref s2;
+ EXPECT_EQ(nullptr, s2.data());
+ s2 = s1;
+ EXPECT_EQ(s1.length(), s2.length());
+ EXPECT_EQ(s1.data(), s2.data());
+}
+
+TEST_F(StringRefTest, Iterator) {
+ string_ref s(kTestString);
+ size_t i = 0;
+ for (auto it = s.cbegin(); it != s.cend(); ++it) {
+ auto val = kTestString[i++];
+ EXPECT_EQ(val, *it);
+ }
+ EXPECT_EQ(strlen(kTestString), i);
+}
+
+TEST_F(StringRefTest, ReverseIterator) {
+ string_ref s(kTestString);
+ size_t i = strlen(kTestString);
+ for (auto rit = s.crbegin(); rit != s.crend(); ++rit) {
+ auto val = kTestString[--i];
+ EXPECT_EQ(val, *rit);
+ }
+ EXPECT_EQ(0U, i);
+}
+
+TEST_F(StringRefTest, Capacity) {
+ string_ref empty;
+ EXPECT_EQ(0U, empty.length());
+ EXPECT_EQ(0U, empty.size());
+ EXPECT_EQ(0U, empty.max_size());
+ EXPECT_TRUE(empty.empty());
+
+ string_ref s(kTestString);
+ EXPECT_EQ(strlen(kTestString), s.length());
+ EXPECT_EQ(s.length(), s.size());
+ EXPECT_EQ(s.max_size(), s.length());
+ EXPECT_FALSE(s.empty());
+}
+
+TEST_F(StringRefTest, Compare) {
+ string_ref s1(kTestString);
+ string s1_copy(kTestString);
+ string_ref s2(kTestUnrelatedString);
+ string_ref s3(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ EXPECT_EQ(0, s1.compare(s1_copy));
+ EXPECT_NE(0, s1.compare(s2));
+ EXPECT_NE(0, s1.compare(s3));
+}
+
+TEST_F(StringRefTest, StartsWith) {
+ string_ref s1(kTestString);
+ string_ref s2(kTestUnrelatedString);
+ string_ref s3(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ EXPECT_TRUE(s1.starts_with(s1));
+ EXPECT_FALSE(s1.starts_with(s2));
+ EXPECT_FALSE(s2.starts_with(s1));
+ EXPECT_FALSE(s1.starts_with(s3));
+ EXPECT_TRUE(s3.starts_with(s1));
+}
+
+TEST_F(StringRefTest, Endswith) {
+ string_ref s1(kTestString);
+ string_ref s2(kTestUnrelatedString);
+ string_ref s3(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ EXPECT_TRUE(s1.ends_with(s1));
+ EXPECT_FALSE(s1.ends_with(s2));
+ EXPECT_FALSE(s2.ends_with(s1));
+ EXPECT_FALSE(s2.ends_with(s3));
+ EXPECT_TRUE(s3.ends_with(s2));
+}
+
+TEST_F(StringRefTest, Find) {
+ string_ref s1(kTestString);
+ string_ref s2(kTestUnrelatedString);
+ string_ref s3(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ EXPECT_EQ(0U, s1.find(s1));
+ EXPECT_EQ(0U, s2.find(s2));
+ EXPECT_EQ(0U, s3.find(s3));
+ EXPECT_EQ(string_ref::npos, s1.find(s2));
+ EXPECT_EQ(string_ref::npos, s2.find(s1));
+ EXPECT_EQ(string_ref::npos, s1.find(s3));
+ EXPECT_EQ(0U, s3.find(s1));
+ EXPECT_EQ(5U, s3.find(s2));
+ EXPECT_EQ(string_ref::npos, s1.find('z'));
+ EXPECT_EQ(1U, s2.find('o'));
+}
+
+TEST_F(StringRefTest, SubString) {
+ string_ref s(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ string_ref sub1 = s.substr(0, 4);
+ EXPECT_EQ(string_ref(kTestString), sub1);
+ string_ref sub2 = s.substr(5);
+ EXPECT_EQ(string_ref(kTestUnrelatedString), sub2);
+}
+
+TEST_F(StringRefTest, ComparisonOperators) {
+ string_ref s1(kTestString);
+ string_ref s2(kTestUnrelatedString);
+ string_ref s3(kTestStringWithEmbeddedNull, kTestStringWithEmbeddedNullLength);
+ EXPECT_EQ(s1, s1);
+ EXPECT_EQ(s2, s2);
+ EXPECT_EQ(s3, s3);
+ EXPECT_GE(s1, s1);
+ EXPECT_GE(s2, s2);
+ EXPECT_GE(s3, s3);
+ EXPECT_LE(s1, s1);
+ EXPECT_LE(s2, s2);
+ EXPECT_LE(s3, s3);
+ EXPECT_NE(s1, s2);
+ EXPECT_NE(s1, s3);
+ EXPECT_NE(s2, s3);
+ EXPECT_GT(s3, s1);
+ EXPECT_LT(s1, s3);
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/libs/grpc/test/cpp/util/subprocess.cc b/contrib/libs/grpc/test/cpp/util/subprocess.cc
new file mode 100644
index 0000000000..648bd50274
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/subprocess.cc
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/subprocess.h"
+
+#include <vector>
+
+#include "test/core/util/subprocess.h"
+
+namespace grpc {
+
+static gpr_subprocess* MakeProcess(const std::vector<TString>& args) {
+ std::vector<const char*> vargs;
+ for (auto it = args.begin(); it != args.end(); ++it) {
+ vargs.push_back(it->c_str());
+ }
+ return gpr_subprocess_create(vargs.size(), &vargs[0]);
+}
+
+SubProcess::SubProcess(const std::vector<TString>& args)
+ : subprocess_(MakeProcess(args)) {}
+
+SubProcess::~SubProcess() { gpr_subprocess_destroy(subprocess_); }
+
+int SubProcess::Join() { return gpr_subprocess_join(subprocess_); }
+
+void SubProcess::Interrupt() { gpr_subprocess_interrupt(subprocess_); }
+
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/subprocess.h b/contrib/libs/grpc/test/cpp/util/subprocess.h
new file mode 100644
index 0000000000..84dda31dd1
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/subprocess.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_SUBPROCESS_H
+#define GRPC_TEST_CPP_UTIL_SUBPROCESS_H
+
+#include <initializer_list>
+#include <util/generic/string.h>
+#include <vector>
+
+struct gpr_subprocess;
+
+namespace grpc {
+
+class SubProcess {
+ public:
+ SubProcess(const std::vector<TString>& args);
+ ~SubProcess();
+
+ int Join();
+ void Interrupt();
+
+ private:
+ SubProcess(const SubProcess& other);
+ SubProcess& operator=(const SubProcess& other);
+
+ gpr_subprocess* const subprocess_;
+};
+
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_SUBPROCESS_H
diff --git a/contrib/libs/grpc/test/cpp/util/test_config.h b/contrib/libs/grpc/test/cpp/util/test_config.h
new file mode 100644
index 0000000000..094ed44f63
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/test_config.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_TEST_CONFIG_H
+#define GRPC_TEST_CPP_UTIL_TEST_CONFIG_H
+
+namespace grpc {
+namespace testing {
+
+void InitTest(int* argc, char*** argv, bool remove_flags);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_TEST_CONFIG_H
diff --git a/contrib/libs/grpc/test/cpp/util/test_config_cc.cc b/contrib/libs/grpc/test/cpp/util/test_config_cc.cc
new file mode 100644
index 0000000000..e4b6886335
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/test_config_cc.cc
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <gflags/gflags.h>
+#include "test/cpp/util/test_config.h"
+
+// In some distros, gflags is in the namespace google, and in some others,
+// in gflags. This hack is enabling us to find both.
+namespace google {}
+namespace gflags {}
+using namespace google;
+using namespace gflags;
+
+namespace grpc {
+namespace testing {
+
+void InitTest(int* argc, char*** argv, bool remove_flags) {
+ ParseCommandLineFlags(argc, argv, remove_flags);
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/test_credentials_provider.cc b/contrib/libs/grpc/test/cpp/util/test_credentials_provider.cc
new file mode 100644
index 0000000000..f7134b773f
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/test_credentials_provider.cc
@@ -0,0 +1,181 @@
+
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/cpp/util/test_credentials_provider.h"
+
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+
+#include <mutex>
+#include <unordered_map>
+
+#include <gflags/gflags.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpcpp/security/server_credentials.h>
+
+#include "test/core/end2end/data/ssl_test_data.h"
+
+DEFINE_string(tls_cert_file, "", "The TLS cert file used when --use_tls=true");
+DEFINE_string(tls_key_file, "", "The TLS key file used when --use_tls=true");
+
+namespace grpc {
+namespace testing {
+namespace {
+
+TString ReadFile(const TString& src_path) {
+ std::ifstream src;
+ src.open(src_path, std::ifstream::in | std::ifstream::binary);
+
+ TString contents;
+ src.seekg(0, std::ios::end);
+ contents.reserve(src.tellg());
+ src.seekg(0, std::ios::beg);
+ contents.assign((std::istreambuf_iterator<char>(src)),
+ (std::istreambuf_iterator<char>()));
+ return contents;
+}
+
+class DefaultCredentialsProvider : public CredentialsProvider {
+ public:
+ DefaultCredentialsProvider() {
+ if (!FLAGS_tls_key_file.empty()) {
+ custom_server_key_ = ReadFile(FLAGS_tls_key_file);
+ }
+ if (!FLAGS_tls_cert_file.empty()) {
+ custom_server_cert_ = ReadFile(FLAGS_tls_cert_file);
+ }
+ }
+ ~DefaultCredentialsProvider() override {}
+
+ void AddSecureType(
+ const TString& type,
+ std::unique_ptr<CredentialTypeProvider> type_provider) override {
+ // This clobbers any existing entry for type, except the defaults, which
+ // can't be clobbered.
+ std::unique_lock<std::mutex> lock(mu_);
+ auto it = std::find(added_secure_type_names_.begin(),
+ added_secure_type_names_.end(), type);
+ if (it == added_secure_type_names_.end()) {
+ added_secure_type_names_.push_back(type);
+ added_secure_type_providers_.push_back(std::move(type_provider));
+ } else {
+ added_secure_type_providers_[it - added_secure_type_names_.begin()] =
+ std::move(type_provider);
+ }
+ }
+
+ std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+ const TString& type, ChannelArguments* args) override {
+ if (type == grpc::testing::kInsecureCredentialsType) {
+ return InsecureChannelCredentials();
+ } else if (type == grpc::testing::kAltsCredentialsType) {
+ grpc::experimental::AltsCredentialsOptions alts_opts;
+ return grpc::experimental::AltsCredentials(alts_opts);
+ } else if (type == grpc::testing::kTlsCredentialsType) {
+ SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
+ args->SetSslTargetNameOverride("foo.test.google.fr");
+ return grpc::SslCredentials(ssl_opts);
+ } else if (type == grpc::testing::kGoogleDefaultCredentialsType) {
+ return grpc::GoogleDefaultCredentials();
+ } else {
+ std::unique_lock<std::mutex> lock(mu_);
+ auto it(std::find(added_secure_type_names_.begin(),
+ added_secure_type_names_.end(), type));
+ if (it == added_secure_type_names_.end()) {
+ gpr_log(GPR_ERROR, "Unsupported credentials type %s.", type.c_str());
+ return nullptr;
+ }
+ return added_secure_type_providers_[it - added_secure_type_names_.begin()]
+ ->GetChannelCredentials(args);
+ }
+ }
+
+ std::shared_ptr<ServerCredentials> GetServerCredentials(
+ const TString& type) override {
+ if (type == grpc::testing::kInsecureCredentialsType) {
+ return InsecureServerCredentials();
+ } else if (type == grpc::testing::kAltsCredentialsType) {
+ grpc::experimental::AltsServerCredentialsOptions alts_opts;
+ return grpc::experimental::AltsServerCredentials(alts_opts);
+ } else if (type == grpc::testing::kTlsCredentialsType) {
+ SslServerCredentialsOptions ssl_opts;
+ ssl_opts.pem_root_certs = "";
+ if (!custom_server_key_.empty() && !custom_server_cert_.empty()) {
+ SslServerCredentialsOptions::PemKeyCertPair pkcp = {
+ custom_server_key_, custom_server_cert_};
+ ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+ } else {
+ SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
+ test_server1_cert};
+ ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+ }
+ return SslServerCredentials(ssl_opts);
+ } else {
+ std::unique_lock<std::mutex> lock(mu_);
+ auto it(std::find(added_secure_type_names_.begin(),
+ added_secure_type_names_.end(), type));
+ if (it == added_secure_type_names_.end()) {
+ gpr_log(GPR_ERROR, "Unsupported credentials type %s.", type.c_str());
+ return nullptr;
+ }
+ return added_secure_type_providers_[it - added_secure_type_names_.begin()]
+ ->GetServerCredentials();
+ }
+ }
+ std::vector<TString> GetSecureCredentialsTypeList() override {
+ std::vector<TString> types;
+ types.push_back(grpc::testing::kTlsCredentialsType);
+ std::unique_lock<std::mutex> lock(mu_);
+ for (auto it = added_secure_type_names_.begin();
+ it != added_secure_type_names_.end(); it++) {
+ types.push_back(*it);
+ }
+ return types;
+ }
+
+ private:
+ std::mutex mu_;
+ std::vector<TString> added_secure_type_names_;
+ std::vector<std::unique_ptr<CredentialTypeProvider>>
+ added_secure_type_providers_;
+ TString custom_server_key_;
+ TString custom_server_cert_;
+};
+
+CredentialsProvider* g_provider = nullptr;
+
+} // namespace
+
+CredentialsProvider* GetCredentialsProvider() {
+ if (g_provider == nullptr) {
+ g_provider = new DefaultCredentialsProvider;
+ }
+ return g_provider;
+}
+
+void SetCredentialsProvider(CredentialsProvider* provider) {
+ // For now, forbids overriding provider.
+ GPR_ASSERT(g_provider == nullptr);
+ g_provider = provider;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/contrib/libs/grpc/test/cpp/util/test_credentials_provider.h b/contrib/libs/grpc/test/cpp/util/test_credentials_provider.h
new file mode 100644
index 0000000000..acba277ada
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/test_credentials_provider.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H
+#define GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H
+
+#include <memory>
+
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+namespace testing {
+
+const char kInsecureCredentialsType[] = "INSECURE_CREDENTIALS";
+// For real credentials, like tls/ssl, this name should match the AuthContext
+// property "transport_security_type".
+const char kTlsCredentialsType[] = "ssl";
+const char kAltsCredentialsType[] = "alts";
+const char kGoogleDefaultCredentialsType[] = "google_default_credentials";
+
+// Provide test credentials of a particular type.
+class CredentialTypeProvider {
+ public:
+ virtual ~CredentialTypeProvider() {}
+
+ virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+ ChannelArguments* args) = 0;
+ virtual std::shared_ptr<ServerCredentials> GetServerCredentials() = 0;
+};
+
+// Provide test credentials. Thread-safe.
+class CredentialsProvider {
+ public:
+ virtual ~CredentialsProvider() {}
+
+ // Add a secure type in addition to the defaults. The default provider has
+ // (kInsecureCredentialsType, kTlsCredentialsType).
+ virtual void AddSecureType(
+ const TString& type,
+ std::unique_ptr<CredentialTypeProvider> type_provider) = 0;
+
+ // Provide channel credentials according to the given type. Alter the channel
+ // arguments if needed. Return nullptr if type is not registered.
+ virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+ const TString& type, ChannelArguments* args) = 0;
+
+ // Provide server credentials according to the given type.
+ // Return nullptr if type is not registered.
+ virtual std::shared_ptr<ServerCredentials> GetServerCredentials(
+ const TString& type) = 0;
+
+ // Provide a list of secure credentials type.
+ virtual std::vector<TString> GetSecureCredentialsTypeList() = 0;
+};
+
+// Get the current provider. Create a default one if not set.
+// Not thread-safe.
+CredentialsProvider* GetCredentialsProvider();
+
+// Set the global provider. Takes ownership. The previous set provider will be
+// destroyed.
+// Not thread-safe.
+void SetCredentialsProvider(CredentialsProvider* provider);
+
+} // namespace testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_TEST_CREDENTIALS_PROVIDER_H
diff --git a/contrib/libs/grpc/test/cpp/util/time_test.cc b/contrib/libs/grpc/test/cpp/util/time_test.cc
new file mode 100644
index 0000000000..bcbfa14f94
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/time_test.cc
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/time.h>
+#include <grpcpp/support/time.h>
+#include <gtest/gtest.h>
+
+#include "test/core/util/test_config.h"
+
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace {
+
+class TimeTest : public ::testing::Test {};
+
+TEST_F(TimeTest, AbsolutePointTest) {
+ int64_t us = 10000000L;
+ gpr_timespec ts = gpr_time_from_micros(us, GPR_TIMESPAN);
+ ts.clock_type = GPR_CLOCK_REALTIME;
+ system_clock::time_point tp{microseconds(us)};
+ system_clock::time_point tp_converted = Timespec2Timepoint(ts);
+ gpr_timespec ts_converted;
+ Timepoint2Timespec(tp_converted, &ts_converted);
+ EXPECT_TRUE(ts.tv_sec == ts_converted.tv_sec);
+ EXPECT_TRUE(ts.tv_nsec == ts_converted.tv_nsec);
+ system_clock::time_point tp_converted_2 = Timespec2Timepoint(ts_converted);
+ EXPECT_TRUE(tp == tp_converted);
+ EXPECT_TRUE(tp == tp_converted_2);
+}
+
+// gpr_inf_future is treated specially and mapped to/from time_point::max()
+TEST_F(TimeTest, InfFuture) {
+ EXPECT_EQ(system_clock::time_point::max(),
+ Timespec2Timepoint(gpr_inf_future(GPR_CLOCK_REALTIME)));
+ gpr_timespec from_time_point_max;
+ Timepoint2Timespec(system_clock::time_point::max(), &from_time_point_max);
+ EXPECT_EQ(
+ 0, gpr_time_cmp(gpr_inf_future(GPR_CLOCK_REALTIME), from_time_point_max));
+ // This will cause an overflow
+ Timepoint2Timespec(
+ std::chrono::time_point<system_clock, std::chrono::seconds>::max(),
+ &from_time_point_max);
+ EXPECT_EQ(
+ 0, gpr_time_cmp(gpr_inf_future(GPR_CLOCK_REALTIME), from_time_point_max));
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/libs/grpc/test/cpp/util/ya.make b/contrib/libs/grpc/test/cpp/util/ya.make
new file mode 100644
index 0000000000..f043cc5b14
--- /dev/null
+++ b/contrib/libs/grpc/test/cpp/util/ya.make
@@ -0,0 +1,39 @@
+LIBRARY()
+
+LICENSE(Apache-2.0)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+OWNER(orivej)
+
+PEERDIR(
+ contrib/libs/gflags
+ contrib/libs/protoc
+ contrib/libs/grpc/src/proto/grpc/reflection/v1alpha
+ contrib/restricted/googletest/googlemock
+ contrib/restricted/googletest/googletest
+)
+
+ADDINCL(
+ ${ARCADIA_BUILD_ROOT}/contrib/libs/grpc
+ contrib/libs/grpc
+)
+
+NO_COMPILER_WARNINGS()
+
+SRCS(
+ byte_buffer_proto_helper.cc
+ # grpc_cli_libs:
+ cli_call.cc
+ cli_credentials.cc
+ grpc_tool.cc
+ proto_file_parser.cc
+ service_describer.cc
+ string_ref_helper.cc
+ # grpc++_proto_reflection_desc_db:
+ proto_reflection_descriptor_database.cc
+ # grpc++_test_config:
+ test_config_cc.cc
+)
+
+END()