diff options
author | Yash Tibrewal <yashkt@google.com> | 2018-08-13 10:53:06 -0700 |
---|---|---|
committer | Yash Tibrewal <yashkt@google.com> | 2018-08-13 10:53:06 -0700 |
commit | 556775d7c78125e051c6571d4c528de214024c23 (patch) | |
tree | 77d3e0effdb58b01e9e257a8dcd03a024acedf31 /test | |
parent | 0ec6973b743e8e1f463bdcc8691e1869097c92f0 (diff) | |
parent | ba7ca9742eb7484009b75c268dba7e56b8feaebb (diff) |
Merge master
Diffstat (limited to 'test')
62 files changed, 1970 insertions, 315 deletions
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index bbddee3f14..f224457a55 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -34,8 +34,6 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/channel_trace_proto_helper.h" -// remove me -#include <grpc/support/string_util.h> #include <stdlib.h> #include <string.h> @@ -88,7 +86,7 @@ void AddSimpleTrace(ChannelTrace* tracer) { void ValidateChannelTrace(ChannelTrace* tracer, size_t expected_num_event_logged, size_t max_nodes) { if (!max_nodes) return; - grpc_json* json = tracer->RenderJSON(); + grpc_json* json = tracer->RenderJson(); EXPECT_NE(json, nullptr); char* json_str = grpc_json_dump_to_string(json, 0); grpc_json_destroy(json); @@ -157,7 +155,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); ChannelFixture channel1(GetParam()); RefCountedPtr<ChannelNode> sc1 = - MakeRefCounted<ChannelNode>(channel1.channel(), GetParam()); + MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -175,7 +173,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { ValidateChannelTrace(&tracer, 5, GetParam()); ChannelFixture channel2(GetParam()); RefCountedPtr<ChannelNode> sc2 = - MakeRefCounted<ChannelNode>(channel2.channel(), GetParam()); + MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); @@ -189,8 +187,8 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); - sc1.reset(nullptr); - sc2.reset(nullptr); + sc1.reset(); + sc2.reset(); } // Test a case in which the parent channel has subchannels and the subchannels @@ -204,7 +202,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(&tracer, 2, GetParam()); ChannelFixture channel1(GetParam()); RefCountedPtr<ChannelNode> sc1 = - MakeRefCounted<ChannelNode>(channel1.channel(), GetParam()); + MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -212,7 +210,7 @@ TEST_P(ChannelTracerTest, TestNesting) { AddSimpleTrace(sc1->trace()); ChannelFixture channel2(GetParam()); RefCountedPtr<ChannelNode> conn1 = - MakeRefCounted<ChannelNode>(channel2.channel(), GetParam()); + MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true); // nesting one level deeper. sc1->trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, @@ -225,7 +223,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(conn1->trace(), 1, GetParam()); ChannelFixture channel3(GetParam()); RefCountedPtr<ChannelNode> sc2 = - MakeRefCounted<ChannelNode>(channel3.channel(), GetParam()); + MakeRefCounted<ChannelNode>(channel3.channel(), GetParam(), true); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); @@ -236,9 +234,9 @@ TEST_P(ChannelTracerTest, TestNesting) { grpc_slice_from_static_string("subchannel one inactive"), sc1); AddSimpleTrace(&tracer); ValidateChannelTrace(&tracer, 8, GetParam()); - sc1.reset(nullptr); - sc2.reset(nullptr); - conn1.reset(nullptr); + sc1.reset(); + sc2.reset(); + conn1.reset(); } INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest, diff --git a/test/core/channel/channelz_registry_test.cc b/test/core/channel/channelz_registry_test.cc index 24e50933d7..581e867584 100644 --- a/test/core/channel/channelz_registry_test.cc +++ b/test/core/channel/channelz_registry_test.cc @@ -19,17 +19,20 @@ #include <stdlib.h> #include <string.h> +#include <grpc/grpc.h> #include <gtest/gtest.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/json/json.h" +#include "src/core/lib/surface/channel.h" #include "test/core/util/test_config.h" @@ -37,27 +40,26 @@ #include <string.h> namespace grpc_core { +namespace channelz { namespace testing { -// Tests basic ChannelTrace functionality like construction, adding trace, and -// lookups by uuid. TEST(ChannelzRegistryTest, UuidStartsAboveZeroTest) { - int object_to_register; - intptr_t uuid = ChannelzRegistry::Register(&object_to_register); + ChannelNode* channelz_channel = nullptr; + intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel); EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if " "reserved according to " "https://github.com/grpc/proposal/blob/master/" "A14-channelz.md"; - ChannelzRegistry::Unregister(uuid); + ChannelzRegistry::UnregisterChannelNode(uuid); } TEST(ChannelzRegistryTest, UuidsAreIncreasing) { - int object_to_register; + ChannelNode* channelz_channel = nullptr; std::vector<intptr_t> uuids; uuids.reserve(10); for (int i = 0; i < 10; ++i) { // reregister the same object. It's ok since we are just testing uuids - uuids.push_back(ChannelzRegistry::Register(&object_to_register)); + uuids.push_back(ChannelzRegistry::RegisterChannelNode(channelz_channel)); } for (size_t i = 1; i < uuids.size(); ++i) { EXPECT_LT(uuids[i - 1], uuids[i]) << "Uuids must always be increasing"; @@ -65,60 +67,36 @@ TEST(ChannelzRegistryTest, UuidsAreIncreasing) { } TEST(ChannelzRegistryTest, RegisterGetTest) { - int object_to_register = 42; - intptr_t uuid = ChannelzRegistry::Register(&object_to_register); - int* retrieved = ChannelzRegistry::Get<int>(uuid); - EXPECT_EQ(&object_to_register, retrieved); -} - -TEST(ChannelzRegistryTest, MultipleTypeTest) { - int int_to_register = 42; - intptr_t int_uuid = ChannelzRegistry::Register(&int_to_register); - std::string str_to_register = "hello world"; - intptr_t str_uuid = ChannelzRegistry::Register(&str_to_register); - int* retrieved_int = ChannelzRegistry::Get<int>(int_uuid); - std::string* retrieved_str = ChannelzRegistry::Get<std::string>(str_uuid); - EXPECT_EQ(&int_to_register, retrieved_int); - EXPECT_EQ(&str_to_register, retrieved_str); + // we hackily jam an intptr_t into this pointer to check for equality later + ChannelNode* channelz_channel = (ChannelNode*)42; + intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel); + ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid); + EXPECT_EQ(channelz_channel, retrieved); } TEST(ChannelzRegistryTest, RegisterManyItems) { - int object_to_register = 42; + // we hackily jam an intptr_t into this pointer to check for equality later + ChannelNode* channelz_channel = (ChannelNode*)42; for (int i = 0; i < 100; i++) { - intptr_t uuid = ChannelzRegistry::Register(&object_to_register); - int* retrieved = ChannelzRegistry::Get<int>(uuid); - EXPECT_EQ(&object_to_register, retrieved); + intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel); + ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid); + EXPECT_EQ(channelz_channel, retrieved); } } -namespace { -class Foo { - public: - int bar; -}; -} // namespace - -TEST(ChannelzRegistryTest, CustomObjectTest) { - Foo* foo = New<Foo>(); - foo->bar = 1024; - intptr_t uuid = ChannelzRegistry::Register(foo); - Foo* retrieved = ChannelzRegistry::Get<Foo>(uuid); - EXPECT_EQ(foo, retrieved); - Delete(foo); -} - TEST(ChannelzRegistryTest, NullIfNotPresentTest) { - int object_to_register = 42; - intptr_t uuid = ChannelzRegistry::Register(&object_to_register); + // we hackily jam an intptr_t into this pointer to check for equality later + ChannelNode* channelz_channel = (ChannelNode*)42; + intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel); // try to pull out a uuid that does not exist. - int* nonexistant = ChannelzRegistry::Get<int>(uuid + 1); + ChannelNode* nonexistant = ChannelzRegistry::GetChannelNode(uuid + 1); EXPECT_EQ(nonexistant, nullptr); - int* retrieved = ChannelzRegistry::Get<int>(uuid); - EXPECT_EQ(object_to_register, *retrieved); - EXPECT_EQ(&object_to_register, retrieved); + ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid); + EXPECT_EQ(channelz_channel, retrieved); } } // namespace testing +} // namespace channelz } // namespace grpc_core int main(int argc, char** argv) { diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 058eea914c..ad5f86d934 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -67,17 +67,50 @@ grpc_json* GetJsonChild(grpc_json* parent, const char* key) { return nullptr; } +void ValidateJsonArraySize(grpc_json* json, const char* key, + size_t expected_size) { + grpc_json* arr = GetJsonChild(json, key); + if (expected_size == 0) { + ASSERT_EQ(arr, nullptr); + return; + } + ASSERT_NE(arr, nullptr); + ASSERT_EQ(arr->type, GRPC_JSON_ARRAY); + size_t count = 0; + for (grpc_json* child = arr->child; child != nullptr; child = child->next) { + ++count; + } + EXPECT_EQ(count, expected_size); +} + +void ValidateGetTopChannels(size_t expected_channels) { + char* json_str = ChannelzRegistry::GetTopChannels(0); + grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str); + grpc_json* parsed_json = grpc_json_parse_string(json_str); + // This check will naturally have to change when we support pagination. + // tracked: https://github.com/grpc/grpc/issues/16019. + ValidateJsonArraySize(parsed_json, "channel", expected_channels); + grpc_json* end = GetJsonChild(parsed_json, "end"); + ASSERT_NE(end, nullptr); + EXPECT_EQ(end->type, GRPC_JSON_TRUE); + grpc_json_destroy(parsed_json); + gpr_free(json_str); + // also check that the core API formats this correctly + char* core_api_json_str = grpc_channelz_get_top_channels(0); + grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( + core_api_json_str); + gpr_free(core_api_json_str); +} + class ChannelFixture { public: - ChannelFixture(int max_trace_nodes) { + ChannelFixture(int max_trace_nodes = 0) { grpc_arg client_a[2]; - client_a[0].type = GRPC_ARG_INTEGER; - client_a[0].key = - const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - client_a[0].value.integer = max_trace_nodes; - client_a[1].type = GRPC_ARG_INTEGER; - client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ); - client_a[1].value.integer = true; + client_a[0] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE), + max_trace_nodes); + client_a[1] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; channel_ = grpc_insecure_channel_create("fake_target", &client_args, nullptr); @@ -99,6 +132,10 @@ struct validate_channel_data_args { void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) { grpc_json* gotten_json = GetJsonChild(json, key); + if (expect == 0) { + ASSERT_EQ(gotten_json, nullptr); + return; + } ASSERT_NE(gotten_json, nullptr); int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0); EXPECT_EQ(gotten_number, expect); @@ -115,10 +152,15 @@ void ValidateCounters(char* json_str, validate_channel_data_args args) { } void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) { - char* json_str = channel->RenderJSON(); + char* json_str = channel->RenderJsonString(); grpc::testing::ValidateChannelProtoJsonTranslation(json_str); ValidateCounters(json_str, args); gpr_free(json_str); + // also check that the core API formats this the correct way + char* core_api_json_str = grpc_channelz_get_channel(channel->channel_uuid()); + grpc::testing::ValidateGetChannelResponseProtoJsonTranslation( + core_api_json_str); + gpr_free(core_api_json_str); } grpc_millis GetLastCallStartedMillis(ChannelNode* channel) { @@ -141,9 +183,7 @@ TEST_P(ChannelzChannelTest, BasicChannel) { ChannelFixture channel(GetParam()); ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel.channel()); - char* json_str = channelz_channel->RenderJSON(); - ValidateCounters(json_str, {0, 0, 0}); - gpr_free(json_str); + ValidateChannel(channelz_channel, {0, 0, 0}); } TEST(ChannelzChannelTest, ChannelzDisabled) { @@ -199,6 +239,42 @@ TEST_P(ChannelzChannelTest, LastCallStartedMillis) { EXPECT_NE(millis1, millis4); } +TEST(ChannelzGetTopChannelsTest, BasicTest) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channel; + ValidateGetTopChannels(1); +} + +TEST(ChannelzGetTopChannelsTest, NoChannelsTest) { + grpc_core::ExecCtx exec_ctx; + ValidateGetTopChannels(0); +} + +TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channels[10]; + (void)channels; // suppress unused variable error + ValidateGetTopChannels(10); +} + +TEST(ChannelzGetTopChannelsTest, InternalChannelTest) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channels[10]; + (void)channels; // suppress unused variable error + // create an internal channel + grpc_arg client_a[2]; + client_a[0] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true); + client_a[1] = grpc_channel_arg_integer_create( + const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); + grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; + grpc_channel* internal_channel = + grpc_insecure_channel_create("fake_target", &client_args, nullptr); + // The internal channel should not be returned from the request + ValidateGetTopChannels(10); + grpc_channel_destroy(internal_channel); +} + INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest, ::testing::Values(0, 1, 2, 6, 10, 15)); diff --git a/test/core/channel/minimal_stack_is_minimal_test.cc b/test/core/channel/minimal_stack_is_minimal_test.cc index e5953acedc..5b651ed39b 100644 --- a/test/core/channel/minimal_stack_is_minimal_test.cc +++ b/test/core/channel/minimal_stack_is_minimal_test.cc @@ -85,21 +85,21 @@ int main(int argc, char** argv) { // tests with a default stack errors += - CHECK_STACK("unknown", nullptr, GRPC_CLIENT_DIRECT_CHANNEL, "authority", - "message_size", "deadline", "connected", NULL); + CHECK_STACK("unknown", nullptr, GRPC_CLIENT_DIRECT_CHANNEL, "deadline", + "authority", "message_size", "connected", NULL); errors += CHECK_STACK("unknown", nullptr, GRPC_CLIENT_SUBCHANNEL, "authority", "message_size", "connected", NULL); errors += CHECK_STACK("unknown", nullptr, GRPC_SERVER_CHANNEL, "server", - "message_size", "deadline", "connected", NULL); + "deadline", "message_size", "connected", NULL); errors += CHECK_STACK("chttp2", nullptr, GRPC_CLIENT_DIRECT_CHANNEL, - "authority", "message_size", "deadline", "http-client", - "message_compress", "connected", NULL); + "deadline", "authority", "message_size", + "message_compress", "http-client", "connected", NULL); errors += CHECK_STACK("chttp2", nullptr, GRPC_CLIENT_SUBCHANNEL, "authority", - "message_size", "http-client", "message_compress", + "message_size", "message_compress", "http-client", "connected", NULL); errors += CHECK_STACK("chttp2", nullptr, GRPC_SERVER_CHANNEL, "server", - "message_size", "deadline", "http-server", - "message_compress", "connected", NULL); + "deadline", "message_size", "message_compress", + "http-server", "connected", NULL); errors += CHECK_STACK(nullptr, nullptr, GRPC_CLIENT_CHANNEL, "client-channel", NULL); diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index eb052119ca..533703a2be 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -209,27 +209,27 @@ static void test_channelz(grpc_end2end_test_config config) { grpc_channel_get_channelz_node(f.client); GPR_ASSERT(channelz_channel != nullptr); - char* json = channelz_channel->RenderJSON(); + char* json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); + // nothing is present yet + GPR_ASSERT(nullptr == strstr(json, "\"callsStarted\"")); + GPR_ASSERT(nullptr == strstr(json, "\"callsFailed\"")); + GPR_ASSERT(nullptr == strstr(json, "\"callsSucceeded\"")); gpr_free(json); // one successful request run_one_request(config, f, true); - json = channelz_channel->RenderJSON(); + json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); gpr_free(json); // one failed request run_one_request(config, f, false); - json = channelz_channel->RenderJSON(); + json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); @@ -264,7 +264,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_channel_get_channelz_node(f.client); GPR_ASSERT(channelz_channel != nullptr); - char* json = channelz_channel->RenderJSON(); + char* json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); diff --git a/test/core/end2end/tests/filter_call_init_fails.cc b/test/core/end2end/tests/filter_call_init_fails.cc index ab96879fe4..07e1421446 100644 --- a/test/core/end2end/tests/filter_call_init_fails.cc +++ b/test/core/end2end/tests/filter_call_init_fails.cc @@ -438,7 +438,6 @@ static bool maybe_add_server_channel_filter(grpc_channel_stack_builder* builder, // must be the last one. So we add it right before the last one. grpc_channel_stack_builder_iterator* it = grpc_channel_stack_builder_create_iterator_at_last(builder); - GPR_ASSERT(grpc_channel_stack_builder_move_prev(it)); const bool retval = grpc_channel_stack_builder_add_filter_before( it, &test_filter, nullptr, nullptr); grpc_channel_stack_builder_iterator_destroy(it); @@ -457,7 +456,6 @@ static bool maybe_add_client_channel_filter(grpc_channel_stack_builder* builder, // must be the last one. So we add it right before the last one. grpc_channel_stack_builder_iterator* it = grpc_channel_stack_builder_create_iterator_at_last(builder); - GPR_ASSERT(grpc_channel_stack_builder_move_prev(it)); const bool retval = grpc_channel_stack_builder_add_filter_before( it, &test_filter, nullptr, nullptr); grpc_channel_stack_builder_iterator_destroy(it); @@ -476,7 +474,6 @@ static bool maybe_add_client_subchannel_filter( // must be the last one. So we add it right before the last one. grpc_channel_stack_builder_iterator* it = grpc_channel_stack_builder_create_iterator_at_last(builder); - GPR_ASSERT(grpc_channel_stack_builder_move_prev(it)); const bool retval = grpc_channel_stack_builder_add_filter_before( it, &test_filter, nullptr, nullptr); grpc_channel_stack_builder_iterator_destroy(it); @@ -487,13 +484,17 @@ static bool maybe_add_client_subchannel_filter( } static void init_plugin(void) { - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, + GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_server_channel_filter, nullptr); - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, + GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_client_channel_filter, nullptr); - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, + GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_client_subchannel_filter, nullptr); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, + GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_client_channel_filter, nullptr); } diff --git a/test/core/end2end/tests/filter_causes_close.cc b/test/core/end2end/tests/filter_causes_close.cc index a7f4268803..891c1b8c1f 100644 --- a/test/core/end2end/tests/filter_causes_close.cc +++ b/test/core/end2end/tests/filter_causes_close.cc @@ -261,8 +261,9 @@ static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) { } static void init_plugin(void) { - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, 0, maybe_add_filter, - nullptr); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, + GRPC_CHANNEL_INIT_PRIORITY_HIGH, + maybe_add_filter, nullptr); } static void destroy_plugin(void) {} diff --git a/test/core/end2end/tests/filter_latency.cc b/test/core/end2end/tests/filter_latency.cc index a89db7b094..02a4d07927 100644 --- a/test/core/end2end/tests/filter_latency.cc +++ b/test/core/end2end/tests/filter_latency.cc @@ -314,7 +314,6 @@ static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) { // must be the last one. So we add it right before the last one. grpc_channel_stack_builder_iterator* it = grpc_channel_stack_builder_create_iterator_at_last(builder); - GPR_ASSERT(grpc_channel_stack_builder_move_prev(it)); const bool retval = grpc_channel_stack_builder_add_filter_before( it, filter, nullptr, nullptr); grpc_channel_stack_builder_iterator_destroy(it); @@ -326,15 +325,15 @@ static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) { static void init_plugin(void) { gpr_mu_init(&g_mu); - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_client_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_client_filter); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_server_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_filter, + (void*)&test_client_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, + maybe_add_filter, (void*)&test_client_filter); + grpc_channel_init_register_stage( + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_filter, + (void*)&test_server_filter); } static void destroy_plugin(void) { gpr_mu_destroy(&g_mu); } diff --git a/test/core/end2end/tests/filter_status_code.cc b/test/core/end2end/tests/filter_status_code.cc index ba3cbfa6d1..6ed1de15c6 100644 --- a/test/core/end2end/tests/filter_status_code.cc +++ b/test/core/end2end/tests/filter_status_code.cc @@ -333,7 +333,6 @@ static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) { // So we add it right before the last one. grpc_channel_stack_builder_iterator* it = grpc_channel_stack_builder_create_iterator_at_last(builder); - GPR_ASSERT(grpc_channel_stack_builder_move_prev(it)); const bool retval = grpc_channel_stack_builder_add_filter_before( it, filter, nullptr, nullptr); grpc_channel_stack_builder_iterator_destroy(it); @@ -350,15 +349,15 @@ static void init_plugin(void) { g_client_code_recv = false; g_server_code_recv = false; - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_client_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_client_filter); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_add_filter, - (void*)&test_server_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_filter, + (void*)&test_client_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, + maybe_add_filter, (void*)&test_client_filter); + grpc_channel_init_register_stage( + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_MAX, maybe_add_filter, + (void*)&test_server_filter); } static void destroy_plugin(void) { diff --git a/test/core/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc index 41f4338f8a..e9d1eb2c76 100644 --- a/test/core/gprpp/inlined_vector_test.cc +++ b/test/core/gprpp/inlined_vector_test.cc @@ -17,20 +17,32 @@ */ #include "src/core/lib/gprpp/inlined_vector.h" +#include <grpc/support/log.h> #include <gtest/gtest.h> #include "src/core/lib/gprpp/memory.h" #include "test/core/util/test_config.h" namespace grpc_core { namespace testing { +namespace { + +template <typename Vector> +static void FillVector(Vector* v, int len, int start = 0) { + for (int i = 0; i < len; i++) { + v->push_back(i + start); + EXPECT_EQ(i + 1UL, v->size()); + } + EXPECT_EQ(static_cast<size_t>(len), v->size()); + EXPECT_LE(static_cast<size_t>(len), v->capacity()); +} + +} // namespace TEST(InlinedVectorTest, CreateAndIterate) { const int kNumElements = 9; InlinedVector<int, 2> v; EXPECT_TRUE(v.empty()); - for (int i = 0; i < kNumElements; ++i) { - v.push_back(i); - } + FillVector(&v, kNumElements); EXPECT_EQ(static_cast<size_t>(kNumElements), v.size()); EXPECT_FALSE(v.empty()); for (int i = 0; i < kNumElements; ++i) { @@ -42,9 +54,7 @@ TEST(InlinedVectorTest, CreateAndIterate) { TEST(InlinedVectorTest, ValuesAreInlined) { const int kNumElements = 5; InlinedVector<int, 10> v; - for (int i = 0; i < kNumElements; ++i) { - v.push_back(i); - } + FillVector(&v, kNumElements); EXPECT_EQ(static_cast<size_t>(kNumElements), v.size()); for (int i = 0; i < kNumElements; ++i) { EXPECT_EQ(i, v[i]); @@ -71,19 +81,13 @@ TEST(InlinedVectorTest, ClearAndRepopulate) { const int kNumElements = 10; InlinedVector<int, 5> v; EXPECT_EQ(0UL, v.size()); - for (int i = 0; i < kNumElements; ++i) { - v.push_back(i); - EXPECT_EQ(i + 1UL, v.size()); - } + FillVector(&v, kNumElements); for (int i = 0; i < kNumElements; ++i) { EXPECT_EQ(i, v[i]); } v.clear(); EXPECT_EQ(0UL, v.size()); - for (int i = 0; i < kNumElements; ++i) { - v.push_back(kNumElements + i); - EXPECT_EQ(i + 1UL, v.size()); - } + FillVector(&v, kNumElements, kNumElements); for (int i = 0; i < kNumElements; ++i) { EXPECT_EQ(kNumElements + i, v[i]); } @@ -93,10 +97,7 @@ TEST(InlinedVectorTest, ConstIndexOperator) { constexpr int kNumElements = 10; InlinedVector<int, 5> v; EXPECT_EQ(0UL, v.size()); - for (int i = 0; i < kNumElements; ++i) { - v.push_back(i); - EXPECT_EQ(i + 1UL, v.size()); - } + FillVector(&v, kNumElements); // The following lambda function is exceptionally allowed to use an anonymous // capture due to the erroneous behavior of the MSVC compiler, that refuses to // capture the kNumElements constexpr, something allowed by the standard. @@ -108,6 +109,161 @@ TEST(InlinedVectorTest, ConstIndexOperator) { const_func(v); } +// the following constants and typedefs are used for copy/move +// construction/assignment +const size_t kInlinedLength = 8; +typedef InlinedVector<int, kInlinedLength> IntVec8; +const size_t kInlinedFillSize = kInlinedLength - 1; +const size_t kAllocatedFillSize = kInlinedLength + 1; + +TEST(InlinedVectorTest, CopyConstructerInlined) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 copy_constructed(original); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_constructed[i]); + } +} + +TEST(InlinedVectorTest, CopyConstructerAllocated) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 copy_constructed(original); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_constructed[i]); + } +} + +TEST(InlinedVectorTest, CopyAssignementInlinedInlined) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 copy_assigned; + FillVector(©_assigned, kInlinedFillSize, 99); + copy_assigned = original; + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_assigned[i]); + } +} + +TEST(InlinedVectorTest, CopyAssignementInlinedAllocated) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 copy_assigned; + FillVector(©_assigned, kAllocatedFillSize, 99); + copy_assigned = original; + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_assigned[i]); + } +} + +TEST(InlinedVectorTest, CopyAssignementAllocatedInlined) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 copy_assigned; + FillVector(©_assigned, kInlinedFillSize, 99); + copy_assigned = original; + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_assigned[i]); + } +} + +TEST(InlinedVectorTest, CopyAssignementAllocatedAllocated) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 copy_assigned; + FillVector(©_assigned, kAllocatedFillSize, 99); + copy_assigned = original; + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], copy_assigned[i]); + } +} + +TEST(InlinedVectorTest, MoveConstructorInlined) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 tmp(original); + auto* old_data = tmp.data(); + IntVec8 move_constructed(std::move(tmp)); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_constructed[i]); + } + // original data was inlined so it should have been copied, not moved. + EXPECT_NE(move_constructed.data(), old_data); +} + +TEST(InlinedVectorTest, MoveConstructorAllocated) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 tmp(original); + auto* old_data = tmp.data(); + IntVec8 move_constructed(std::move(tmp)); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_constructed[i]); + } + // original data was allocated, so it should been moved, not copied + EXPECT_EQ(move_constructed.data(), old_data); +} + +TEST(InlinedVectorTest, MoveAssignmentInlinedInlined) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 move_assigned; + FillVector(&move_assigned, kInlinedFillSize, 99); // Add dummy elements + IntVec8 tmp(original); + auto* old_data = tmp.data(); + move_assigned = std::move(tmp); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_assigned[i]); + } + // original data was inlined so it should have been copied, not moved. + EXPECT_NE(move_assigned.data(), old_data); +} + +TEST(InlinedVectorTest, MoveAssignmentInlinedAllocated) { + IntVec8 original; + FillVector(&original, kInlinedFillSize); + IntVec8 move_assigned; + FillVector(&move_assigned, kAllocatedFillSize, 99); // Add dummy elements + IntVec8 tmp(original); + auto* old_data = tmp.data(); + move_assigned = std::move(tmp); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_assigned[i]); + } + // original data was inlined so it should have been copied, not moved. + EXPECT_NE(move_assigned.data(), old_data); +} + +TEST(InlinedVectorTest, MoveAssignmentAllocatedInlined) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 move_assigned; + FillVector(&move_assigned, kInlinedFillSize, 99); // Add dummy elements + IntVec8 tmp(original); + auto* old_data = tmp.data(); + move_assigned = std::move(tmp); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_assigned[i]); + } + // original data was allocated so it should have been moved, not copied. + EXPECT_EQ(move_assigned.data(), old_data); +} + +TEST(InlinedVectorTest, MoveAssignmentAllocatedAllocated) { + IntVec8 original; + FillVector(&original, kAllocatedFillSize); + IntVec8 move_assigned; + FillVector(&move_assigned, kAllocatedFillSize, 99); // Add dummy elements + IntVec8 tmp(original); + auto* old_data = tmp.data(); + move_assigned = std::move(tmp); + for (size_t i = 0; i < original.size(); ++i) { + EXPECT_EQ(original[i], move_assigned[i]); + } + // original data was allocated so it should have been moved, not copied. + EXPECT_EQ(move_assigned.data(), old_data); +} + } // namespace testing } // namespace grpc_core diff --git a/test/core/gprpp/ref_counted_ptr_test.cc b/test/core/gprpp/ref_counted_ptr_test.cc index aa30b72282..463b5e8966 100644 --- a/test/core/gprpp/ref_counted_ptr_test.cc +++ b/test/core/gprpp/ref_counted_ptr_test.cc @@ -127,7 +127,7 @@ TEST(RefCountedPtr, ResetFromNonNullToNull) { TEST(RefCountedPtr, ResetFromNullToNull) { RefCountedPtr<Foo> foo; EXPECT_EQ(nullptr, foo.get()); - foo.reset(nullptr); + foo.reset(); EXPECT_EQ(nullptr, foo.get()); } @@ -175,6 +175,67 @@ TEST(RefCountedPtr, RefCountedWithTracing) { foo->Unref(DEBUG_LOCATION, "foo"); } +class BaseClass : public RefCounted<BaseClass> { + public: + BaseClass() {} +}; + +class Subclass : public BaseClass { + public: + Subclass() {} +}; + +TEST(RefCountedPtr, ConstructFromSubclass) { + RefCountedPtr<BaseClass> p(New<Subclass>()); +} + +TEST(RefCountedPtr, CopyAssignFromSubclass) { + RefCountedPtr<BaseClass> b; + EXPECT_EQ(nullptr, b.get()); + RefCountedPtr<Subclass> s = MakeRefCounted<Subclass>(); + b = s; + EXPECT_NE(nullptr, b.get()); +} + +TEST(RefCountedPtr, MoveAssignFromSubclass) { + RefCountedPtr<BaseClass> b; + EXPECT_EQ(nullptr, b.get()); + RefCountedPtr<Subclass> s = MakeRefCounted<Subclass>(); + b = std::move(s); + EXPECT_NE(nullptr, b.get()); +} + +TEST(RefCountedPtr, ResetFromSubclass) { + RefCountedPtr<BaseClass> b; + EXPECT_EQ(nullptr, b.get()); + b.reset(New<Subclass>()); + EXPECT_NE(nullptr, b.get()); +} + +TEST(RefCountedPtr, EqualityWithSubclass) { + Subclass* s = New<Subclass>(); + RefCountedPtr<BaseClass> b(s); + EXPECT_EQ(b, s); +} + +void FunctionTakingBaseClass(RefCountedPtr<BaseClass> p) { + p.reset(); // To appease clang-tidy. +} + +TEST(RefCountedPtr, CanPassSubclassToFunctionExpectingBaseClass) { + RefCountedPtr<Subclass> p = MakeRefCounted<Subclass>(); + FunctionTakingBaseClass(p); +} + +void FunctionTakingSubclass(RefCountedPtr<Subclass> p) { + p.reset(); // To appease clang-tidy. +} + +TEST(RefCountedPtr, CanPassSubclassToFunctionExpectingSubclass) { + RefCountedPtr<Subclass> p = MakeRefCounted<Subclass>(); + FunctionTakingSubclass(p); +} + } // namespace } // namespace testing } // namespace grpc_core diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD index a3d2ba2fc0..675d9e6278 100644 --- a/test/core/iomgr/BUILD +++ b/test/core/iomgr/BUILD @@ -125,6 +125,19 @@ grpc_cc_test( ) grpc_cc_test( + name = "grpc_ipv6_loopback_available_test", + srcs = ["grpc_ipv6_loopback_available_test.cc"], + language = "C++", + deps = [ + "//:gpr", + "//:grpc", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + ], +) + + +grpc_cc_test( name = "load_file_test", srcs = ["load_file_test.cc"], language = "C++", diff --git a/test/core/iomgr/grpc_ipv6_loopback_available_test.cc b/test/core/iomgr/grpc_ipv6_loopback_available_test.cc new file mode 100644 index 0000000000..329aa9a851 --- /dev/null +++ b/test/core/iomgr/grpc_ipv6_loopback_available_test.cc @@ -0,0 +1,48 @@ +/* + * + * 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 "src/core/lib/iomgr/port.h" + +// grpc_ipv6_loopback_available isn't currently available on UV. +#ifndef GRPC_UV + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include "test/core/util/test_config.h" + +#ifdef GPR_WINDOWS +#include "src/core/lib/iomgr/socket_windows.h" +#else +#include "src/core/lib/iomgr/socket_utils_posix.h" +#endif + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + grpc_init(); + // This test assumes that the ipv6 loopback is available + // in all environments in which grpc tests run in. + GPR_ASSERT(grpc_ipv6_loopback_available()); + grpc_shutdown(); + return 0; +} + +#else + +int main(int argc, char** argv) { return 0; } + +#endif /* GRPC_UV */ diff --git a/test/core/security/BUILD b/test/core/security/BUILD index 12aa84d93b..b7de955cdb 100644 --- a/test/core/security/BUILD +++ b/test/core/security/BUILD @@ -129,6 +129,27 @@ grpc_cc_test( ) grpc_cc_test( + name = "linux_system_roots_test", + srcs = ["linux_system_roots_test.cc"], + data = [ + "//test/core/security/etc:bundle.pem", + "//test/core/security/etc:test_roots/cert1.pem", + "//test/core/security/etc:test_roots/cert2.pem", + "//test/core/security/etc:test_roots/cert3.pem", + ], + language = "C++", + external_deps = [ + "gtest", + ], + deps = [ + "//:gpr", + "//:grpc", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + ], +) + +grpc_cc_test( name = "ssl_credentials_test", srcs = ["ssl_credentials_test.cc"], language = "C++", @@ -219,9 +240,9 @@ grpc_cc_test( deps = [ "//:gpr", "//:grpc", - "//:grpc_base_c", + "//:grpc_base_c", "//:grpc_secure", - "//:tsi", + "//:tsi", "//:tsi_interface", "//test/core/util:gpr_test_util", ], diff --git a/test/core/security/check_gcp_environment_linux_test.cc b/test/core/security/check_gcp_environment_linux_test.cc index 3acd5b6ae4..b01471abd3 100644 --- a/test/core/security/check_gcp_environment_linux_test.cc +++ b/test/core/security/check_gcp_environment_linux_test.cc @@ -69,6 +69,7 @@ static void test_gcp_environment_check_failure() { GPR_ASSERT(!check_bios_data_linux_test("Amazon")); GPR_ASSERT(!check_bios_data_linux_test("Google-Chrome\t\t")); GPR_ASSERT(!check_bios_data_linux_test("Amazon")); + GPR_ASSERT(!check_bios_data_linux_test("\n")); } int main(int argc, char** argv) { diff --git a/test/core/security/etc/BUILD b/test/core/security/etc/BUILD new file mode 100644 index 0000000000..2c6ab64a3b --- /dev/null +++ b/test/core/security/etc/BUILD @@ -0,0 +1,22 @@ +# 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. + +licenses(["notice"]) # Apache v2 + +exports_files([ + "bundle.pem", + "test_roots/cert1.pem", + "test_roots/cert2.pem", + "test_roots/cert3.pem", +]) diff --git a/test/core/security/etc/README b/test/core/security/etc/README new file mode 100644 index 0000000000..6ba4382586 --- /dev/null +++ b/test/core/security/etc/README @@ -0,0 +1,2 @@ +These files are manual copies of a pem cert from the /etc/ssl/certs/ directory. +They serve only as dummy certificate test files. diff --git a/test/core/security/etc/bundle.pem b/test/core/security/etc/bundle.pem new file mode 100644 index 0000000000..07d7672f83 --- /dev/null +++ b/test/core/security/etc/bundle.pem @@ -0,0 +1,63 @@ +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/test/core/security/etc/test_roots/cert1.pem b/test/core/security/etc/test_roots/cert1.pem new file mode 100644 index 0000000000..988cc68aac --- /dev/null +++ b/test/core/security/etc/test_roots/cert1.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/test/core/security/etc/test_roots/cert2.pem b/test/core/security/etc/test_roots/cert2.pem new file mode 100644 index 0000000000..988cc68aac --- /dev/null +++ b/test/core/security/etc/test_roots/cert2.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/test/core/security/etc/test_roots/cert3.pem b/test/core/security/etc/test_roots/cert3.pem new file mode 100644 index 0000000000..988cc68aac --- /dev/null +++ b/test/core/security/etc/test_roots/cert3.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- diff --git a/test/core/security/linux_system_roots_test.cc b/test/core/security/linux_system_roots_test.cc new file mode 100644 index 0000000000..fce9c8dcc5 --- /dev/null +++ b/test/core/security/linux_system_roots_test.cc @@ -0,0 +1,104 @@ +/* + * + * 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 <stdio.h> + +#ifdef GPR_LINUX +#include <grpc/grpc_security.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <string.h> +#include <sys/param.h> + +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gpr/tmpfile.h" +#include "src/core/lib/iomgr/load_file.h" +#include "src/core/lib/security/context/security_context.h" +#include "src/core/lib/security/security_connector/load_system_roots.h" +#include "src/core/lib/security/security_connector/load_system_roots_linux.h" +#include "src/core/lib/security/security_connector/security_connector.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security.h" +#include "test/core/util/test_config.h" + +#include "gtest/gtest.h" + +#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR +#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS" +#endif + +namespace grpc { +namespace { + +TEST(AbsoluteFilePathTest, ConcatenatesCorrectly) { + const char* directory = "nonexistent/test/directory"; + const char* filename = "doesnotexist.txt"; + char result_path[MAXPATHLEN]; + grpc_core::GetAbsoluteFilePath(directory, filename, result_path); + EXPECT_STREQ(result_path, "nonexistent/test/directory/doesnotexist.txt"); +} + +TEST(CreateRootCertsBundleTest, ReturnsEmpty) { + // Test that CreateRootCertsBundle returns an empty slice for null or + // nonexistent cert directories. + grpc_slice result_slice = grpc_core::CreateRootCertsBundle(nullptr); + EXPECT_TRUE(GRPC_SLICE_IS_EMPTY(result_slice)); + grpc_slice_unref(result_slice); + result_slice = grpc_core::CreateRootCertsBundle("does/not/exist"); + EXPECT_TRUE(GRPC_SLICE_IS_EMPTY(result_slice)); + grpc_slice_unref(result_slice); +} + +TEST(CreateRootCertsBundleTest, BundlesCorrectly) { + gpr_setenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR, "true"); + // Test that CreateRootCertsBundle returns a correct slice. + grpc_slice roots_bundle = grpc_empty_slice(); + GRPC_LOG_IF_ERROR( + "load_file", + grpc_load_file("test/core/security/etc/bundle.pem", 1, &roots_bundle)); + // result_slice should have the same content as roots_bundle. + grpc_slice result_slice = + grpc_core::CreateRootCertsBundle("test/core/security/etc/test_roots"); + char* result_str = grpc_slice_to_c_string(result_slice); + char* bundle_str = grpc_slice_to_c_string(roots_bundle); + EXPECT_STREQ(result_str, bundle_str); + // Clean up. + unsetenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR); + gpr_free(result_str); + gpr_free(bundle_str); + grpc_slice_unref(roots_bundle); + grpc_slice_unref(result_slice); +} + +} // namespace +} // namespace grpc + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#else +int main() { + printf("*** WARNING: this test is only supported on Linux systems ***\n"); + return 0; +} +#endif // GPR_LINUX diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc index e4c3ace6b4..82d77eef8b 100644 --- a/test/core/security/security_connector_test.cc +++ b/test/core/security/security_connector_test.cc @@ -363,7 +363,7 @@ static void test_ipv6_address_san(void) { namespace grpc_core { namespace { -class TestDefafaultSllRootStore : public DefaultSslRootStore { +class TestDefaultSslRootStore : public DefaultSslRootStore { public: static grpc_slice ComputePemRootCertsForTesting() { return ComputePemRootCerts(); @@ -389,7 +389,7 @@ static void test_default_ssl_roots(void) { gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); grpc_set_ssl_roots_override_callback(override_roots_success); grpc_slice roots = - grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); + grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); char* roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); @@ -398,7 +398,7 @@ static void test_default_ssl_roots(void) { /* Now let's set the env var: We should get the contents pointed value instead. */ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path); - roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); + roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0); @@ -407,7 +407,7 @@ static void test_default_ssl_roots(void) { /* Now reset the env var. We should fall back to the value overridden using the api. */ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); - roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); + roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); @@ -416,10 +416,10 @@ static void test_default_ssl_roots(void) { /* Now setup a permanent failure for the overridden roots and we should get an empty slice. */ grpc_set_ssl_roots_override_callback(override_roots_permanent_failure); - roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); + roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots)); const tsi_ssl_root_certs_store* root_store = - grpc_core::TestDefafaultSllRootStore::GetRootStore(); + grpc_core::TestDefaultSslRootStore::GetRootStore(); GPR_ASSERT(root_store == nullptr); /* Cleanup. */ diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 9a79b468dd..7b3e875cf0 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -104,6 +104,7 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_census_call_get_context); printf("%lx", (unsigned long) grpc_channel_get_target); printf("%lx", (unsigned long) grpc_channel_get_info); + printf("%lx", (unsigned long) grpc_channel_reset_connect_backoff); printf("%lx", (unsigned long) grpc_insecure_channel_create); printf("%lx", (unsigned long) grpc_lame_client_channel_create); printf("%lx", (unsigned long) grpc_channel_destroy); @@ -131,6 +132,8 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_resource_quota_unref); printf("%lx", (unsigned long) grpc_resource_quota_resize); printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable); + printf("%lx", (unsigned long) grpc_channelz_get_top_channels); + printf("%lx", (unsigned long) grpc_channelz_get_channel); printf("%lx", (unsigned long) grpc_auth_property_iterator_next); printf("%lx", (unsigned long) grpc_auth_context_property_iterator); printf("%lx", (unsigned long) grpc_auth_context_peer_identity); diff --git a/test/cpp/common/channel_filter_test.cc b/test/cpp/common/channel_filter_test.cc index 7bdd53f9e7..9b603ca5b4 100644 --- a/test/cpp/common/channel_filter_test.cc +++ b/test/cpp/common/channel_filter_test.cc @@ -50,7 +50,8 @@ class MyCallData : public CallData { // C-core, we don't accidentally break the C++ filter API. TEST(ChannelFilterTest, RegisterChannelFilter) { grpc::RegisterChannelFilter<MyChannelData, MyCallData>( - "myfilter", GRPC_CLIENT_CHANNEL, INT_MAX, nullptr); + "myfilter", GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_LOW, true, + nullptr); } // TODO(roth): When we have time, add tests for all methods of the diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index 95bb7ed229..75dec56a60 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -120,6 +120,27 @@ grpc_cc_library( ) grpc_cc_test( + name = "channelz_service_test", + srcs = ["channelz_service_test.cc"], + external_deps = [ + "gtest", + ], + deps = [ + ":test_service_impl", + "//:gpr", + "//:grpc", + "//:grpc++", + "//:grpcpp_channelz", + "//src/proto/grpc/channelz:channelz_proto", + "//src/proto/grpc/testing:echo_messages_proto", + "//src/proto/grpc/testing:echo_proto", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", + ], +) + +grpc_cc_test( name = "server_early_return_test", srcs = ["server_early_return_test.cc"], external_deps = [ diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 3d31c9d810..c9246f0806 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -1709,7 +1709,7 @@ TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelAfter) { } std::vector<TestScenario> CreateTestScenarios(bool test_secure, - int test_big_limit) { + bool test_message_size_limit) { std::vector<TestScenario> scenarios; std::vector<grpc::string> credentials_types; std::vector<grpc::string> messages; @@ -1731,13 +1731,18 @@ std::vector<TestScenario> CreateTestScenarios(bool test_secure, GPR_ASSERT(!credentials_types.empty()); messages.push_back("Hello"); - for (int sz = 1; sz <= test_big_limit; sz *= 32) { - grpc::string big_msg; - for (int i = 0; i < sz * 1024; i++) { - char c = 'a' + (i % 26); - big_msg += c; + if (test_message_size_limit) { + for (size_t k = 1; k < GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH / 1024; + k *= 32) { + grpc::string big_msg; + for (size_t i = 0; i < k * 1024; ++i) { + char c = 'a' + (i % 26); + big_msg += c; + } + messages.push_back(big_msg); } - messages.push_back(big_msg); + messages.push_back( + grpc::string(GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH - 10, 'a')); } // TODO (sreek) Renable tests with health check service after the issue @@ -1758,10 +1763,10 @@ std::vector<TestScenario> CreateTestScenarios(bool test_secure, } INSTANTIATE_TEST_CASE_P(AsyncEnd2end, AsyncEnd2endTest, - ::testing::ValuesIn(CreateTestScenarios(true, 1024))); + ::testing::ValuesIn(CreateTestScenarios(true, true))); INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel, AsyncEnd2endServerTryCancelTest, - ::testing::ValuesIn(CreateTestScenarios(false, 0))); + ::testing::ValuesIn(CreateTestScenarios(false, false))); } // namespace } // namespace testing diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc new file mode 100644 index 0000000000..933e4a1ff6 --- /dev/null +++ b/test/cpp/end2end/channelz_service_test.cc @@ -0,0 +1,352 @@ +/* + * + * 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 <grpc/grpc.h> +#include <grpcpp/channel.h> +#include <grpcpp/client_context.h> +#include <grpcpp/create_channel.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 <grpcpp/ext/channelz_service_plugin.h> +#include "src/proto/grpc/channelz/channelz.grpc.pb.h" +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" +#include "test/cpp/end2end/test_service_impl.h" + +#include <gtest/gtest.h> + +using grpc::channelz::v1::GetChannelRequest; +using grpc::channelz::v1::GetChannelResponse; +using grpc::channelz::v1::GetTopChannelsRequest; +using grpc::channelz::v1::GetTopChannelsResponse; + +namespace grpc { +namespace testing { +namespace { + +// Proxy service supports N backends. Sends RPC to backend dictated by +// request->backend_channel_idx(). +class Proxy : public ::grpc::testing::EchoTestService::Service { + public: + Proxy() {} + + void AddChannelToBackend(const std::shared_ptr<Channel>& channel) { + stubs_.push_back(grpc::testing::EchoTestService::NewStub(channel)); + } + + Status Echo(ServerContext* server_context, const EchoRequest* request, + EchoResponse* response) override { + std::unique_ptr<ClientContext> client_context = + ClientContext::FromServerContext(*server_context); + size_t idx = request->param().backend_channel_idx(); + GPR_ASSERT(idx < stubs_.size()); + return stubs_[idx]->Echo(client_context.get(), *request, response); + } + + private: + std::vector<std::unique_ptr<::grpc::testing::EchoTestService::Stub>> stubs_; +}; + +} // namespace + +class ChannelzServerTest : public ::testing::Test { + public: + ChannelzServerTest() {} + + void SetUp() override { + // ensure channel server is brought up on all severs we build. + ::grpc::channelz::experimental::InitChannelzService(); + + // We set up a proxy server with channelz enabled. + proxy_port_ = grpc_pick_unused_port_or_die(); + ServerBuilder proxy_builder; + grpc::string proxy_server_address = "localhost:" + to_string(proxy_port_); + proxy_builder.AddListeningPort(proxy_server_address, + InsecureServerCredentials()); + // forces channelz and channel tracing to be enabled. + proxy_builder.AddChannelArgument(GRPC_ARG_ENABLE_CHANNELZ, 1); + proxy_builder.AddChannelArgument(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE, + 10); + proxy_builder.RegisterService(&proxy_service_); + proxy_server_ = proxy_builder.BuildAndStart(); + } + + // Sets the proxy up to have an arbitrary number of backends. + void ConfigureProxy(size_t num_backends) { + backends_.resize(num_backends); + for (size_t i = 0; i < num_backends; ++i) { + // create a new backend. + backends_[i].port = grpc_pick_unused_port_or_die(); + ServerBuilder backend_builder; + grpc::string backend_server_address = + "localhost:" + to_string(backends_[i].port); + backend_builder.AddListeningPort(backend_server_address, + InsecureServerCredentials()); + backends_[i].service.reset(new TestServiceImpl); + // ensure that the backend itself has channelz disabled. + backend_builder.AddChannelArgument(GRPC_ARG_ENABLE_CHANNELZ, 0); + backend_builder.RegisterService(backends_[i].service.get()); + backends_[i].server = backend_builder.BuildAndStart(); + // set up a channel to the backend. We ensure that this channel has + // channelz enabled since these channels (proxy outbound to backends) + // are the ones that our test will actually be validating. + ChannelArguments args; + args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 1); + args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE, 10); + std::shared_ptr<Channel> channel_to_backend = CreateCustomChannel( + backend_server_address, InsecureChannelCredentials(), args); + proxy_service_.AddChannelToBackend(channel_to_backend); + } + } + + void ResetStubs() { + string target = "dns:localhost:" + to_string(proxy_port_); + ChannelArguments args; + // disable channelz. We only want to focus on proxy to backend outbound. + args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 0); + std::shared_ptr<Channel> channel = + CreateCustomChannel(target, InsecureChannelCredentials(), args); + channelz_stub_ = grpc::channelz::v1::Channelz::NewStub(channel); + echo_stub_ = grpc::testing::EchoTestService::NewStub(channel); + } + + void SendSuccessfulEcho(int channel_idx) { + EchoRequest request; + EchoResponse response; + request.set_message("Hello channelz"); + request.mutable_param()->set_backend_channel_idx(channel_idx); + ClientContext context; + Status s = echo_stub_->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(s.ok()); + } + + void SendFailedEcho(int channel_idx) { + EchoRequest request; + EchoResponse response; + request.set_message("Hello channelz"); + request.mutable_param()->set_backend_channel_idx(channel_idx); + auto* error = request.mutable_param()->mutable_expected_error(); + error->set_code(13); // INTERNAL + error->set_error_message("error"); + ClientContext context; + Status s = echo_stub_->Echo(&context, request, &response); + EXPECT_FALSE(s.ok()); + } + + static string to_string(const int number) { + std::stringstream strs; + strs << number; + return strs.str(); + } + + protected: + // package of data needed for each backend server. + struct BackendData { + std::unique_ptr<Server> server; + int port; + std::unique_ptr<TestServiceImpl> service; + }; + + std::unique_ptr<grpc::channelz::v1::Channelz::Stub> channelz_stub_; + std::unique_ptr<grpc::testing::EchoTestService::Stub> echo_stub_; + + // proxy server to ping with channelz requests. + std::unique_ptr<Server> proxy_server_; + int proxy_port_; + Proxy proxy_service_; + + // backends. All implement the echo service. + std::vector<BackendData> backends_; +}; + +TEST_F(ChannelzServerTest, BasicTest) { + ResetStubs(); + ConfigureProxy(1); + GetTopChannelsRequest request; + GetTopChannelsResponse response; + request.set_start_channel_id(0); + ClientContext context; + Status s = channelz_stub_->GetTopChannels(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel_size(), 1); +} + +TEST_F(ChannelzServerTest, HighStartId) { + ResetStubs(); + ConfigureProxy(1); + GetTopChannelsRequest request; + GetTopChannelsResponse response; + request.set_start_channel_id(10000); + ClientContext context; + Status s = channelz_stub_->GetTopChannels(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel_size(), 0); +} + +TEST_F(ChannelzServerTest, SuccessfulRequestTest) { + ResetStubs(); + ConfigureProxy(1); + SendSuccessfulEcho(0); + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(1); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), 1); + EXPECT_EQ(response.channel().data().calls_succeeded(), 1); + EXPECT_EQ(response.channel().data().calls_failed(), 0); +} + +TEST_F(ChannelzServerTest, FailedRequestTest) { + ResetStubs(); + ConfigureProxy(1); + SendFailedEcho(0); + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(1); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), 1); + EXPECT_EQ(response.channel().data().calls_succeeded(), 0); + EXPECT_EQ(response.channel().data().calls_failed(), 1); +} + +TEST_F(ChannelzServerTest, ManyRequestsTest) { + ResetStubs(); + ConfigureProxy(1); + // send some RPCs + const int kNumSuccess = 10; + const int kNumFailed = 11; + for (int i = 0; i < kNumSuccess; ++i) { + SendSuccessfulEcho(0); + } + for (int i = 0; i < kNumFailed; ++i) { + SendFailedEcho(0); + } + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(1); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), + kNumSuccess + kNumFailed); + EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess); + EXPECT_EQ(response.channel().data().calls_failed(), kNumFailed); +} + +TEST_F(ChannelzServerTest, ManyChannels) { + ResetStubs(); + const int kNumChannels = 4; + ConfigureProxy(kNumChannels); + GetTopChannelsRequest request; + GetTopChannelsResponse response; + request.set_start_channel_id(0); + ClientContext context; + Status s = channelz_stub_->GetTopChannels(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel_size(), kNumChannels); +} + +TEST_F(ChannelzServerTest, ManyRequestsManyChannels) { + ResetStubs(); + const int kNumChannels = 4; + ConfigureProxy(kNumChannels); + const int kNumSuccess = 10; + const int kNumFailed = 11; + for (int i = 0; i < kNumSuccess; ++i) { + SendSuccessfulEcho(0); + SendSuccessfulEcho(2); + } + for (int i = 0; i < kNumFailed; ++i) { + SendFailedEcho(1); + SendFailedEcho(2); + } + + // the first channel saw only successes + { + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(1); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), kNumSuccess); + EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess); + EXPECT_EQ(response.channel().data().calls_failed(), 0); + } + + // the second channel saw only failures + { + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(2); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), kNumFailed); + EXPECT_EQ(response.channel().data().calls_succeeded(), 0); + EXPECT_EQ(response.channel().data().calls_failed(), kNumFailed); + } + + // the third channel saw both + { + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(3); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), + kNumSuccess + kNumFailed); + EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess); + EXPECT_EQ(response.channel().data().calls_failed(), kNumFailed); + } + + // the fourth channel saw nothing + { + GetChannelRequest request; + GetChannelResponse response; + request.set_channel_id(4); + ClientContext context; + Status s = channelz_stub_->GetChannel(&context, request, &response); + EXPECT_TRUE(s.ok()); + EXPECT_EQ(response.channel().data().calls_started(), 0); + EXPECT_EQ(response.channel().data().calls_succeeded(), 0); + EXPECT_EQ(response.channel().data().calls_failed(), 0); + } +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 8896fc6cae..7fe0da8aae 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -279,9 +279,14 @@ class ClientLbEnd2endTest : public ::testing::Test { void WaitForServer( const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub, - size_t server_idx, const grpc_core::DebugLocation& location) { + size_t server_idx, const grpc_core::DebugLocation& location, + bool ignore_failure = false) { do { - CheckRpcSendOk(stub, location); + if (ignore_failure) { + SendRpc(stub); + } else { + CheckRpcSendOk(stub, location); + } } while (servers_[server_idx]->service_.request_count() == 0); ResetCounters(); } @@ -403,6 +408,36 @@ TEST_F(ClientLbEnd2endTest, PickFirstBackOffMinReconnect) { gpr_atm_rel_store(&g_connection_delay_ms, 0); } +TEST_F(ClientLbEnd2endTest, PickFirstResetConnectionBackoff) { + ChannelArguments args; + constexpr int kInitialBackOffMs = 1000; + args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs); + const std::vector<int> ports = {grpc_pick_unused_port_or_die()}; + auto channel = BuildChannel("pick_first", args); + auto stub = BuildStub(channel); + SetNextResolution(ports); + // The channel won't become connected (there's no server). + EXPECT_FALSE( + channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); + // Bring up a server on the chosen port. + StartServers(1, ports); + const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); + // Wait for connect, but not long enough. This proves that we're + // being throttled by initial backoff. + EXPECT_FALSE( + channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); + // Reset connection backoff. + experimental::ChannelResetConnectionBackoff(channel.get()); + // Wait for connect. Should happen ~immediately. + EXPECT_TRUE( + channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); + const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC); + const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0)); + gpr_log(GPR_DEBUG, "Waited %" PRId64 " milliseconds", waited_ms); + // We should have waited less than kInitialBackOffMs. + EXPECT_LT(waited_ms, kInitialBackOffMs); +} + TEST_F(ClientLbEnd2endTest, PickFirstUpdates) { // Start servers and send one RPC per server. const int kNumServers = 3; @@ -507,6 +542,37 @@ TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) { EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName()); } +TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) { + // Prepare the ports for up servers and down servers. + const int kNumServers = 3; + const int kNumAliveServers = 1; + StartServers(kNumAliveServers); + std::vector<int> alive_ports, dead_ports; + for (size_t i = 0; i < kNumServers; ++i) { + if (i < kNumAliveServers) { + alive_ports.emplace_back(servers_[i]->port_); + } else { + dead_ports.emplace_back(grpc_pick_unused_port_or_die()); + } + } + auto channel = BuildChannel("pick_first"); + auto stub = BuildStub(channel); + // The initial resolution only contains dead ports. There won't be any + // selected subchannel. Re-resolution will return the same result. + SetNextResolution(dead_ports); + gpr_log(GPR_INFO, "****** INITIAL RESOLUTION SET *******"); + for (size_t i = 0; i < 10; ++i) CheckRpcSendFailure(stub); + // Set a re-resolution result that contains reachable ports, so that the + // pick_first LB policy can recover soon. + SetNextResolutionUponError(alive_ports); + gpr_log(GPR_INFO, "****** RE-RESOLUTION SET *******"); + WaitForServer(stub, 0, DEBUG_LOCATION, true /* ignore_failure */); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_EQ(servers_[0]->service_.request_count(), 1); + // Check LB policy name for the channel. + EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName()); +} + TEST_F(ClientLbEnd2endTest, RoundRobin) { // Start servers and send one RPC per server. const int kNumServers = 3; diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc index 88f8f380c3..a8022823b1 100644 --- a/test/cpp/end2end/filter_end2end_test.cc +++ b/test/cpp/end2end/filter_end2end_test.cc @@ -323,7 +323,8 @@ TEST_F(FilterEnd2endTest, SimpleBidiStreaming) { void RegisterFilter() { grpc::RegisterChannelFilter<ChannelDataImpl, CallDataImpl>( - "test-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr); + "test-filter", GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_PRIORITY_LOW, true, + nullptr); } } // namespace diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index 3eb155ef95..7bcf23c0eb 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -46,6 +46,7 @@ DEFINE_string( "all : all test cases;\n" "cancel_after_begin : cancel stream after starting it;\n" "cancel_after_first_response: cancel on first response;\n" + "channel_soak: sends 'soak_iterations' rpcs, rebuilds channel each time;\n" "client_compressed_streaming : compressed request streaming with " "client_compressed_unary : single compressed request;\n" "client_streaming : request streaming with single response;\n" @@ -60,6 +61,7 @@ DEFINE_string( "per_rpc_creds: raw oauth2 access token on a single rpc;\n" "ping_pong : full-duplex streaming;\n" "response streaming;\n" + "rpc_soak: 'sends soak_iterations' large_unary rpcs;\n" "server_compressed_streaming : single request with compressed " "server_compressed_unary : single compressed response;\n" "server_streaming : single request with response streaming;\n" @@ -83,6 +85,10 @@ DEFINE_bool(do_not_abort_on_transient_failures, false, "test is retried in case of transient failures (and currently the " "interop tests are not retried even if this flag is set to true)"); +DEFINE_int32(soak_iterations, 1000, + "number of iterations to use for the two soak tests; rpc_soak and " + "channel_soak"); + using grpc::testing::CreateChannelForTestCase; using grpc::testing::GetServiceAccountJsonKey; using grpc::testing::UpdateActions; @@ -91,8 +97,9 @@ int main(int argc, char** argv) { grpc::testing::InitTest(&argc, &argv, true); gpr_log(GPR_INFO, "Testing these cases: %s", FLAGS_test_case.c_str()); int ret = 0; - grpc::testing::InteropClient client(CreateChannelForTestCase(FLAGS_test_case), - true, + grpc::testing::ChannelCreationFunc channel_creation_func = + std::bind(&CreateChannelForTestCase, FLAGS_test_case); + grpc::testing::InteropClient client(channel_creation_func, true, FLAGS_do_not_abort_on_transient_failures); std::unordered_map<grpc::string, std::function<bool()>> actions; @@ -151,6 +158,11 @@ int main(int argc, char** argv) { std::bind(&grpc::testing::InteropClient::DoUnimplementedService, &client); actions["cacheable_unary"] = std::bind(&grpc::testing::InteropClient::DoCacheableUnary, &client); + actions["channel_soak"] = + std::bind(&grpc::testing::InteropClient::DoChannelSoakTest, &client, + FLAGS_soak_iterations); + actions["rpc_soak"] = std::bind(&grpc::testing::InteropClient::DoRpcSoakTest, + &client, FLAGS_soak_iterations); UpdateActions(&actions); diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc index 29b5a1ed6c..fb7b7bb7d0 100644 --- a/test/cpp/interop/client_helper.cc +++ b/test/cpp/interop/client_helper.cc @@ -88,20 +88,20 @@ std::shared_ptr<Channel> CreateChannelForTestCase( std::shared_ptr<CallCredentials> creds; if (test_case == "compute_engine_creds") { - GPR_ASSERT(FLAGS_use_tls); - creds = GoogleComputeEngineCredentials(); - GPR_ASSERT(creds); + creds = FLAGS_custom_credentials_type == "google_default_credentials" + ? nullptr + : GoogleComputeEngineCredentials(); } else if (test_case == "jwt_token_creds") { - GPR_ASSERT(FLAGS_use_tls); grpc::string json_key = GetServiceAccountJsonKey(); std::chrono::seconds token_lifetime = std::chrono::hours(1); - creds = - ServiceAccountJWTAccessCredentials(json_key, token_lifetime.count()); - GPR_ASSERT(creds); + creds = FLAGS_custom_credentials_type == "google_default_credentials" + ? nullptr + : ServiceAccountJWTAccessCredentials(json_key, + token_lifetime.count()); } else if (test_case == "oauth2_auth_token") { - grpc::string raw_token = GetOauth2AccessToken(); - creds = AccessTokenCredentials(raw_token); - GPR_ASSERT(creds); + creds = FLAGS_custom_credentials_type == "google_default_credentials" + ? nullptr + : AccessTokenCredentials(GetOauth2AccessToken()); } if (FLAGS_custom_credentials_type.empty()) { transport_security security_type = diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc index fce99a1697..b7ce90803b 100644 --- a/test/cpp/interop/interop_client.cc +++ b/test/cpp/interop/interop_client.cc @@ -74,13 +74,15 @@ void UnaryCompressionChecks(const InteropClientContextInspector& inspector, } } // namespace -InteropClient::ServiceStub::ServiceStub(const std::shared_ptr<Channel>& channel, - bool new_stub_every_call) - : channel_(channel), new_stub_every_call_(new_stub_every_call) { +InteropClient::ServiceStub::ServiceStub( + ChannelCreationFunc channel_creation_func, bool new_stub_every_call) + : channel_creation_func_(channel_creation_func), + channel_(channel_creation_func_()), + new_stub_every_call_(new_stub_every_call) { // If new_stub_every_call is false, then this is our chance to initialize // stub_. (see Get()) if (!new_stub_every_call) { - stub_ = TestService::NewStub(channel); + stub_ = TestService::NewStub(channel_); } } @@ -100,27 +102,17 @@ InteropClient::ServiceStub::GetUnimplementedServiceStub() { return unimplemented_service_stub_.get(); } -void InteropClient::ServiceStub::Reset( - const std::shared_ptr<Channel>& channel) { - channel_ = channel; - - // Update stub_ as well. Note: If new_stub_every_call_ is true, we can reset - // the stub_ since the next call to Get() will create a new stub - if (new_stub_every_call_) { - stub_.reset(); - } else { - stub_ = TestService::NewStub(channel); +void InteropClient::ServiceStub::ResetChannel() { + channel_ = channel_creation_func_(); + if (!new_stub_every_call_) { + stub_ = TestService::NewStub(channel_); } } -void InteropClient::Reset(const std::shared_ptr<Channel>& channel) { - serviceStub_.Reset(std::move(channel)); -} - -InteropClient::InteropClient(const std::shared_ptr<Channel>& channel, +InteropClient::InteropClient(ChannelCreationFunc channel_creation_func, bool new_stub_every_test_case, bool do_not_abort_on_transient_failures) - : serviceStub_(std::move(channel), new_stub_every_test_case), + : serviceStub_(channel_creation_func, new_stub_every_test_case), do_not_abort_on_transient_failures_(do_not_abort_on_transient_failures) {} bool InteropClient::AssertStatusOk(const Status& s, @@ -1028,6 +1020,38 @@ bool InteropClient::DoCustomMetadata() { return true; } +bool InteropClient::DoRpcSoakTest(int32_t soak_iterations) { + gpr_log(GPR_DEBUG, "Sending %d RPCs...", soak_iterations); + GPR_ASSERT(soak_iterations > 0); + SimpleRequest request; + SimpleResponse response; + for (int i = 0; i < soak_iterations; ++i) { + if (!PerformLargeUnary(&request, &response)) { + gpr_log(GPR_ERROR, "rpc_soak test failed on iteration %d", i); + return false; + } + } + gpr_log(GPR_DEBUG, "rpc_soak test done."); + return true; +} + +bool InteropClient::DoChannelSoakTest(int32_t soak_iterations) { + gpr_log(GPR_DEBUG, "Sending %d RPCs, tearing down the channel each time...", + soak_iterations); + GPR_ASSERT(soak_iterations > 0); + SimpleRequest request; + SimpleResponse response; + for (int i = 0; i < soak_iterations; ++i) { + serviceStub_.ResetChannel(); + if (!PerformLargeUnary(&request, &response)) { + gpr_log(GPR_ERROR, "channel_soak test failed on iteration %d", i); + return false; + } + } + gpr_log(GPR_DEBUG, "channel_soak test done."); + return true; +} + bool InteropClient::DoUnimplementedService() { gpr_log(GPR_DEBUG, "Sending a request for an unimplemented service..."); diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h index 480eb3f4b6..e5be44d1d4 100644 --- a/test/cpp/interop/interop_client.h +++ b/test/cpp/interop/interop_client.h @@ -34,13 +34,15 @@ typedef std::function<void(const InteropClientContextInspector&, const SimpleRequest*, const SimpleResponse*)> CheckerFn; +typedef std::function<std::shared_ptr<Channel>(void)> ChannelCreationFunc; + class InteropClient { public: /// If new_stub_every_test_case is true, a new TestService::Stub object is /// created for every test case /// If do_not_abort_on_transient_failures is true, abort() is not called in /// case of transient failures (like connection failures) - explicit InteropClient(const std::shared_ptr<Channel>& channel, + explicit InteropClient(ChannelCreationFunc channel_creation_func, bool new_stub_every_test_case, bool do_not_abort_on_transient_failures); ~InteropClient() {} @@ -67,6 +69,14 @@ class InteropClient { bool DoUnimplementedMethod(); bool DoUnimplementedService(); bool DoCacheableUnary(); + + // The following interop test are not yet part of the interop spec, and are + // not implemented cross-language. They are considered experimental for now, + // but at some point in the future, might be codified and implemented in all + // languages + bool DoChannelSoakTest(int32_t soak_iterations); + bool DoRpcSoakTest(int32_t soak_iterations); + // Auth tests. // username is a string containing the user email bool DoJwtTokenCreds(const grpc::string& username); @@ -83,15 +93,17 @@ class InteropClient { public: // If new_stub_every_call = true, pointer to a new instance of // TestServce::Stub is returned by Get() everytime it is called - ServiceStub(const std::shared_ptr<Channel>& channel, + ServiceStub(ChannelCreationFunc channel_creation_func, bool new_stub_every_call); TestService::Stub* Get(); UnimplementedService::Stub* GetUnimplementedServiceStub(); - void Reset(const std::shared_ptr<Channel>& channel); + // forces channel to be recreated. + void ResetChannel(); private: + ChannelCreationFunc channel_creation_func_; std::unique_ptr<TestService::Stub> stub_; std::unique_ptr<UnimplementedService::Stub> unimplemented_service_stub_; std::shared_ptr<Channel> channel_; @@ -109,8 +121,8 @@ class InteropClient { bool AssertStatusCode(const Status& s, StatusCode expected_code, const grpc::string& optional_debug_string); bool TransientFailureOrAbort(); - ServiceStub serviceStub_; + ServiceStub serviceStub_; /// If true, abort() is not called for transient failures bool do_not_abort_on_transient_failures_; }; diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc index 9d373c3cd9..7dc1956f78 100644 --- a/test/cpp/interop/stress_interop_client.cc +++ b/test/cpp/interop/stress_interop_client.cc @@ -68,13 +68,13 @@ TestCaseType WeightedRandomTestSelector::GetNextTest() const { StressTestInteropClient::StressTestInteropClient( int test_id, const grpc::string& server_address, - const std::shared_ptr<Channel>& channel, + ChannelCreationFunc channel_creation_func, const WeightedRandomTestSelector& test_selector, long test_duration_secs, long sleep_duration_ms, bool do_not_abort_on_transient_failures) : test_id_(test_id), server_address_(server_address), - channel_(channel), - interop_client_(new InteropClient(channel, false, + channel_creation_func_(channel_creation_func), + interop_client_(new InteropClient(channel_creation_func_, false, do_not_abort_on_transient_failures)), test_selector_(test_selector), test_duration_secs_(test_duration_secs), diff --git a/test/cpp/interop/stress_interop_client.h b/test/cpp/interop/stress_interop_client.h index e4fa7d0973..58680d8093 100644 --- a/test/cpp/interop/stress_interop_client.h +++ b/test/cpp/interop/stress_interop_client.h @@ -91,7 +91,7 @@ class WeightedRandomTestSelector { class StressTestInteropClient { public: StressTestInteropClient(int test_id, const grpc::string& server_address, - const std::shared_ptr<Channel>& channel, + ChannelCreationFunc channel_creation_func, const WeightedRandomTestSelector& test_selector, long test_duration_secs, long sleep_duration_ms, bool do_not_abort_on_transient_failures); @@ -105,7 +105,7 @@ class StressTestInteropClient { int test_id_; const grpc::string& server_address_; - std::shared_ptr<Channel> channel_; + ChannelCreationFunc channel_creation_func_; std::unique_ptr<InteropClient> interop_client_; const WeightedRandomTestSelector& test_selector_; long test_duration_secs_; diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc index 023e0c8f0b..ebbd14beba 100644 --- a/test/cpp/interop/stress_test.cc +++ b/test/cpp/interop/stress_test.cc @@ -283,15 +283,20 @@ int main(int argc, char** argv) { channel_idx++) { gpr_log(GPR_INFO, "Starting test with %s channel_idx=%d..", it->c_str(), channel_idx); - std::shared_ptr<grpc::Channel> channel = grpc::CreateTestChannel( + grpc::testing::ChannelCreationFunc channel_creation_func = std::bind( + static_cast<std::shared_ptr<grpc::Channel> (*)( + const grpc::string&, const grpc::string&, + grpc::testing::transport_security, bool)>( + grpc::CreateTestChannel), *it, FLAGS_server_host_override, security_type, !FLAGS_use_test_ca); // Create stub(s) for each channel for (int stub_idx = 0; stub_idx < FLAGS_num_stubs_per_channel; stub_idx++) { clients.emplace_back(new StressTestInteropClient( - ++thread_idx, *it, channel, test_selector, FLAGS_test_duration_secs, - FLAGS_sleep_duration_ms, FLAGS_do_not_abort_on_transient_failures)); + ++thread_idx, *it, channel_creation_func, test_selector, + FLAGS_test_duration_secs, FLAGS_sleep_duration_ms, + FLAGS_do_not_abort_on_transient_failures)); bool is_already_created = false; // QpsGauge name diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc index a92e9e3b3e..04c300876c 100644 --- a/test/cpp/naming/address_sorting_test.cc +++ b/test/cpp/naming/address_sorting_test.cc @@ -24,10 +24,8 @@ #include <grpc/support/time.h> #include <string.h> -#include <arpa/inet.h> #include <gflags/gflags.h> #include <gmock/gmock.h> -#include <sys/socket.h> #include <sys/types.h> #include <vector> @@ -51,6 +49,11 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" +#ifndef GPR_WINDOWS +#include <arpa/inet.h> +#include <sys/socket.h> +#endif + namespace { struct TestAddress { @@ -190,10 +193,18 @@ void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, grpc_lb_addresses_destroy(lb_addrs); } -} // namespace +/* We need to run each test case inside of its own + * isolated grpc_init/grpc_shutdown pair, so that + * the "address sorting source addr factory" can be + * restored to its default for each test case. */ +class AddressSortingTest : public ::testing::Test { + protected: + void SetUp() override { grpc_init(); } + void TearDown() override { grpc_shutdown(); } +}; /* Tests for rule 1 */ -TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) { +TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -212,7 +223,7 @@ TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) { }); } -TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { +TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { bool ipv4_supported = true; bool ipv6_supported = false; OverrideAddressSortingSourceAddrFactory( @@ -231,7 +242,7 @@ TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { }); } -TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { +TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { bool ipv4_supported = false; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -253,7 +264,7 @@ TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { /* Tests for rule 2 */ -TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) { +TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -277,7 +288,7 @@ TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) { /* Tests for rule 5 */ -TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) { +TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -300,7 +311,7 @@ TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) { /* Flip the input on the test above to reorder the sort function's * comparator's inputs. */ -TEST(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { +TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -323,8 +334,8 @@ TEST(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { /* Tests for rule 6 */ -TEST(AddressSortingTest, - TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) { +TEST_F(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -348,8 +359,8 @@ TEST(AddressSortingTest, }); } -TEST(AddressSortingTest, - TestUsesDestinationWithHigherPrecedenceWithV4CompatAndLocalhostAddress) { +TEST_F(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithV4CompatAndLocalhostAddress) { bool ipv4_supported = true; bool ipv6_supported = true; // Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X. @@ -377,8 +388,8 @@ TEST(AddressSortingTest, }); } -TEST(AddressSortingTest, - TestUsesDestinationWithHigherPrecedenceWithCatchAllAndLocalhostAddress) { +TEST_F(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithCatchAllAndLocalhostAddress) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -403,8 +414,8 @@ TEST(AddressSortingTest, }); } -TEST(AddressSortingTest, - TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) { +TEST_F(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -426,7 +437,7 @@ TEST(AddressSortingTest, }); } -TEST( +TEST_F( AddressSortingTest, TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddressEnsurePrefixMatchHasNoEffect) { bool ipv4_supported = true; @@ -448,8 +459,8 @@ TEST( }); } -TEST(AddressSortingTest, - TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) { +TEST_F(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -469,19 +480,22 @@ TEST(AddressSortingTest, }); } -TEST( +TEST_F( AddressSortingTest, TestUsesDestinationWithHigherPrecedenceWithCatchAllAndAndV4MappedAddresses) { bool ipv4_supported = true; bool ipv6_supported = true; + // Use embedded ipv4 addresses with leading 1's instead of zero's to be + // compatible with inet_ntop implementations that can display such + // addresses with leading zero's as e.g.: "::ffff:0:2", as on windows. OverrideAddressSortingSourceAddrFactory( ipv4_supported, ipv6_supported, { - {"[::ffff:0.0.0.2]:443", {"[::ffff:0.0.0.3]:0", AF_INET6}}, + {"[::ffff:1.1.1.2]:443", {"[::ffff:1.1.1.3]:0", AF_INET6}}, {"[1234::2]:443", {"[1234::3]:0", AF_INET6}}, }); grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ - {"[::ffff:0.0.0.2]:443", AF_INET6}, + {"[::ffff:1.1.1.2]:443", AF_INET6}, {"[1234::2]:443", AF_INET6}, }); grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); @@ -489,13 +503,13 @@ TEST( // ::ffff:0:2 should match the v4-mapped // precedence entry and be deprioritized. "[1234::2]:443", - "[::ffff:0.0.0.2]:443", + "[::ffff:1.1.1.2]:443", }); } /* Tests for rule 8 */ -TEST(AddressSortingTest, TestPrefersSmallerScope) { +TEST_F(AddressSortingTest, TestPrefersSmallerScope) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -520,7 +534,7 @@ TEST(AddressSortingTest, TestPrefersSmallerScope) { /* Tests for rule 9 */ -TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { +TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -543,8 +557,8 @@ TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { }); } -TEST(AddressSortingTest, - TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) { +TEST_F(AddressSortingTest, + TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -564,7 +578,7 @@ TEST(AddressSortingTest, }); } -TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { +TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -584,7 +598,7 @@ TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { }); } -TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { +TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -604,7 +618,7 @@ TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { }); } -TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { +TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -628,7 +642,7 @@ TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { /* Tests for rule 10 */ -TEST(AddressSortingTest, TestStableSort) { +TEST_F(AddressSortingTest, TestStableSort) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -648,7 +662,7 @@ TEST(AddressSortingTest, TestStableSort) { }); } -TEST(AddressSortingTest, TestStableSortFiveElements) { +TEST_F(AddressSortingTest, TestStableSortFiveElements) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory( @@ -677,7 +691,7 @@ TEST(AddressSortingTest, TestStableSortFiveElements) { }); } -TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) { +TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); @@ -698,7 +712,7 @@ TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) { }); } -TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { +TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); @@ -713,7 +727,7 @@ TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { }); } -TEST(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { +TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { bool ipv4_supported = true; bool ipv6_supported = true; // Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X. @@ -744,6 +758,78 @@ TEST(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { }); } +/* TestPrefersIpv6Loopback tests the actual "address probing" code + * for the current platform, without any mocks. + * This test relies on the assumption that the ipv6 loopback address is + * available in the hosts/containers that grpc C/C++ tests run on + * (whether ipv4 loopback is available or not, an available ipv6 + * loopback should be preferred). */ +TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[::1]:443", AF_INET6}, + {"127.0.0.1:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[::1]:443", + "127.0.0.1:443", + }); +} + +/* Flip the order of the inputs above and expect the same output order + * (try to rule out influence of arbitrary qsort ordering) */ +TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) { + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"127.0.0.1:443", AF_INET}, + {"[::1]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[::1]:443", + "127.0.0.1:443", + }); +} + +/* Try to rule out false positives in the above two tests in which + * the sorter might think that neither ipv6 or ipv4 loopback is + * available, but ipv6 loopback is still preferred only due + * to precedance table lookups. */ +TEST_F(AddressSortingTest, TestSorterKnowsIpv6LoopbackIsAvailable) { + sockaddr_in6 ipv6_loopback; + memset(&ipv6_loopback, 0, sizeof(ipv6_loopback)); + ipv6_loopback.sin6_family = AF_INET6; + ((char*)&ipv6_loopback.sin6_addr)[15] = 1; + ipv6_loopback.sin6_port = htons(443); + // Set up the source and destination parameters of + // address_sorting_get_source_addr + address_sorting_address sort_input_dest; + memcpy(&sort_input_dest.addr, &ipv6_loopback, sizeof(ipv6_loopback)); + sort_input_dest.len = sizeof(ipv6_loopback); + address_sorting_address source_for_sort_input_dest; + memset(&source_for_sort_input_dest, 0, sizeof(source_for_sort_input_dest)); + // address_sorting_get_source_addr returns true if a source address was found + // for the destination address, otherwise false. + EXPECT_TRUE(address_sorting_get_source_addr_for_testing( + &sort_input_dest, &source_for_sort_input_dest)); + // Now also check that the source address was filled in correctly. + EXPECT_GT(source_for_sort_input_dest.len, 0u); + sockaddr_in6* source_addr_output = + (sockaddr_in6*)source_for_sort_input_dest.addr; + EXPECT_EQ(source_addr_output->sin6_family, AF_INET6); + char* buf = static_cast<char*>(gpr_zalloc(100)); + EXPECT_NE(inet_ntop(AF_INET6, &source_addr_output->sin6_addr, buf, 100), + nullptr) + << "inet_ntop failed. Errno: " + std::to_string(errno); + std::string source_addr_str(buf); + gpr_free(buf); + // This test + // assumes that the source address for any loopback destination is also the + // loopback address. + EXPECT_EQ(source_addr_str, "::1"); +} + +} // namespace + int main(int argc, char** argv) { char* resolver = gpr_getenv("GRPC_DNS_RESOLVER"); if (resolver == nullptr || strlen(resolver) == 0) { @@ -754,9 +840,7 @@ int main(int argc, char** argv) { gpr_free(resolver); grpc_test_init(argc, argv); ::testing::InitGoogleTest(&argc, argv); - grpc_init(); auto result = RUN_ALL_TESTS(); - grpc_shutdown(); // Test sequential and nested inits and shutdowns. grpc_init(); grpc_init(); diff --git a/test/cpp/naming/cancel_ares_query_test.cc b/test/cpp/naming/cancel_ares_query_test.cc index 0d59bf6fb6..dec7c171dc 100644 --- a/test/cpp/naming/cancel_ares_query_test.cc +++ b/test/cpp/naming/cancel_ares_query_test.cc @@ -45,11 +45,14 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" -// TODO: pull in different headers when enabling this -// test on windows. Also set BAD_SOCKET_RETURN_VAL -// to INVALID_SOCKET on windows. +#ifdef GPR_WINDOWS +#include "src/core/lib/iomgr/sockaddr_windows.h" +#include "src/core/lib/iomgr/socket_windows.h" +#define BAD_SOCKET_RETURN_VAL INVALID_SOCKET +#else #include "src/core/lib/iomgr/sockaddr_posix.h" #define BAD_SOCKET_RETURN_VAL -1 +#endif namespace { @@ -91,7 +94,13 @@ class FakeNonResponsiveDNSServer { abort(); } } - ~FakeNonResponsiveDNSServer() { close(socket_); } + ~FakeNonResponsiveDNSServer() { +#ifdef GPR_WINDOWS + closesocket(socket_); +#else + close(socket_); +#endif + } private: int socket_; @@ -193,6 +202,38 @@ TEST(CancelDuringAresQuery, TestCancelActiveDNSQuery) { TestCancelActiveDNSQuery(&args); } +#ifdef GPR_WINDOWS + +void MaybePollArbitraryPollsetTwice() { + grpc_pollset* pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size()); + gpr_mu* mu; + grpc_pollset_init(pollset, &mu); + grpc_pollset_worker* worker = nullptr; + // Make a zero timeout poll + gpr_mu_lock(mu); + GRPC_LOG_IF_ERROR( + "pollset_work", + grpc_pollset_work(pollset, &worker, grpc_core::ExecCtx::Get()->Now())); + gpr_mu_unlock(mu); + grpc_core::ExecCtx::Get()->Flush(); + // Make a second zero-timeout poll (in case the first one + // short-circuited by picking up a previous "kick") + gpr_mu_lock(mu); + GRPC_LOG_IF_ERROR( + "pollset_work", + grpc_pollset_work(pollset, &worker, grpc_core::ExecCtx::Get()->Now())); + gpr_mu_unlock(mu); + grpc_core::ExecCtx::Get()->Flush(); + grpc_pollset_destroy(pollset); + gpr_free(pollset); +} + +#else + +void MaybePollArbitraryPollsetTwice() {} + +#endif + TEST(CancelDuringAresQuery, TestFdsAreDeletedFromPollsetSet) { grpc_core::ExecCtx exec_ctx; ArgsStruct args; @@ -209,6 +250,12 @@ TEST(CancelDuringAresQuery, TestFdsAreDeletedFromPollsetSet) { // this test. This test only cares about what happens to fd's that c-ares // opens. TestCancelActiveDNSQuery(&args); + // This test relies on the assumption that cancelling a c-ares query + // will flush out all callbacks on the current exec ctx, which is true + // on posix platforms but not on Windows, because fd shutdown on Windows + // requires a trip through the polling loop to schedule the callback. + // So we need to do extra polling work on Windows to free things up. + MaybePollArbitraryPollsetTwice(); EXPECT_EQ(grpc_iomgr_count_objects_for_testing(), 0u); grpc_pollset_set_destroy(fake_other_pollset_set); } diff --git a/test/cpp/naming/gen_build_yaml.py b/test/cpp/naming/gen_build_yaml.py index baa6512f62..1c9d0676b8 100755 --- a/test/cpp/naming/gen_build_yaml.py +++ b/test/cpp/naming/gen_build_yaml.py @@ -68,7 +68,7 @@ def main(): 'gtest': False, 'run': False, 'src': ['test/cpp/naming/resolver_component_test.cc'], - 'platforms': ['linux', 'posix', 'mac'], + 'platforms': ['linux', 'posix', 'mac', 'windows'], 'deps': [ 'grpc++_test_util' + unsecure_build_config_suffix, 'grpc_test_util' + unsecure_build_config_suffix, @@ -110,7 +110,7 @@ def main(): 'gtest': True, 'run': True, 'src': ['test/cpp/naming/address_sorting_test.cc'], - 'platforms': ['linux', 'posix', 'mac'], + 'platforms': ['linux', 'posix', 'mac', 'windows'], 'deps': [ 'grpc++_test_util' + unsecure_build_config_suffix, 'grpc_test_util' + unsecure_build_config_suffix, @@ -129,7 +129,7 @@ def main(): 'gtest': True, 'run': True, 'src': ['test/cpp/naming/cancel_ares_query_test.cc'], - 'platforms': ['linux', 'posix', 'mac'], + 'platforms': ['linux', 'posix', 'mac', 'windows'], 'deps': [ 'grpc++_test_util', 'grpc_test_util', diff --git a/test/cpp/naming/manual_run_resolver_component_test.py b/test/cpp/naming/manual_run_resolver_component_test.py new file mode 100644 index 0000000000..fb2157741a --- /dev/null +++ b/test/cpp/naming/manual_run_resolver_component_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# 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. + +import os +import subprocess +import sys + +# The c-ares test suite doesn't get ran regularly on Windows, but +# this script provides a way to run a lot of the tests manually. +_MSBUILD_CONFIG = os.environ['CONFIG'] +os.chdir(os.path.join('..', '..', os.getcwd())) +# This port is arbitrary, but it needs to be available. +_DNS_SERVER_PORT = 15353 + +subprocess.call([ + sys.executable, + 'test\\cpp\\naming\\resolver_component_tests_runner.py', + '--test_bin_path', 'cmake\\build\\%s\\resolver_component_test.exe' % _MSBUILD_CONFIG, + '--dns_server_bin_path', 'test\\cpp\\naming\\utils\\dns_server.py', + '--records_config_path', 'test\\cpp\\naming\\resolver_test_record_groups.yaml', + '--dns_server_port', str(_DNS_SERVER_PORT), + '--dns_resolver_bin_path', 'test\\cpp\\naming\\utils\\dns_resolver.py', + '--tcp_connect_bin_path', 'test\\cpp\\naming\\utils\\tcp_connect.py', +]) diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index 6ac548120c..3dc6e7178c 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -16,6 +16,8 @@ * */ +#include <grpc/support/port_platform.h> + #include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> @@ -55,8 +57,15 @@ // TODO: pull in different headers when enabling this // test on windows. Also set BAD_SOCKET_RETURN_VAL // to INVALID_SOCKET on windows. +#ifdef GPR_WINDOWS +#include "src/core/lib/iomgr/sockaddr_windows.h" +#include "src/core/lib/iomgr/socket_windows.h" +#include "src/core/lib/iomgr/tcp_windows.h" +#define BAD_SOCKET_RETURN_VAL INVALID_SOCKET +#else #include "src/core/lib/iomgr/sockaddr_posix.h" #define BAD_SOCKET_RETURN_VAL -1 +#endif using grpc::SubProcess; using std::vector; @@ -241,6 +250,62 @@ void CheckLBPolicyResultLocked(grpc_channel_args* channel_args, } } +#ifdef GPR_WINDOWS +void OpenAndCloseSocketsStressLoop(int dummy_port, gpr_event* done_ev) { + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(dummy_port); + ((char*)&addr.sin6_addr)[15] = 1; + for (;;) { + if (gpr_event_get(done_ev)) { + return; + } + std::vector<int> sockets; + for (size_t i = 0; i < 50; i++) { + SOCKET s = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, + WSA_FLAG_OVERLAPPED); + ASSERT_TRUE(s != BAD_SOCKET_RETURN_VAL) + << "Failed to create TCP ipv6 socket"; + gpr_log(GPR_DEBUG, "Opened socket: %d", s); + char val = 1; + ASSERT_TRUE(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != + SOCKET_ERROR) + << "Failed to set socketopt reuseaddr. WSA error: " + + std::to_string(WSAGetLastError()); + ASSERT_TRUE(grpc_tcp_set_non_block(s) == GRPC_ERROR_NONE) + << "Failed to set socket non-blocking"; + ASSERT_TRUE(bind(s, (const sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR) + << "Failed to bind socket " + std::to_string(s) + + " to [::1]:" + std::to_string(dummy_port) + + ". WSA error: " + std::to_string(WSAGetLastError()); + ASSERT_TRUE(listen(s, 1) != SOCKET_ERROR) + << "Failed to listen on socket " + std::to_string(s) + + ". WSA error: " + std::to_string(WSAGetLastError()); + sockets.push_back(s); + } + // Do a non-blocking accept followed by a close on all of those sockets. + // Do this in a separate loop to try to induce a time window to hit races. + for (size_t i = 0; i < sockets.size(); i++) { + gpr_log(GPR_DEBUG, "non-blocking accept then close on %d", sockets[i]); + ASSERT_TRUE(accept(sockets[i], nullptr, nullptr) == INVALID_SOCKET) + << "Accept on dummy socket unexpectedly accepted actual connection."; + ASSERT_TRUE(WSAGetLastError() == WSAEWOULDBLOCK) + << "OpenAndCloseSocketsStressLoop accept on socket " + + std::to_string(sockets[i]) + + " failed in " + "an unexpected way. " + "WSA error: " + + std::to_string(WSAGetLastError()) + + ". Socket use-after-close bugs are likely."; + ASSERT_TRUE(closesocket(sockets[i]) != SOCKET_ERROR) + << "Failed to close socket: " + std::to_string(sockets[i]) + + ". WSA error: " + std::to_string(WSAGetLastError()); + } + } + return; +} +#else void OpenAndCloseSocketsStressLoop(int dummy_port, gpr_event* done_ev) { // The goal of this loop is to catch socket // "use after close" bugs within the c-ares resolver by acting @@ -311,6 +376,7 @@ void OpenAndCloseSocketsStressLoop(int dummy_port, gpr_event* done_ev) { } } } +#endif void CheckResolverResultLocked(void* argsp, grpc_error* err) { EXPECT_EQ(err, GRPC_ERROR_NONE); @@ -372,9 +438,9 @@ void RunResolvesRelevantRecordsTest(void (*OnDoneLocked)(void* arg, args.expected_lb_policy = FLAGS_expected_lb_policy; // maybe build the address with an authority char* whole_uri = nullptr; - GPR_ASSERT(asprintf(&whole_uri, "dns://%s/%s", - FLAGS_local_dns_server_address.c_str(), - FLAGS_target_name.c_str())); + GPR_ASSERT(gpr_asprintf(&whole_uri, "dns://%s/%s", + FLAGS_local_dns_server_address.c_str(), + FLAGS_target_name.c_str())); // create resolver and resolve grpc_core::OrphanablePtr<grpc_core::Resolver> resolver = grpc_core::ResolverRegistry::CreateResolver(whole_uri, nullptr, diff --git a/test/cpp/naming/resolver_component_tests_runner.py b/test/cpp/naming/resolver_component_tests_runner.py index 69386ebeb0..1873eec35b 100755 --- a/test/cpp/naming/resolver_component_tests_runner.py +++ b/test/cpp/naming/resolver_component_tests_runner.py @@ -22,6 +22,7 @@ import tempfile import os import time import signal +import platform argp = argparse.ArgumentParser(description='Run c-ares resolver tests') @@ -43,6 +44,11 @@ args = argp.parse_args() def test_runner_log(msg): sys.stderr.write('\n%s: %s\n' % (__file__, msg)) +def python_args(arg_list): + if platform.system() == 'Windows': + return [sys.executable] + arg_list + return arg_list + cur_resolver = os.environ.get('GRPC_DNS_RESOLVER') if cur_resolver and cur_resolver != 'ares': test_runner_log(('WARNING: cur resolver set to %s. This set of tests ' @@ -50,26 +56,27 @@ if cur_resolver and cur_resolver != 'ares': test_runner_log('Exit 1 without running tests.') sys.exit(1) os.environ.update({'GRPC_DNS_RESOLVER': 'ares'}) +os.environ.update({'GRPC_TRACE': 'cares_resolver'}) def wait_until_dns_server_is_up(args, dns_server_subprocess, dns_server_subprocess_output): for i in range(0, 30): test_runner_log('Health check: attempt to connect to DNS server over TCP.') - tcp_connect_subprocess = subprocess.Popen([ + tcp_connect_subprocess = subprocess.Popen(python_args([ args.tcp_connect_bin_path, '--server_host', '127.0.0.1', '--server_port', str(args.dns_server_port), - '--timeout', str(1)]) + '--timeout', str(1)])) tcp_connect_subprocess.communicate() if tcp_connect_subprocess.returncode == 0: test_runner_log(('Health check: attempt to make an A-record ' 'query to DNS server.')) - dns_resolver_subprocess = subprocess.Popen([ + dns_resolver_subprocess = subprocess.Popen(python_args([ args.dns_resolver_bin_path, '--qname', 'health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp', '--server_host', '127.0.0.1', - '--server_port', str(args.dns_server_port)], + '--server_port', str(args.dns_server_port)]), stdout=subprocess.PIPE) dns_resolver_stdout, _ = dns_resolver_subprocess.communicate() if dns_resolver_subprocess.returncode == 0: @@ -91,10 +98,10 @@ def wait_until_dns_server_is_up(args, dns_server_subprocess_output = tempfile.mktemp() with open(dns_server_subprocess_output, 'w') as l: - dns_server_subprocess = subprocess.Popen([ + dns_server_subprocess = subprocess.Popen(python_args([ args.dns_server_bin_path, '--port', str(args.dns_server_port), - '--records_config_path', args.records_config_path], + '--records_config_path', args.records_config_path]), stdin=subprocess.PIPE, stdout=l, stderr=l) @@ -112,6 +119,18 @@ wait_until_dns_server_is_up(args, dns_server_subprocess_output) num_test_failures = 0 +test_runner_log('Run test with target: %s' % 'no-srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'no-srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '5.5.5.5:443,False', + '--expected_chosen_service_config', '', + '--expected_lb_policy', '', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + test_runner_log('Run test with target: %s' % 'srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.') current_test_subprocess = subprocess.Popen([ args.test_bin_path, diff --git a/test/cpp/naming/resolver_test_record_groups.yaml b/test/cpp/naming/resolver_test_record_groups.yaml index 6c4f89d09b..3c51a00c7b 100644 --- a/test/cpp/naming/resolver_test_record_groups.yaml +++ b/test/cpp/naming/resolver_test_record_groups.yaml @@ -1,6 +1,14 @@ resolver_tests_common_zone_name: resolver-tests-version-4.grpctestingexp. resolver_component_tests: - expected_addrs: + - {address: '5.5.5.5:443', is_balancer: false} + expected_chosen_service_config: null + expected_lb_policy: null + record_to_resolve: no-srv-ipv4-single-target + records: + no-srv-ipv4-single-target: + - {TTL: '2100', data: 5.5.5.5, type: A} +- expected_addrs: - {address: '1.2.3.4:1234', is_balancer: true} expected_chosen_service_config: null expected_lb_policy: null diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD index e7d093c71a..b958c75fc7 100644 --- a/test/cpp/qps/BUILD +++ b/test/cpp/qps/BUILD @@ -34,11 +34,13 @@ grpc_cc_library( "qps_worker.cc", "server_async.cc", "server_sync.cc", + "qps_server_builder.cc", ], hdrs = [ "client.h", "qps_worker.h", "server.h", + "qps_server_builder.h", ], deps = [ ":histogram", @@ -55,6 +57,10 @@ grpc_cc_library( "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", "//test/cpp/util:test_util", + "//test/cpp/util:test_config", + ], + external_deps = [ + "gflags", ], ) diff --git a/test/cpp/qps/benchmark_config.cc b/test/cpp/qps/benchmark_config.cc index a4fd9de820..5fd0f00038 100644 --- a/test/cpp/qps/benchmark_config.cc +++ b/test/cpp/qps/benchmark_config.cc @@ -22,6 +22,8 @@ #include <grpcpp/create_channel.h> #include <grpcpp/security/credentials.h> +#include "test/cpp/util/test_credentials_provider.h" + DEFINE_bool(enable_log_reporter, true, "Enable reporting of benchmark results through GprLog"); @@ -44,6 +46,10 @@ DEFINE_string(rpc_reporter_server_address, "", DEFINE_bool(enable_rpc_reporter, false, "Enable use of RPC reporter"); +DEFINE_string( + rpc_reporter_credential_type, grpc::testing::kInsecureCredentialsType, + "Credential type for communication to the QPS benchmark report server"); + // 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 {} @@ -65,11 +71,14 @@ static std::shared_ptr<Reporter> InitBenchmarkReporters() { new JsonReporter("JsonReporter", FLAGS_scenario_result_file))); } if (FLAGS_enable_rpc_reporter) { + ChannelArguments channel_args; + std::shared_ptr<ChannelCredentials> channel_creds = + testing::GetCredentialsProvider()->GetChannelCredentials( + FLAGS_rpc_reporter_credential_type, &channel_args); GPR_ASSERT(!FLAGS_rpc_reporter_server_address.empty()); composite_reporter->add(std::unique_ptr<Reporter>(new RpcReporter( - "RpcReporter", - grpc::CreateChannel(FLAGS_rpc_reporter_server_address, - grpc::InsecureChannelCredentials())))); + "RpcReporter", grpc::CreateChannel(FLAGS_rpc_reporter_server_address, + channel_creds)))); } return std::shared_ptr<Reporter>(composite_reporter); diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index 9d58ea8882..9d7469c9b5 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -19,6 +19,8 @@ #ifndef TEST_QPS_CLIENT_H #define TEST_QPS_CLIENT_H +#include <stdlib.h> + #include <condition_variable> #include <mutex> #include <unordered_map> @@ -34,6 +36,7 @@ #include "src/proto/grpc/testing/benchmark_service.grpc.pb.h" #include "src/proto/grpc/testing/payloads.pb.h" +#include "src/core/lib/gpr/env.h" #include "src/cpp/util/core_stats.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/interarrival.h" @@ -441,9 +444,24 @@ class ClientImpl : public Client { std::unique_ptr<std::thread> WaitForReady() { return std::unique_ptr<std::thread>(new std::thread([this]() { if (!is_inproc_) { - GPR_ASSERT(channel_->WaitForConnected( - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_seconds(10, GPR_TIMESPAN)))); + int connect_deadline = 10; + /* Allow optionally overriding connect_deadline in order + * to deal with benchmark environments in which the server + * can take a long time to become ready. */ + char* channel_connect_timeout_str = + gpr_getenv("QPS_WORKER_CHANNEL_CONNECT_TIMEOUT"); + if (channel_connect_timeout_str != nullptr && + strcmp(channel_connect_timeout_str, "") != 0) { + connect_deadline = atoi(channel_connect_timeout_str); + } + gpr_log(GPR_INFO, + "Waiting for up to %d seconds for the channel %p to connect", + connect_deadline, channel_.get()); + gpr_free(channel_connect_timeout_str); + GPR_ASSERT(channel_->WaitForConnected(gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_seconds(connect_deadline, GPR_TIMESPAN)))); + gpr_log(GPR_INFO, "Channel %p connected!", channel_.get()); } })); } diff --git a/test/cpp/qps/qps_server_builder.cc b/test/cpp/qps/qps_server_builder.cc new file mode 100644 index 0000000000..5fbc682b75 --- /dev/null +++ b/test/cpp/qps/qps_server_builder.cc @@ -0,0 +1,45 @@ +/* + * + * 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 "qps_server_builder.h" + +using grpc::ServerBuilder; + +namespace grpc { +namespace testing { + +namespace { +std::unique_ptr<ServerBuilder> DefaultCreateQpsServerBuilder() { + return std::unique_ptr<ServerBuilder>(new ServerBuilder()); +} + +std::function<std::unique_ptr<ServerBuilder>()> g_create_qps_server_builder = + DefaultCreateQpsServerBuilder; +} // namespace + +std::unique_ptr<ServerBuilder> CreateQpsServerBuilder() { + return g_create_qps_server_builder(); +} + +void SetCreateQpsServerBuilderFunc( + std::function<std::unique_ptr<ServerBuilder>()> create_qps_server_builder) { + g_create_qps_server_builder = std::move(create_qps_server_builder); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/qps/qps_server_builder.h b/test/cpp/qps/qps_server_builder.h new file mode 100644 index 0000000000..98f9fa72e9 --- /dev/null +++ b/test/cpp/qps/qps_server_builder.h @@ -0,0 +1,46 @@ +/* + * + * 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_QPS_SERVER_BUILDER_H +#define GRPC_QPS_SERVER_BUILDER_H + +#include <functional> +#include <memory> + +#include <grpcpp/server_builder.h> + +namespace grpc { +namespace testing { + +// CreateQpsServerBuilder creates a new ServerBuilder. +// This uses the "create ServerBuilder" func that was set +// in SetCreateQpsServerBuilderFunc if one has been set, +// otherwise, this defaults to creating a new ServerBuilder +// with only its default constructor. +std::unique_ptr<ServerBuilder> CreateQpsServerBuilder(); + +// SetCreateQpsServerBuilderFunc sets a function to use to create new +// ServerBuilders in "CreateQpsServerBuilder". It can be used to modify options +// that the server is built with. +void SetCreateQpsServerBuilderFunc( + std::function<std::unique_ptr<ServerBuilder>()>); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_QPS_SERVER_BUILDER_H diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc index d3f0380474..7ddf3c1cf3 100644 --- a/test/cpp/qps/qps_worker.cc +++ b/test/cpp/qps/qps_worker.cc @@ -39,6 +39,7 @@ #include "test/core/util/grpc_profiler.h" #include "test/core/util/histogram.h" #include "test/cpp/qps/client.h" +#include "test/cpp/qps/qps_server_builder.h" #include "test/cpp/qps/server.h" #include "test/cpp/util/create_test_channel.h" #include "test/cpp/util/test_credentials_provider.h" @@ -272,18 +273,18 @@ QpsWorker::QpsWorker(int driver_port, int server_port, impl_.reset(new WorkerServiceImpl(server_port, this)); gpr_atm_rel_store(&done_, static_cast<gpr_atm>(0)); - ServerBuilder builder; + std::unique_ptr<ServerBuilder> builder = CreateQpsServerBuilder(); if (driver_port >= 0) { char* server_address = nullptr; gpr_join_host_port(&server_address, "::", driver_port); - builder.AddListeningPort( + builder->AddListeningPort( server_address, GetCredentialsProvider()->GetServerCredentials(credential_type)); gpr_free(server_address); } - builder.RegisterService(impl_.get()); + builder->RegisterService(impl_.get()); - server_ = builder.BuildAndStart(); + server_ = builder->BuildAndStart(); } QpsWorker::~QpsWorker() {} diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 1dfef6cfc1..5cd975cf74 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -38,6 +38,7 @@ #include "src/core/lib/surface/completion_queue.h" #include "src/proto/grpc/testing/benchmark_service.grpc.pb.h" #include "test/core/util/test_config.h" +#include "test/cpp/qps/qps_server_builder.h" #include "test/cpp/qps/server.h" namespace grpc { @@ -74,19 +75,19 @@ class AsyncQpsServerTest final : public grpc::testing::Server { ResponseType*)> process_rpc) : Server(config) { - ServerBuilder builder; + std::unique_ptr<ServerBuilder> builder = CreateQpsServerBuilder(); auto port_num = port(); // Negative port number means inproc server, so no listen port needed if (port_num >= 0) { char* server_address = nullptr; gpr_join_host_port(&server_address, "::", port_num); - builder.AddListeningPort(server_address, - Server::CreateServerCredentials(config)); + builder->AddListeningPort(server_address, + Server::CreateServerCredentials(config)); gpr_free(server_address); } - register_service(&builder, &async_service_); + register_service(builder.get(), &async_service_); int num_threads = config.async_server_threads(); if (num_threads <= 0) { // dynamic sizing @@ -97,15 +98,15 @@ class AsyncQpsServerTest final : public grpc::testing::Server { int tpc = std::max(1, config.threads_per_cq()); // 1 if unspecified int num_cqs = (num_threads + tpc - 1) / tpc; // ceiling operator for (int i = 0; i < num_cqs; i++) { - srv_cqs_.emplace_back(builder.AddCompletionQueue()); + srv_cqs_.emplace_back(builder->AddCompletionQueue()); } for (int i = 0; i < num_threads; i++) { cq_.emplace_back(i % srv_cqs_.size()); } - ApplyConfigToBuilder(config, &builder); + ApplyConfigToBuilder(config, builder.get()); - server_ = builder.BuildAndStart(); + server_ = builder->BuildAndStart(); auto process_rpc_bound = std::bind(process_rpc, config.payload_config(), std::placeholders::_1, diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index b8facf9b56..2e63f5ec86 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -27,6 +27,7 @@ #include "src/core/lib/gpr/host_port.h" #include "src/proto/grpc/testing/benchmark_service.grpc.pb.h" +#include "test/cpp/qps/qps_server_builder.h" #include "test/cpp/qps/server.h" #include "test/cpp/qps/usage_timer.h" @@ -154,23 +155,23 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service { class SynchronousServer final : public grpc::testing::Server { public: explicit SynchronousServer(const ServerConfig& config) : Server(config) { - ServerBuilder builder; + std::unique_ptr<ServerBuilder> builder = CreateQpsServerBuilder(); auto port_num = port(); // Negative port number means inproc server, so no listen port needed if (port_num >= 0) { char* server_address = nullptr; gpr_join_host_port(&server_address, "::", port_num); - builder.AddListeningPort(server_address, - Server::CreateServerCredentials(config)); + builder->AddListeningPort(server_address, + Server::CreateServerCredentials(config)); gpr_free(server_address); } - ApplyConfigToBuilder(config, &builder); + ApplyConfigToBuilder(config, builder.get()); - builder.RegisterService(&service_); + builder->RegisterService(&service_); - impl_ = builder.BuildAndStart(); + impl_ = builder->BuildAndStart(); } std::shared_ptr<Channel> InProcessChannel( diff --git a/test/cpp/server/load_reporter/load_reporter_test.cc b/test/cpp/server/load_reporter/load_reporter_test.cc index 719c3a67d9..0d56cdf431 100644 --- a/test/cpp/server/load_reporter/load_reporter_test.cc +++ b/test/cpp/server/load_reporter/load_reporter_test.cc @@ -172,9 +172,9 @@ class LbFeedbackTest : public LoadReporterTest { // TODO(juanlishen): The error is big because we use sleep(). It should be // much smaller when we use fake clock. ASSERT_THAT(static_cast<double>(lb_feedback.calls_per_second()), - DoubleNear(expected_qps, expected_qps / 50)); + DoubleNear(expected_qps, expected_qps * 0.05)); ASSERT_THAT(static_cast<double>(lb_feedback.errors_per_second()), - DoubleNear(expected_eps, expected_eps / 50)); + DoubleNear(expected_eps, expected_eps * 0.05)); gpr_log(GPR_INFO, "Verified LB feedback matches the samples of index [%lu, %lu).", start, start + count); diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD index 9b42bb28b1..c3bfeb7615 100644 --- a/test/cpp/util/BUILD +++ b/test/cpp/util/BUILD @@ -177,6 +177,7 @@ grpc_cc_test( "//:grpc++_reflection", "//src/proto/grpc/testing:echo_messages_proto", "//src/proto/grpc/testing:echo_proto", + "//test/core/end2end:ssl_test_data", "//test/core/util:grpc_test_util", ], ) diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc index ee310784c2..b4704bfe6a 100644 --- a/test/cpp/util/channel_trace_proto_helper.cc +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -64,13 +64,22 @@ void VaidateProtoJsonTranslation(char* json_c_str) { } // namespace -void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { - VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>( - tracer_json_c_str); +void ValidateChannelTraceProtoJsonTranslation(char* json_c_str) { + VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_c_str); } -void ValidateChannelProtoJsonTranslation(char* channel_json_c_str) { - VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(channel_json_c_str); +void ValidateChannelProtoJsonTranslation(char* json_c_str) { + VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(json_c_str); +} + +void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str) { + VaidateProtoJsonTranslation<grpc::channelz::v1::GetTopChannelsResponse>( + json_c_str); +} + +void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str) { + VaidateProtoJsonTranslation<grpc::channelz::v1::GetChannelResponse>( + json_c_str); } } // namespace testing diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h index d1a3603372..18e3d54b6b 100644 --- a/test/cpp/util/channel_trace_proto_helper.h +++ b/test/cpp/util/channel_trace_proto_helper.h @@ -22,8 +22,10 @@ namespace grpc { namespace testing { -void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str); -void ValidateChannelProtoJsonTranslation(char* channel_json_c_str); +void ValidateChannelTraceProtoJsonTranslation(char* json_c_str); +void ValidateChannelProtoJsonTranslation(char* json_c_str); +void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str); +void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str); } // namespace testing } // namespace grpc diff --git a/test/cpp/util/cli_credentials.cc b/test/cpp/util/cli_credentials.cc index aa4eafb756..acf4ef8ef1 100644 --- a/test/cpp/util/cli_credentials.cc +++ b/test/cpp/util/cli_credentials.cc @@ -20,45 +20,123 @@ #include <gflags/gflags.h> -DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls."); -DEFINE_bool(use_auth, false, "Whether to create default google credentials."); +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."); +DEFINE_string( + ssl_target, "", + "If not empty, treat the server host name as this for ssl/tls certificate " + "validation."); +DEFINE_string( + channel_creds_type, "", + "The channel creds type: insecure, ssl, gdc (Google Default Credentials) " + "or alts."); namespace grpc { namespace testing { -std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials() +grpc::string 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"; +} + +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) { + return grpc::SslCredentials(grpc::SslCredentialsOptions()); + } 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()); + } + fprintf(stderr, + "--channel_creds_type=%s invalid; must be insecure, ssl, gdc or " + "alts.\n", + FLAGS_channel_creds_type.c_str()); + return std::shared_ptr<grpc::ChannelCredentials>(); +} + +std::shared_ptr<grpc::CallCredentials> CliCredentials::GetCallCredentials() const { if (!FLAGS_access_token.empty()) { if (FLAGS_use_auth) { fprintf(stderr, "warning: use_auth is ignored when access_token is provided."); } - - return grpc::CompositeChannelCredentials( - grpc::SslCredentials(grpc::SslCredentialsOptions()), - grpc::AccessTokenCredentials(FLAGS_access_token)); + return grpc::AccessTokenCredentials(FLAGS_access_token); } + return std::shared_ptr<grpc::CallCredentials>(); +} - if (FLAGS_use_auth) { - return grpc::GoogleDefaultCredentials(); +std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials() + const { + 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()); } - - if (FLAGS_enable_ssl) { - return grpc::SslCredentials(grpc::SslCredentialsOptions()); + // Legacy transport upgrade logic for insecure requests. + if (!FLAGS_access_token.empty() && + 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"; } - - return grpc::InsecureChannelCredentials(); + 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 grpc::string CliCredentials::GetCredentialUsage() const { - return " --enable_ssl ; Set whether to use tls\n" + return " --enable_ssl ; Set whether to use ssl (deprecated)\n" " --use_auth ; Set whether to create default google" " credentials\n" " --access_token ; Set the access token in metadata," - " overrides --use_auth\n"; + " overrides --use_auth\n" + " --ssl_target ; Set server host for ssl validation\n" + " --channel_creds_type ; Set to insecure, ssl, gdc, or alts\n"; } + +const grpc::string 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/test/cpp/util/cli_credentials.h b/test/cpp/util/cli_credentials.h index b1358e77d8..4636d3ca14 100644 --- a/test/cpp/util/cli_credentials.h +++ b/test/cpp/util/cli_credentials.h @@ -28,8 +28,22 @@ namespace testing { class CliCredentials { public: virtual ~CliCredentials() {} - virtual std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const; + std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const; virtual const grpc::string GetCredentialUsage() const; + virtual const grpc::string GetSslTargetNameOverride() const; + + protected: + // Returns the appropriate channel_creds_type value for the set of legacy + // flag arguments. + virtual grpc::string GetDefaultChannelCredsType() 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 diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc index 840ca07d2b..ccc60cca27 100644 --- a/test/cpp/util/grpc_tool.cc +++ b/test/cpp/util/grpc_tool.cc @@ -206,6 +206,15 @@ void ReadResponse(CliCall* call, const grpc::string& method_name, } } +std::shared_ptr<grpc::Channel> CreateCliChannel( + const grpc::string& server_address, const CliCredentials& cred) { + grpc::ChannelArguments args; + if (!cred.GetSslTargetNameOverride().empty()) { + args.SetSslTargetNameOverride(cred.GetSslTargetNameOverride()); + } + return grpc::CreateCustomChannel(server_address, cred.GetCredentials(), args); +} + struct Command { const char* command; std::function<bool(GrpcTool*, int, const char**, const CliCredentials&, @@ -324,7 +333,7 @@ bool GrpcTool::ListServices(int argc, const char** argv, grpc::string server_address(argv[0]); std::shared_ptr<grpc::Channel> channel = - grpc::CreateChannel(server_address, cred.GetCredentials()); + CreateCliChannel(server_address, cred); grpc::ProtoReflectionDescriptorDatabase desc_db(channel); grpc::protobuf::DescriptorPool desc_pool(&desc_db); @@ -422,7 +431,7 @@ bool GrpcTool::PrintType(int argc, const char** argv, grpc::string server_address(argv[0]); std::shared_ptr<grpc::Channel> channel = - grpc::CreateChannel(server_address, cred.GetCredentials()); + CreateCliChannel(server_address, cred); grpc::ProtoReflectionDescriptorDatabase desc_db(channel); grpc::protobuf::DescriptorPool desc_pool(&desc_db); @@ -469,7 +478,7 @@ bool GrpcTool::CallMethod(int argc, const char** argv, bool print_mode = false; std::shared_ptr<grpc::Channel> channel = - grpc::CreateChannel(server_address, cred.GetCredentials()); + CreateCliChannel(server_address, cred); if (!FLAGS_binary_input || !FLAGS_binary_output) { parser.reset( @@ -820,7 +829,7 @@ bool GrpcTool::ParseMessage(int argc, const char** argv, if (!FLAGS_binary_input || !FLAGS_binary_output) { std::shared_ptr<grpc::Channel> channel = - grpc::CreateChannel(server_address, cred.GetCredentials()); + CreateCliChannel(server_address, cred); parser.reset( new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr, FLAGS_proto_path, FLAGS_protofiles)); diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc index 6574d1bb44..3aae090e81 100644 --- a/test/cpp/util/grpc_tool_test.cc +++ b/test/cpp/util/grpc_tool_test.cc @@ -35,6 +35,7 @@ #include "src/core/lib/gpr/env.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "src/proto/grpc/testing/echo.pb.h" +#include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/util/cli_credentials.h" @@ -80,6 +81,9 @@ using grpc::testing::EchoResponse; " peer: \"peer\"\n" \ "}\n\n" +DECLARE_string(channel_creds_type); +DECLARE_string(ssl_target); + namespace grpc { namespace testing { @@ -97,10 +101,19 @@ const int kServerDefaultResponseStreamsToSend = 3; class TestCliCredentials final : public grpc::testing::CliCredentials { public: - std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const override { - return InsecureChannelCredentials(); + TestCliCredentials(bool secure = false) : secure_(secure) {} + std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials() + const override { + if (!secure_) { + return InsecureChannelCredentials(); + } + SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; + return SslCredentials(grpc::SslCredentialsOptions(ssl_opts)); } const grpc::string GetCredentialUsage() const override { return ""; } + + private: + const bool secure_; }; bool PrintStream(std::stringstream* ss, const grpc::string& output) { @@ -206,13 +219,24 @@ class GrpcToolTest : public ::testing::Test { // 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 grpc::string SetUpServer() { + const grpc::string SetUpServer(bool secure = false) { std::ostringstream server_address; int port = grpc_pick_unused_port_or_die(); server_address << "localhost:" << port; // Setup server ServerBuilder builder; - builder.AddListeningPort(server_address.str(), InsecureServerCredentials()); + std::shared_ptr<grpc::ServerCredentials> creds; + if (secure) { + SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, + test_server1_cert}; + 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(); return server_address.str(); @@ -743,6 +767,29 @@ TEST_F(GrpcToolTest, CallCommandWithBadMetadata) { gpr_free(test_srcdir); } +TEST_F(GrpcToolTest, ListCommand_OverrideSslHostName) { + const grpc::string 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(); +} + } // namespace testing } // namespace grpc diff --git a/test/distrib/cpp/run_distrib_test_cmake.bat b/test/distrib/cpp/run_distrib_test_cmake.bat index 8eb3b201b1..7658156be1 100644 --- a/test/distrib/cpp/run_distrib_test_cmake.bat +++ b/test/distrib/cpp/run_distrib_test_cmake.bat @@ -39,7 +39,7 @@ cd ../../.. cd third_party/protobuf/cmake mkdir build cd build -cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -Dprotobuf_MSVC_STATIC_RUNTIME=OFF -Dprotobuf_BUILD_TESTS=OFF .. +cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DZLIB_ROOT=%INSTALL_DIR% -Dprotobuf_MSVC_STATIC_RUNTIME=OFF -Dprotobuf_BUILD_TESTS=OFF .. cmake --build . --config Release --target install || goto :error cd ../../../.. diff --git a/test/distrib/cpp/run_distrib_test_routeguide.sh b/test/distrib/cpp/run_distrib_test_routeguide.sh index dc69ab8377..a81692d920 100755 --- a/test/distrib/cpp/run_distrib_test_routeguide.sh +++ b/test/distrib/cpp/run_distrib_test_routeguide.sh @@ -19,7 +19,7 @@ set -ex cd "$(dirname "$0")/../../.." cd third_party/protobuf && ./autogen.sh && \ -./configure && make -j4 && make check && make install && ldconfig +./configure && make -j4 && make install && ldconfig cd ../.. && make -j4 && make install |