diff options
Diffstat (limited to 'test')
31 files changed, 2084 insertions, 155 deletions
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD index c5dfd8ef37..6bf4fcdbb8 100644 --- a/test/core/channel/BUILD +++ b/test/core/channel/BUILD @@ -65,3 +65,32 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "channel_trace_test", + srcs = ["channel_trace_test.cc"], + language = "C++", + deps = [ + "//:gpr", + "//:grpc", + "//:grpc++", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + "//test/cpp/util:channel_trace_proto_helper", + ], + external_deps = [ + "gtest", + ], +) + +grpc_cc_test( + name = "status_util_test", + srcs = ["status_util_test.cc"], + language = "C++", + deps = [ + "//:grpc", + ], + external_deps = [ + "gtest", + ], +) diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc new file mode 100644 index 0000000000..3c73e33612 --- /dev/null +++ b/test/core/channel/channel_trace_test.cc @@ -0,0 +1,240 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdlib.h> +#include <string.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/channel_trace_registry.h" +#include "src/core/lib/gpr/useful.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/json/json.h" + +#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> + +namespace grpc_core { +namespace testing { +namespace { + +grpc_json* GetJsonChild(grpc_json* parent, const char* key) { + EXPECT_NE(parent, nullptr); + for (grpc_json* child = parent->child; child != nullptr; + child = child->next) { + if (child->key != nullptr && strcmp(child->key, key) == 0) return child; + } + return nullptr; +} + +void ValidateJsonArraySize(grpc_json* json, const char* key, + size_t expected_size) { + grpc_json* arr = GetJsonChild(json, key); + 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; + } + ASSERT_EQ(count, expected_size); +} + +void ValidateChannelTraceData(grpc_json* json, + size_t num_events_logged_expected, + size_t actual_num_events_expected) { + ASSERT_NE(json, nullptr); + grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged"); + ASSERT_NE(num_events_logged_json, nullptr); + grpc_json* start_time = GetJsonChild(json, "creationTime"); + ASSERT_NE(start_time, nullptr); + size_t num_events_logged = + (size_t)strtol(num_events_logged_json->value, nullptr, 0); + ASSERT_EQ(num_events_logged, num_events_logged_expected); + ValidateJsonArraySize(json, "events", actual_num_events_expected); +} + +void AddSimpleTrace(RefCountedPtr<ChannelTrace> tracer) { + tracer->AddTraceEvent(ChannelTrace::Severity::Info, + grpc_slice_from_static_string("simple trace")); +} + +// checks for the existence of all the required members of the tracer. +void ValidateChannelTrace(RefCountedPtr<ChannelTrace> tracer, + size_t expected_num_event_logged, size_t max_nodes) { + if (!max_nodes) return; + char* json_str = tracer->RenderTrace(); + grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str); + grpc_json* json = grpc_json_parse_string(json_str); + ValidateChannelTraceData(json, expected_num_event_logged, + GPR_MIN(expected_num_event_logged, max_nodes)); + grpc_json_destroy(json); + gpr_free(json_str); +} + +void ValidateTraceDataMatchedUuidLookup(RefCountedPtr<ChannelTrace> tracer) { + intptr_t uuid = tracer->GetUuid(); + if (uuid == -1) return; // Doesn't make sense to lookup if tracing disabled + char* tracer_json_str = tracer->RenderTrace(); + ChannelTrace* uuid_lookup = + grpc_channel_trace_registry_get_channel_trace(uuid); + char* uuid_lookup_json_str = uuid_lookup->RenderTrace(); + EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0); + gpr_free(tracer_json_str); + gpr_free(uuid_lookup_json_str); +} + +} // anonymous namespace + +class ChannelTracerTest : public ::testing::TestWithParam<size_t> {}; + +// Tests basic ChannelTrace functionality like construction, adding trace, and +// lookups by uuid. +TEST_P(ChannelTracerTest, BasicTest) { + grpc_core::ExecCtx exec_ctx; + RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateTraceDataMatchedUuidLookup(tracer); + tracer->AddTraceEvent(ChannelTrace::Severity::Info, + grpc_slice_from_static_string("trace three")); + tracer->AddTraceEvent(ChannelTrace::Severity::Error, + grpc_slice_from_static_string("trace four error")); + ValidateChannelTrace(tracer, 4, GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 6, GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 10, GetParam()); + ValidateTraceDataMatchedUuidLookup(tracer); + tracer.reset(nullptr); +} + +// Tests more complex functionality, like a parent channel tracking +// subchannles. This exercises the ref/unref patterns since the parent tracer +// and this function will both hold refs to the subchannel. +TEST_P(ChannelTracerTest, ComplexTest) { + grpc_core::ExecCtx exec_ctx; + RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam()); + tracer->AddTraceEventReferencingSubchannel( + ChannelTrace::Severity::Info, + grpc_slice_from_static_string("subchannel one created"), sc1); + ValidateChannelTrace(tracer, 3, GetParam()); + AddSimpleTrace(sc1); + AddSimpleTrace(sc1); + AddSimpleTrace(sc1); + ValidateChannelTrace(sc1, 3, GetParam()); + AddSimpleTrace(sc1); + AddSimpleTrace(sc1); + AddSimpleTrace(sc1); + ValidateChannelTrace(sc1, 6, GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 5, GetParam()); + ValidateTraceDataMatchedUuidLookup(tracer); + RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam()); + tracer->AddTraceEventReferencingChannel( + ChannelTrace::Severity::Info, + grpc_slice_from_static_string("LB channel two created"), sc2); + tracer->AddTraceEventReferencingSubchannel( + ChannelTrace::Severity::Warning, + grpc_slice_from_static_string("subchannel one inactive"), sc1); + ValidateChannelTrace(tracer, 7, GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateTraceDataMatchedUuidLookup(tracer); + tracer.reset(nullptr); + sc1.reset(nullptr); + sc2.reset(nullptr); +} + +// Test a case in which the parent channel has subchannels and the subchannels +// have connections. Ensures that everything lives as long as it should then +// gets deleted. +TEST_P(ChannelTracerTest, TestNesting) { + grpc_core::ExecCtx exec_ctx; + RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 2, GetParam()); + RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam()); + tracer->AddTraceEventReferencingChannel( + ChannelTrace::Severity::Info, + grpc_slice_from_static_string("subchannel one created"), sc1); + ValidateChannelTrace(tracer, 3, GetParam()); + AddSimpleTrace(sc1); + RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(GetParam()); + // nesting one level deeper. + sc1->AddTraceEventReferencingSubchannel( + ChannelTrace::Severity::Info, + grpc_slice_from_static_string("connection one created"), conn1); + ValidateChannelTrace(tracer, 3, GetParam()); + AddSimpleTrace(conn1); + AddSimpleTrace(tracer); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 5, GetParam()); + ValidateChannelTrace(conn1, 1, GetParam()); + RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam()); + tracer->AddTraceEventReferencingSubchannel( + ChannelTrace::Severity::Info, + grpc_slice_from_static_string("subchannel two created"), sc2); + // this trace should not get added to the parents children since it is already + // present in the tracer. + tracer->AddTraceEventReferencingChannel( + ChannelTrace::Severity::Warning, + grpc_slice_from_static_string("subchannel one inactive"), sc1); + AddSimpleTrace(tracer); + ValidateChannelTrace(tracer, 8, GetParam()); + tracer.reset(nullptr); + sc1.reset(nullptr); + sc2.reset(nullptr); + conn1.reset(nullptr); +} + +INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest, + ::testing::Values(0, 1, 2, 6, 10, 15)); + +} // namespace testing +} // namespace grpc_core + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + grpc_init(); + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; +} diff --git a/test/core/client_channel/status_util_test.cc b/test/core/channel/status_util_test.cc index f944990ad2..1d64bf1995 100644 --- a/test/core/client_channel/status_util_test.cc +++ b/test/core/channel/status_util_test.cc @@ -16,7 +16,7 @@ * */ -#include "src/core/ext/filters/client_channel/status_util.h" +#include "src/core/lib/channel/status_util.h" #include <gtest/gtest.h> diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD index d430b722df..5148dc5f74 100644 --- a/test/core/client_channel/BUILD +++ b/test/core/client_channel/BUILD @@ -53,15 +53,3 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) - -grpc_cc_test( - name = "status_util_test", - srcs = ["status_util_test.cc"], - language = "C++", - deps = [ - "//:grpc", - ], - external_deps = [ - "gtest", - ], -) diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index 952f3505fb..dd16694204 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -163,3 +163,20 @@ grpc_cc_test( ) grpc_end2end_tests() + +grpc_cc_test( + name = "h2_ssl_session_reuse_test", + srcs = ["h2_ssl_session_reuse_test.cc"], + external_deps = [ + "gtest", + ], + language = "C++", + deps = [ + ':end2end_tests', + '//:gpr', + '//:grpc', + '//:tsi', + '//test/core/util:gpr_test_util', + '//test/core/util:grpc_test_util', + ], +) diff --git a/test/core/end2end/fuzzers/BUILD b/test/core/end2end/fuzzers/BUILD index d33e2b0ff4..c12cfc6983 100644 --- a/test/core/end2end/fuzzers/BUILD +++ b/test/core/end2end/fuzzers/BUILD @@ -25,6 +25,8 @@ grpc_fuzzer( srcs = ["api_fuzzer.cc"], language = "C++", corpus = "api_fuzzer_corpus", + size = "enormous", + timeout = "eternal", deps = [ "//:gpr", "//:grpc", diff --git a/test/core/end2end/h2_ssl_session_reuse_test.cc b/test/core/end2end/h2_ssl_session_reuse_test.cc new file mode 100644 index 0000000000..d5984be93f --- /dev/null +++ b/test/core/end2end/h2_ssl_session_reuse_test.cc @@ -0,0 +1,280 @@ +/* + * + * 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 "test/core/end2end/end2end_tests.h" + +#include <stdio.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gpr/host_port.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/gpr/tmpfile.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "test/core/end2end/cq_verifier.h" +#include "test/core/end2end/data/ssl_test_data.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +#include <gtest/gtest.h> + +namespace grpc { +namespace testing { +namespace { + +void* tag(intptr_t t) { return (void*)t; } + +gpr_timespec five_seconds_time() { return grpc_timeout_seconds_to_deadline(5); } + +grpc_server* server_create(grpc_completion_queue* cq, char* server_addr) { + grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, + test_server1_cert}; + grpc_server_credentials* server_creds = grpc_ssl_server_credentials_create_ex( + test_root_cert, &pem_cert_key_pair, 1, + GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, nullptr); + + grpc_server* server = grpc_server_create(nullptr, nullptr); + grpc_server_register_completion_queue(server, cq, nullptr); + GPR_ASSERT( + grpc_server_add_secure_http2_port(server, server_addr, server_creds)); + grpc_server_credentials_release(server_creds); + grpc_server_start(server); + + return server; +} + +grpc_channel* client_create(char* server_addr, grpc_ssl_session_cache* cache) { + grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { + test_signed_client_key, test_signed_client_cert}; + grpc_channel_credentials* client_creds = grpc_ssl_credentials_create( + test_root_cert, &signed_client_key_cert_pair, nullptr); + + grpc_arg args[] = { + grpc_channel_arg_string_create( + const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), + const_cast<char*>("waterzooi.test.google.be")), + grpc_ssl_session_cache_create_channel_arg(cache), + }; + + grpc_channel_args* client_args = + grpc_channel_args_copy_and_add(nullptr, args, GPR_ARRAY_SIZE(args)); + + grpc_channel* client = grpc_secure_channel_create(client_creds, server_addr, + client_args, nullptr); + GPR_ASSERT(client != nullptr); + grpc_channel_credentials_release(client_creds); + + { + grpc_core::ExecCtx exec_ctx; + grpc_channel_args_destroy(client_args); + } + + return client; +} + +void do_round_trip(grpc_completion_queue* cq, grpc_server* server, + char* server_addr, grpc_ssl_session_cache* cache, + bool expect_session_reuse) { + grpc_channel* client = client_create(server_addr, cache); + + cq_verifier* cqv = cq_verifier_create(cq); + grpc_op ops[6]; + grpc_op* op; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + + gpr_timespec deadline = grpc_timeout_seconds_to_deadline(60); + grpc_call* c = grpc_channel_create_call( + client, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, + grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr); + GPR_ASSERT(c); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + grpc_call* s; + error = grpc_server_request_call(server, &s, &call_details, + &request_metadata_recv, cq, cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + cq_verify(cqv); + + grpc_auth_context* auth = grpc_call_auth_context(s); + grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name( + auth, GRPC_SSL_SESSION_REUSED_PROPERTY); + const grpc_auth_property* property = grpc_auth_property_iterator_next(&it); + GPR_ASSERT(property != nullptr); + + if (expect_session_reuse) { + GPR_ASSERT(strcmp(property->value, "true") == 0); + } else { + GPR_ASSERT(strcmp(property->value, "false") == 0); + } + grpc_auth_context_release(auth); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_OK; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + grpc_channel_destroy(client); +} + +void drain_cq(grpc_completion_queue* cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_time(), nullptr); + } while (ev.type != GRPC_QUEUE_SHUTDOWN); +} + +TEST(H2SessionReuseTest, SingleReuse) { + int port = grpc_pick_unused_port_or_die(); + + char* server_addr; + gpr_join_host_port(&server_addr, "localhost", port); + + grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr); + grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); + + grpc_server* server = server_create(cq, server_addr); + + do_round_trip(cq, server, server_addr, cache, false); + do_round_trip(cq, server, server_addr, cache, true); + do_round_trip(cq, server, server_addr, cache, true); + + gpr_free(server_addr); + grpc_ssl_session_cache_destroy(cache); + + GPR_ASSERT(grpc_completion_queue_next( + cq, grpc_timeout_milliseconds_to_deadline(100), nullptr) + .type == GRPC_QUEUE_TIMEOUT); + + grpc_completion_queue* shutdown_cq = + grpc_completion_queue_create_for_pluck(nullptr); + grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000), + grpc_timeout_seconds_to_deadline(5), + nullptr) + .type == GRPC_OP_COMPLETE); + grpc_server_destroy(server); + grpc_completion_queue_destroy(shutdown_cq); + + grpc_completion_queue_shutdown(cq); + drain_cq(cq); + grpc_completion_queue_destroy(cq); +} + +} // namespace +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + FILE* roots_file; + size_t roots_size = strlen(test_root_cert); + char* roots_filename; + + grpc_test_init(argc, argv); + /* Set the SSL roots env var. */ + roots_file = gpr_tmpfile("chttp2_ssl_session_reuse_test", &roots_filename); + GPR_ASSERT(roots_filename != nullptr); + GPR_ASSERT(roots_file != nullptr); + GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); + fclose(roots_file); + gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + + grpc_init(); + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + + /* Cleanup. */ + remove(roots_filename); + gpr_free(roots_filename); + + return ret; +} diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc index 6113885171..e8ce4032e0 100644 --- a/test/core/end2end/no_server_test.cc +++ b/test/core/end2end/no_server_test.cc @@ -22,45 +22,47 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/util/test_config.h" static void* tag(intptr_t i) { return (void*)i; } -int main(int argc, char** argv) { - grpc_channel* chan; - grpc_call* call; - gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2); - grpc_completion_queue* cq; - cq_verifier* cqv; - grpc_op ops[6]; - grpc_op* op; - grpc_metadata_array trailing_metadata_recv; - grpc_status_code status; - grpc_slice details; +void run_test(bool wait_for_ready) { + gpr_log(GPR_INFO, "TEST: wait_for_ready=%d", wait_for_ready); - grpc_test_init(argc, argv); grpc_init(); - grpc_metadata_array_init(&trailing_metadata_recv); + grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr); + cq_verifier* cqv = cq_verifier_create(cq); - cq = grpc_completion_queue_create_for_next(nullptr); - cqv = cq_verifier_create(cq); + grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator> + response_generator = + grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>(); + grpc_arg arg = grpc_core::FakeResolverResponseGenerator::MakeChannelArg( + response_generator.get()); + grpc_channel_args args = {1, &arg}; /* create a call, channel to a non existant server */ - chan = grpc_insecure_channel_create("nonexistant:54321", nullptr, nullptr); - grpc_slice host = grpc_slice_from_static_string("nonexistant"); - call = grpc_channel_create_call(chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, - grpc_slice_from_static_string("/Foo"), &host, - deadline, nullptr); + grpc_channel* chan = + grpc_insecure_channel_create("fake:nonexistant", &args, nullptr); + gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2); + grpc_call* call = grpc_channel_create_call( + chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, + grpc_slice_from_static_string("/Foo"), nullptr, deadline, nullptr); + grpc_op ops[6]; memset(ops, 0, sizeof(ops)); - op = ops; + grpc_op* op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; - op->flags = 0; + op->flags = wait_for_ready ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0; op->reserved = nullptr; op++; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_status_code status; + grpc_slice details; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; op->data.recv_status_on_client.status = &status; @@ -71,11 +73,25 @@ int main(int argc, char** argv) { GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(1), nullptr)); + + { + grpc_core::ExecCtx exec_ctx; + response_generator->SetFailure(); + } + /* verify that all tags get completed */ CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED); + gpr_log(GPR_INFO, "call status: %d", status); + if (wait_for_ready) { + GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED); + } else { + GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); + } + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_completion_queue_shutdown(cq); while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), @@ -87,10 +103,12 @@ int main(int argc, char** argv) { grpc_channel_destroy(chan); cq_verifier_destroy(cqv); - grpc_slice_unref(details); - grpc_metadata_array_destroy(&trailing_metadata_recv); - grpc_shutdown(); +} +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + run_test(true /* wait_for_ready */); + run_test(false /* wait_for_ready */); return 0; } diff --git a/test/core/end2end/tests/bad_ping.cc b/test/core/end2end/tests/bad_ping.cc index 95f72ca4c8..239c60845c 100644 --- a/test/core/end2end/tests/bad_ping.cc +++ b/test/core/end2end/tests/bad_ping.cc @@ -28,7 +28,7 @@ #include "src/core/lib/gpr/useful.h" #include "test/core/end2end/cq_verifier.h" -#define MAX_PING_STRIKES 1 +#define MAX_PING_STRIKES 2 static void* tag(intptr_t t) { return (void*)t; } @@ -62,6 +62,7 @@ static void end_test(grpc_end2end_test_fixture* f) { grpc_completion_queue_destroy(f->shutdown_cq); } +// Send more pings than server allows to trigger server's GOAWAY. static void test_bad_ping(grpc_end2end_test_config config) { grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr); cq_verifier* cqv = cq_verifier_create(f.cq); @@ -221,9 +222,170 @@ static void test_bad_ping(grpc_end2end_test_config config) { config.tear_down_data(&f); } +// Try sending more pings than server allows, but server should be fine because +// max_pings_without_data should limit pings sent out on wire. +static void test_pings_without_data(grpc_end2end_test_config config) { + grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr); + cq_verifier* cqv = cq_verifier_create(f.cq); + grpc_arg client_a[3]; + client_a[0].type = GRPC_ARG_INTEGER; + client_a[0].key = + const_cast<char*>(GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS); + client_a[0].value.integer = 10; + // Only allow MAX_PING_STRIKES pings without data (DATA/HEADERS/WINDOW_UPDATE) + // so that the transport will throttle the excess pings. + client_a[1].type = GRPC_ARG_INTEGER; + client_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA); + client_a[1].value.integer = MAX_PING_STRIKES; + client_a[2].type = GRPC_ARG_INTEGER; + client_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE); + client_a[2].value.integer = 0; + grpc_arg server_a[3]; + server_a[0].type = GRPC_ARG_INTEGER; + server_a[0].key = + const_cast<char*>(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS); + server_a[0].value.integer = 300000 /* 5 minutes */; + server_a[1].type = GRPC_ARG_INTEGER; + server_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PING_STRIKES); + server_a[1].value.integer = MAX_PING_STRIKES; + server_a[2].type = GRPC_ARG_INTEGER; + server_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE); + server_a[2].value.integer = 0; + grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; + grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a}; + + config.init_client(&f, &client_args); + config.init_server(&f, &server_args); + + grpc_call* c; + grpc_call* s; + gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10); + grpc_op ops[6]; + grpc_op* op; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + + c = grpc_channel_create_call( + f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq, + grpc_slice_from_static_string("/foo"), + get_host_override_slice("foo.test.google.fr:1234", config), deadline, + nullptr); + GPR_ASSERT(c); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->data.send_initial_metadata.metadata = nullptr; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + cq_verify(cqv); + + // Send too many pings to the server similar to the prevous test case. + // However, since we set the MAX_PINGS_WITHOUT_DATA at the client side, only + // MAX_PING_STRIKES will actually be sent and the rpc will still succeed. + int i; + for (i = 1; i <= MAX_PING_STRIKES + 2; i++) { + grpc_channel_ping(f.client, f.cq, tag(200 + i), nullptr); + if (i <= MAX_PING_STRIKES) { + CQ_EXPECT_COMPLETION(cqv, tag(200 + i), 1); + } + cq_verify(cqv); + } + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(102), 1); + // Client call should return. + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead)); + CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1); + cq_verify(cqv); + + grpc_call_unref(s); + + // The rpc should be successful. + GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); + GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); + validate_host_override_string("foo.test.google.fr:1234", call_details.host, + config); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + grpc_call_unref(c); + cq_verifier_destroy(cqv); + end_test(&f); + config.tear_down_data(&f); +} + void bad_ping(grpc_end2end_test_config config) { GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION); test_bad_ping(config); + test_pings_without_data(config); } void bad_ping_pre_init(void) {} diff --git a/test/core/end2end/tests/keepalive_timeout.cc b/test/core/end2end/tests/keepalive_timeout.cc index f0dd061e33..c0771b8bd2 100644 --- a/test/core/end2end/tests/keepalive_timeout.cc +++ b/test/core/end2end/tests/keepalive_timeout.cc @@ -102,7 +102,7 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { grpc_arg keepalive_arg_elems[3]; keepalive_arg_elems[0].type = GRPC_ARG_INTEGER; keepalive_arg_elems[0].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS); - keepalive_arg_elems[0].value.integer = 1500; + keepalive_arg_elems[0].value.integer = 3500; keepalive_arg_elems[1].type = GRPC_ARG_INTEGER; keepalive_arg_elems[1].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIMEOUT_MS); keepalive_arg_elems[1].value.integer = 0; diff --git a/test/core/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc index b900afaf3d..2a357420f3 100644 --- a/test/core/gprpp/inlined_vector_test.cc +++ b/test/core/gprpp/inlined_vector_test.cc @@ -87,14 +87,17 @@ TEST(InlinedVectorTest, ClearAndRepopulate) { } TEST(InlinedVectorTest, ConstIndexOperator) { - const int kNumElements = 10; + 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()); } - auto const_func = [kNumElements](const InlinedVector<int, 5>& v) { + // 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. + auto const_func = [&](const InlinedVector<int, 5>& v) { for (int i = 0; i < kNumElements; ++i) { EXPECT_EQ(i, v[i]); } diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc index ed3849bfc8..f03f4ccdbd 100644 --- a/test/core/security/security_connector_test.cc +++ b/test/core/security/security_connector_test.cc @@ -340,6 +340,21 @@ static grpc_ssl_roots_override_result override_roots_permanent_failure( return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY; } +namespace grpc_core { +namespace { + +class TestDefafaultSllRootStore : public DefaultSslRootStore { + public: + static grpc_slice ComputePemRootCertsForTesting() { + return ComputePemRootCerts(); + } +}; + +} // namespace +} // namespace grpc_core + +// TODO: Convert this test to C++ test when security_connector implementation +// is converted to C++. static void test_default_ssl_roots(void) { const char* roots_for_env_var = "roots for env var"; @@ -353,7 +368,8 @@ static void test_default_ssl_roots(void) { value. */ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); grpc_set_ssl_roots_override_callback(override_roots_success); - grpc_slice roots = grpc_get_default_ssl_roots_for_testing(); + grpc_slice roots = + grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); char* roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); @@ -362,7 +378,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_get_default_ssl_roots_for_testing(); + roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0); @@ -371,7 +387,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_get_default_ssl_roots_for_testing(); + roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0); @@ -380,8 +396,11 @@ 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_get_default_ssl_roots_for_testing(); + roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting(); GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots)); + const tsi_ssl_root_certs_store* root_store = + grpc_core::TestDefafaultSllRootStore::GetRootStore(); + GPR_ASSERT(root_store == nullptr); /* Cleanup. */ remove(roots_env_var_file_path); diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index bd4dc0b60e..866bee5b2f 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -106,6 +106,8 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_insecure_channel_create); printf("%lx", (unsigned long) grpc_lame_client_channel_create); printf("%lx", (unsigned long) grpc_channel_destroy); + printf("%lx", (unsigned long) grpc_channel_get_trace); + printf("%lx", (unsigned long) grpc_channel_get_uuid); printf("%lx", (unsigned long) grpc_call_cancel); printf("%lx", (unsigned long) grpc_call_cancel_with_status); printf("%lx", (unsigned long) grpc_call_ref); @@ -141,6 +143,9 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_auth_context_add_property); printf("%lx", (unsigned long) grpc_auth_context_add_cstring_property); printf("%lx", (unsigned long) grpc_auth_context_set_peer_identity_property_name); + printf("%lx", (unsigned long) grpc_ssl_session_cache_create_lru); + printf("%lx", (unsigned long) grpc_ssl_session_cache_destroy); + printf("%lx", (unsigned long) grpc_ssl_session_cache_create_channel_arg); printf("%lx", (unsigned long) grpc_channel_credentials_release); printf("%lx", (unsigned long) grpc_google_default_credentials_create); printf("%lx", (unsigned long) grpc_set_ssl_roots_override_callback); diff --git a/test/core/tsi/BUILD b/test/core/tsi/BUILD index 8ac3e7687c..ae6e8fdc32 100644 --- a/test/core/tsi/BUILD +++ b/test/core/tsi/BUILD @@ -41,6 +41,20 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "ssl_session_cache_test", + srcs = ["ssl_session_cache_test.cc"], + language = "C++", + external_deps = [ + "gtest", + ], + deps = [ + "//:grpc", + "//:gpr", + "//:tsi", + "//test/core/util:gpr_test_util", + ], +) grpc_cc_test( name = "ssl_transport_security_test", diff --git a/test/core/tsi/ssl_session_cache_test.cc b/test/core/tsi/ssl_session_cache_test.cc new file mode 100644 index 0000000000..72df0e545c --- /dev/null +++ b/test/core/tsi/ssl_session_cache_test.cc @@ -0,0 +1,154 @@ +/* + * + * 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 <string> +#include <unordered_set> + +#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h" +#include "test/core/util/test_config.h" + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <gtest/gtest.h> + +namespace grpc_core { + +namespace { + +class SessionTracker; + +struct SessionExDataId { + SessionTracker* tracker; + long id; +}; + +class SessionTracker { + public: + SessionTracker() { ssl_context_ = SSL_CTX_new(TLSv1_2_method()); } + + ~SessionTracker() { SSL_CTX_free(ssl_context_); } + + tsi::SslSessionPtr NewSession(long id) { + static int ex_data_id = SSL_SESSION_get_ex_new_index( + 0, nullptr, nullptr, nullptr, DestroyExData); + GPR_ASSERT(ex_data_id != -1); + // OpenSSL and different version of BoringSSL don't agree on API + // so try both. + tsi::SslSessionPtr session = NewSessionInternal(SSL_SESSION_new); + SessionExDataId* data = new SessionExDataId{this, id}; + int result = SSL_SESSION_set_ex_data(session.get(), ex_data_id, data); + EXPECT_EQ(result, 1); + alive_sessions_.insert(id); + return session; + } + + bool IsAlive(long id) const { + return alive_sessions_.find(id) != alive_sessions_.end(); + } + + size_t AliveCount() const { return alive_sessions_.size(); } + + private: + tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)()) { + return tsi::SslSessionPtr(cb()); + } + + tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)(const SSL_CTX*)) { + return tsi::SslSessionPtr(cb(ssl_context_)); + } + + static void DestroyExData(void* parent, void* ptr, CRYPTO_EX_DATA* ad, + int index, long argl, void* argp) { + SessionExDataId* data = static_cast<SessionExDataId*>(ptr); + data->tracker->alive_sessions_.erase(data->id); + delete data; + } + + SSL_CTX* ssl_context_; + std::unordered_set<long> alive_sessions_; +}; + +TEST(SslSessionCacheTest, InitialState) { + SessionTracker tracker; + // Verify session initial state. + { + tsi::SslSessionPtr tmp_sess = tracker.NewSession(1); + EXPECT_EQ(tmp_sess->references, 1); + EXPECT_TRUE(tracker.IsAlive(1)); + EXPECT_EQ(tracker.AliveCount(), 1); + } + EXPECT_FALSE(tracker.IsAlive(1)); + EXPECT_EQ(tracker.AliveCount(), 0); +} + +TEST(SslSessionCacheTest, LruCache) { + SessionTracker tracker; + { + RefCountedPtr<tsi::SslSessionLRUCache> cache = + tsi::SslSessionLRUCache::Create(3); + tsi::SslSessionPtr sess2 = tracker.NewSession(2); + SSL_SESSION* sess2_ptr = sess2.get(); + cache->Put("first.dropbox.com", std::move(sess2)); + EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess2_ptr); + EXPECT_TRUE(tracker.IsAlive(2)); + EXPECT_EQ(tracker.AliveCount(), 1); + // Putting element with the same key destroys old session. + tsi::SslSessionPtr sess3 = tracker.NewSession(3); + SSL_SESSION* sess3_ptr = sess3.get(); + cache->Put("first.dropbox.com", std::move(sess3)); + EXPECT_FALSE(tracker.IsAlive(2)); + EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess3_ptr); + EXPECT_TRUE(tracker.IsAlive(3)); + EXPECT_EQ(tracker.AliveCount(), 1); + // Putting three more elements discards current one. + for (long id = 4; id < 7; id++) { + EXPECT_TRUE(tracker.IsAlive(3)); + std::string domain = std::to_string(id) + ".random.domain"; + cache->Put(domain.c_str(), tracker.NewSession(id)); + } + EXPECT_EQ(cache->Size(), 3); + EXPECT_FALSE(tracker.IsAlive(3)); + EXPECT_EQ(tracker.AliveCount(), 3); + // Accessing element moves it into front of the queue. + EXPECT_TRUE(cache->Get("4.random.domain")); + EXPECT_TRUE(tracker.IsAlive(4)); + EXPECT_TRUE(tracker.IsAlive(5)); + EXPECT_TRUE(tracker.IsAlive(6)); + // One element has to be evicted from cache-> + cache->Put("7.random.domain", tracker.NewSession(7)); + EXPECT_TRUE(tracker.IsAlive(4)); + EXPECT_FALSE(tracker.IsAlive(5)); + EXPECT_TRUE(tracker.IsAlive(6)); + EXPECT_TRUE(tracker.IsAlive(7)); + EXPECT_EQ(tracker.AliveCount(), 3); + } + // Cache destructor destroys all sessions. + EXPECT_EQ(tracker.AliveCount(), 0); +} + +} // namespace +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc_test_init(argc, argv); + grpc_init(); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; +} diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc index d9eb7470d5..88f1abc18c 100644 --- a/test/core/tsi/ssl_transport_security_test.cc +++ b/test/core/tsi/ssl_transport_security_test.cc @@ -52,8 +52,8 @@ typedef enum AlpnMode { typedef struct ssl_alpn_lib { AlpnMode alpn_mode; - char** server_alpn_protocols; - char** client_alpn_protocols; + const char** server_alpn_protocols; + const char** client_alpn_protocols; uint16_t num_server_alpn_protocols; uint16_t num_client_alpn_protocols; } ssl_alpn_lib; @@ -61,7 +61,9 @@ typedef struct ssl_alpn_lib { typedef struct ssl_key_cert_lib { bool use_bad_server_cert; bool use_bad_client_cert; + bool use_root_store; char* root_cert; + tsi_ssl_root_certs_store* root_store; tsi_ssl_pem_key_cert_pair* server_pem_key_cert_pairs; tsi_ssl_pem_key_cert_pair* bad_server_pem_key_cert_pairs; tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair; @@ -76,6 +78,10 @@ typedef struct ssl_tsi_test_fixture { ssl_alpn_lib* alpn_lib; bool force_client_auth; char* server_name_indication; + tsi_ssl_session_cache* session_cache; + bool session_reused; + const char* session_ticket_key; + size_t session_ticket_key_size; tsi_ssl_server_handshaker_factory* server_handshaker_factory; tsi_ssl_client_handshaker_factory* client_handshaker_factory; } ssl_tsi_test_fixture; @@ -89,47 +95,62 @@ static void ssl_test_setup_handshakers(tsi_test_fixture* fixture) { ssl_key_cert_lib* key_cert_lib = ssl_fixture->key_cert_lib; ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib; /* Create client handshaker factory. */ - tsi_ssl_pem_key_cert_pair* client_key_cert_pair = nullptr; + tsi_ssl_client_handshaker_options client_options; + memset(&client_options, 0, sizeof(client_options)); + client_options.pem_root_certs = key_cert_lib->root_cert; if (ssl_fixture->force_client_auth) { - client_key_cert_pair = key_cert_lib->use_bad_client_cert - ? &key_cert_lib->bad_client_pem_key_cert_pair - : &key_cert_lib->client_pem_key_cert_pair; + client_options.pem_key_cert_pair = + key_cert_lib->use_bad_client_cert + ? &key_cert_lib->bad_client_pem_key_cert_pair + : &key_cert_lib->client_pem_key_cert_pair; } - char** client_alpn_protocols = nullptr; - uint16_t num_client_alpn_protocols = 0; if (alpn_lib->alpn_mode == ALPN_CLIENT_NO_SERVER || alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { - client_alpn_protocols = alpn_lib->client_alpn_protocols; - num_client_alpn_protocols = alpn_lib->num_client_alpn_protocols; + client_options.alpn_protocols = alpn_lib->client_alpn_protocols; + client_options.num_alpn_protocols = alpn_lib->num_client_alpn_protocols; } - GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( - client_key_cert_pair, key_cert_lib->root_cert, nullptr, - (const char**)client_alpn_protocols, num_client_alpn_protocols, - &ssl_fixture->client_handshaker_factory) == TSI_OK); + client_options.root_store = + key_cert_lib->use_root_store ? key_cert_lib->root_store : nullptr; + if (ssl_fixture->session_cache != nullptr) { + client_options.session_cache = ssl_fixture->session_cache; + } + GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options( + &client_options, &ssl_fixture->client_handshaker_factory) == + TSI_OK); /* Create server handshaker factory. */ - char** server_alpn_protocols = nullptr; - uint16_t num_server_alpn_protocols = 0; + tsi_ssl_server_handshaker_options server_options; + memset(&server_options, 0, sizeof(server_options)); if (alpn_lib->alpn_mode == ALPN_SERVER_NO_CLIENT || alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { - server_alpn_protocols = alpn_lib->server_alpn_protocols; - num_server_alpn_protocols = alpn_lib->num_server_alpn_protocols; + server_options.alpn_protocols = alpn_lib->server_alpn_protocols; + server_options.num_alpn_protocols = alpn_lib->num_server_alpn_protocols; if (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { - num_server_alpn_protocols--; + server_options.num_alpn_protocols--; } } - GPR_ASSERT(tsi_create_ssl_server_handshaker_factory( - key_cert_lib->use_bad_server_cert - ? key_cert_lib->bad_server_pem_key_cert_pairs - : key_cert_lib->server_pem_key_cert_pairs, - key_cert_lib->use_bad_server_cert - ? key_cert_lib->bad_server_num_key_cert_pairs - : key_cert_lib->server_num_key_cert_pairs, - key_cert_lib->root_cert, ssl_fixture->force_client_auth, - nullptr, (const char**)server_alpn_protocols, - num_server_alpn_protocols, - &ssl_fixture->server_handshaker_factory) == TSI_OK); + server_options.pem_key_cert_pairs = + key_cert_lib->use_bad_server_cert + ? key_cert_lib->bad_server_pem_key_cert_pairs + : key_cert_lib->server_pem_key_cert_pairs; + server_options.num_key_cert_pairs = + key_cert_lib->use_bad_server_cert + ? key_cert_lib->bad_server_num_key_cert_pairs + : key_cert_lib->server_num_key_cert_pairs; + server_options.pem_client_root_certs = key_cert_lib->root_cert; + if (ssl_fixture->force_client_auth) { + server_options.client_certificate_request = + TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; + } else { + server_options.client_certificate_request = + TSI_DONT_REQUEST_CLIENT_CERTIFICATE; + } + server_options.session_ticket_key = ssl_fixture->session_ticket_key; + server_options.session_ticket_key_size = ssl_fixture->session_ticket_key_size; + GPR_ASSERT(tsi_create_ssl_server_handshaker_factory_with_options( + &server_options, &ssl_fixture->server_handshaker_factory) == + TSI_OK); /* Create server and client handshakers. */ tsi_handshaker* client_handshaker = nullptr; GPR_ASSERT(tsi_ssl_client_handshaker_factory_create_handshaker( @@ -176,6 +197,18 @@ check_basic_authenticated_peer_and_get_common_name(const tsi_peer* peer) { return property; } +static void check_session_reusage(ssl_tsi_test_fixture* ssl_fixture, + tsi_peer* peer) { + const tsi_peer_property* session_reused = + tsi_peer_get_property_by_name(peer, TSI_SSL_SESSION_REUSED_PEER_PROPERTY); + GPR_ASSERT(session_reused != nullptr); + if (ssl_fixture->session_reused) { + GPR_ASSERT(strcmp(session_reused->value.data, "true") == 0); + } else { + GPR_ASSERT(strcmp(session_reused->value.data, "false") == 0); + } +} + void check_server0_peer(tsi_peer* peer) { const tsi_peer_property* property = check_basic_authenticated_peer_and_get_common_name(peer); @@ -233,7 +266,7 @@ static void check_client_peer(ssl_tsi_test_fixture* ssl_fixture, ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib; if (!ssl_fixture->force_client_auth) { GPR_ASSERT(peer->property_count == - (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0)); + (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 2 : 1)); } else { const tsi_peer_property* property = check_basic_authenticated_peer_and_get_common_name(peer); @@ -257,8 +290,8 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) { if (expect_success) { GPR_ASSERT(tsi_handshaker_result_extract_peer( ssl_fixture->base.client_result, &peer) == TSI_OK); + check_session_reusage(ssl_fixture, &peer); check_alpn(ssl_fixture, &peer); - if (ssl_fixture->server_name_indication != nullptr) { check_server1_peer(&peer); } else { @@ -270,6 +303,7 @@ static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) { if (expect_success) { GPR_ASSERT(tsi_handshaker_result_extract_peer( ssl_fixture->base.server_result, &peer) == TSI_OK); + check_session_reusage(ssl_fixture, &peer); check_alpn(ssl_fixture, &peer); check_client_peer(ssl_fixture, &peer); } else { @@ -291,11 +325,11 @@ static void ssl_test_destruct(tsi_test_fixture* fixture) { /* Destroy ssl_alpn_lib. */ ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib; for (size_t i = 0; i < alpn_lib->num_server_alpn_protocols; i++) { - gpr_free(alpn_lib->server_alpn_protocols[i]); + gpr_free(const_cast<char*>(alpn_lib->server_alpn_protocols[i])); } gpr_free(alpn_lib->server_alpn_protocols); for (size_t i = 0; i < alpn_lib->num_client_alpn_protocols; i++) { - gpr_free(alpn_lib->client_alpn_protocols[i]); + gpr_free(const_cast<char*>(alpn_lib->client_alpn_protocols[i])); } gpr_free(alpn_lib->client_alpn_protocols); gpr_free(alpn_lib); @@ -315,7 +349,11 @@ static void ssl_test_destruct(tsi_test_fixture* fixture) { ssl_test_pem_key_cert_pair_destroy( key_cert_lib->bad_client_pem_key_cert_pair); gpr_free(key_cert_lib->root_cert); + tsi_ssl_root_certs_store_destroy(key_cert_lib->root_store); gpr_free(key_cert_lib); + if (ssl_fixture->session_cache != nullptr) { + tsi_ssl_session_cache_unref(ssl_fixture->session_cache); + } /* Unreference others. */ tsi_ssl_server_handshaker_factory_unref( ssl_fixture->server_handshaker_factory); @@ -351,6 +389,7 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() { static_cast<ssl_key_cert_lib*>(gpr_zalloc(sizeof(*key_cert_lib))); key_cert_lib->use_bad_server_cert = false; key_cert_lib->use_bad_client_cert = false; + key_cert_lib->use_root_store = false; key_cert_lib->server_num_key_cert_pairs = SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM; key_cert_lib->bad_server_num_key_cert_pairs = @@ -384,14 +423,17 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() { key_cert_lib->bad_client_pem_key_cert_pair.cert_chain = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem"); key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem"); + key_cert_lib->root_store = + tsi_ssl_root_certs_store_create(key_cert_lib->root_cert); + GPR_ASSERT(key_cert_lib->root_store != nullptr); ssl_fixture->key_cert_lib = key_cert_lib; /* Create ssl_alpn_lib. */ ssl_alpn_lib* alpn_lib = static_cast<ssl_alpn_lib*>(gpr_zalloc(sizeof(*alpn_lib))); - alpn_lib->server_alpn_protocols = - static_cast<char**>(gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM)); - alpn_lib->client_alpn_protocols = - static_cast<char**>(gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM)); + alpn_lib->server_alpn_protocols = static_cast<const char**>( + gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM)); + alpn_lib->client_alpn_protocols = static_cast<const char**>( + gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM)); alpn_lib->server_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN1); alpn_lib->server_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3); alpn_lib->client_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN2); @@ -402,6 +444,9 @@ static tsi_test_fixture* ssl_tsi_test_fixture_create() { ssl_fixture->alpn_lib = alpn_lib; ssl_fixture->base.vtable = &vtable; ssl_fixture->server_name_indication = nullptr; + ssl_fixture->session_reused = false; + ssl_fixture->session_ticket_key = nullptr; + ssl_fixture->session_ticket_key_size = 0; ssl_fixture->force_client_auth = false; return &ssl_fixture->base; } @@ -426,6 +471,15 @@ void ssl_tsi_test_do_handshake() { tsi_test_fixture_destroy(fixture); } +void ssl_tsi_test_do_handshake_with_root_store() { + tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture* ssl_fixture = + reinterpret_cast<ssl_tsi_test_fixture*>(fixture); + ssl_fixture->key_cert_lib->use_root_store = true; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + void ssl_tsi_test_do_handshake_with_client_authentication() { tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); ssl_tsi_test_fixture* ssl_fixture = @@ -435,6 +489,16 @@ void ssl_tsi_test_do_handshake_with_client_authentication() { tsi_test_fixture_destroy(fixture); } +void ssl_tsi_test_do_handshake_with_client_authentication_and_root_store() { + tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture* ssl_fixture = + reinterpret_cast<ssl_tsi_test_fixture*>(fixture); + ssl_fixture->force_client_auth = true; + ssl_fixture->key_cert_lib->use_root_store = true; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() { /* server1 cert contains "waterzooi.test.google.be" in SAN. */ tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); @@ -558,6 +622,38 @@ void ssl_tsi_test_do_round_trip_odd_buffer_size() { } } +void ssl_tsi_test_do_handshake_session_cache() { + tsi_ssl_session_cache* session_cache = tsi_ssl_session_cache_create_lru(16); + char session_ticket_key[48]; + auto do_handshake = [&session_ticket_key, + &session_cache](bool session_reused) { + tsi_test_fixture* fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture* ssl_fixture = + reinterpret_cast<ssl_tsi_test_fixture*>(fixture); + ssl_fixture->server_name_indication = + const_cast<char*>("waterzooi.test.google.be"); + ssl_fixture->session_ticket_key = session_ticket_key; + ssl_fixture->session_ticket_key_size = 48; + tsi_ssl_session_cache_ref(session_cache); + ssl_fixture->session_cache = session_cache; + ssl_fixture->session_reused = session_reused; + tsi_test_do_round_trip(&ssl_fixture->base); + tsi_test_fixture_destroy(fixture); + }; + memset(session_ticket_key, 'a', 48); + do_handshake(false); + do_handshake(true); + do_handshake(true); + // Changing session_ticket_key on server invalidates ticket. + memset(session_ticket_key, 'b', 48); + do_handshake(false); + do_handshake(true); + memset(session_ticket_key, 'c', 48); + do_handshake(false); + do_handshake(true); + tsi_ssl_session_cache_unref(session_cache); +} + static const tsi_ssl_handshaker_factory_vtable* original_vtable; static bool handshaker_factory_destructor_called; @@ -575,13 +671,14 @@ static tsi_ssl_handshaker_factory_vtable test_handshaker_factory_vtable = { void test_tsi_ssl_client_handshaker_factory_refcounting() { int i; - const char* cert_chain = - load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem"); + char* cert_chain = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem"); + tsi_ssl_client_handshaker_options options; + memset(&options, 0, sizeof(options)); + options.pem_root_certs = cert_chain; tsi_ssl_client_handshaker_factory* client_handshaker_factory; - GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( - nullptr, cert_chain, nullptr, nullptr, 0, - &client_handshaker_factory) == TSI_OK); + GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options( + &options, &client_handshaker_factory) == TSI_OK); handshaker_factory_destructor_called = false; original_vtable = tsi_ssl_handshaker_factory_swap_vtable( @@ -608,7 +705,7 @@ void test_tsi_ssl_client_handshaker_factory_refcounting() { tsi_handshaker_destroy(handshaker[2]); GPR_ASSERT(handshaker_factory_destructor_called); - gpr_free((void*)cert_chain); + gpr_free(cert_chain); } void test_tsi_ssl_server_handshaker_factory_refcounting() { @@ -658,9 +755,11 @@ void test_tsi_ssl_client_handshaker_factory_bad_params() { const char* cert_chain = "This is not a valid PEM file."; tsi_ssl_client_handshaker_factory* client_handshaker_factory; - GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( - nullptr, cert_chain, nullptr, nullptr, 0, - &client_handshaker_factory) == TSI_INVALID_ARGUMENT); + tsi_ssl_client_handshaker_options options; + memset(&options, 0, sizeof(options)); + options.pem_root_certs = cert_chain; + GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options( + &options, &client_handshaker_factory) == TSI_INVALID_ARGUMENT); tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory); } @@ -673,10 +772,13 @@ void ssl_tsi_test_handshaker_factory_internals() { int main(int argc, char** argv) { grpc_test_init(argc, argv); grpc_init(); + ssl_tsi_test_do_handshake_tiny_handshake_buffer(); ssl_tsi_test_do_handshake_small_handshake_buffer(); ssl_tsi_test_do_handshake(); + ssl_tsi_test_do_handshake_with_root_store(); ssl_tsi_test_do_handshake_with_client_authentication(); + ssl_tsi_test_do_handshake_with_client_authentication_and_root_store(); ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain(); ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain(); ssl_tsi_test_do_handshake_with_bad_server_cert(); @@ -688,6 +790,7 @@ int main(int argc, char** argv) { #endif ssl_tsi_test_do_handshake_alpn_server_no_client(); ssl_tsi_test_do_handshake_alpn_client_server_ok(); + ssl_tsi_test_do_handshake_session_cache(); ssl_tsi_test_do_round_trip_for_all_configs(); ssl_tsi_test_do_round_trip_odd_buffer_size(); ssl_tsi_test_handshaker_factory_internals(); diff --git a/test/core/util/grpc_fuzzer.bzl b/test/core/util/grpc_fuzzer.bzl index cece023fc0..a6a60b0311 100644 --- a/test/core/util/grpc_fuzzer.bzl +++ b/test/core/util/grpc_fuzzer.bzl @@ -14,7 +14,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_cc_test") -def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs): +def grpc_fuzzer(name, corpus, srcs = [], deps = [], size = "large", timeout = "long", **kwargs): grpc_cc_test( name = name, srcs = srcs, @@ -23,6 +23,8 @@ def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs): external_deps = [ 'gtest', ], + size = size, + timeout = timeout, args = ["--directory=" + native.package_name() + "/" + corpus,], **kwargs ) diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_test.cc index fb5f6713d1..57d958349e 100644 --- a/test/cpp/common/alarm_test.cc +++ b/test/cpp/common/alarm_test.cc @@ -36,7 +36,7 @@ TEST(AlarmTest, RegularExpiry) { void* output_tag; bool ok; const CompletionQueue::NextStatus status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); @@ -57,7 +57,7 @@ TEST(AlarmTest, MultithreadedRegularExpiry) { std::thread t2([&cq, &ok, &output_tag, &status] { status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); }); t1.join(); @@ -75,7 +75,7 @@ TEST(AlarmTest, DeprecatedRegularExpiry) { void* output_tag; bool ok; const CompletionQueue::NextStatus status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); @@ -91,7 +91,7 @@ TEST(AlarmTest, MoveConstructor) { void* output_tag; bool ok; const CompletionQueue::NextStatus status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); EXPECT_EQ(junk, output_tag); @@ -108,7 +108,7 @@ TEST(AlarmTest, MoveAssignment) { void* output_tag; bool ok; const CompletionQueue::NextStatus status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); @@ -126,7 +126,7 @@ TEST(AlarmTest, RegularExpiryChrono) { void* output_tag; bool ok; const CompletionQueue::NextStatus status = - cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10)); EXPECT_EQ(status, CompletionQueue::GOT_EVENT); EXPECT_TRUE(ok); @@ -169,7 +169,7 @@ TEST(AlarmTest, Cancellation) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); Alarm alarm; - alarm.Set(&cq, grpc_timeout_seconds_to_deadline(2), junk); + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk); alarm.Cancel(); void* output_tag; @@ -187,7 +187,7 @@ TEST(AlarmTest, SetDestruction) { void* junk = reinterpret_cast<void*>(1618033); { Alarm alarm; - alarm.Set(&cq, grpc_timeout_seconds_to_deadline(2), junk); + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk); } void* output_tag; diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index dd777d10c2..e8d2325b7d 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -319,12 +319,13 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); + response_reader->Finish(&recv_response, &recv_status, tag(4)); + Verifier().Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); send_response.set_message(recv_request.message()); response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); EXPECT_EQ(send_response.message(), recv_response.message()); @@ -434,13 +435,13 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) { service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); + response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(2, true).Verify(cq_.get(), time_limit); EXPECT_EQ(send_request.message(), recv_request.message()); send_response.set_message(recv_request.message()); response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(3, true).Expect(4, true).Verify( cq_.get(), std::chrono::system_clock::time_point::max()); @@ -475,21 +476,18 @@ TEST_P(AsyncEnd2endTest, DoThenAsyncNextRpc) { auto resp_writer_ptr = &response_writer; auto lambda_2 = [&, this, resp_writer_ptr]() { - gpr_log(GPR_ERROR, "CALLED"); service_->RequestEcho(&srv_ctx, &recv_request, resp_writer_ptr, cq_.get(), cq_.get(), tag(2)); }; + response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(2, true).Verify(cq_.get(), time_limit, lambda_2); EXPECT_EQ(send_request.message(), recv_request.message()); - auto recv_resp_ptr = &recv_response; - auto status_ptr = &recv_status; send_response.set_message(recv_request.message()); - auto lambda_3 = [&, this, resp_writer_ptr, send_response]() { + auto lambda_3 = [resp_writer_ptr, send_response]() { resp_writer_ptr->Finish(send_response, Status::OK, tag(3)); }; - response_reader->Finish(recv_resp_ptr, status_ptr, tag(4)); Verifier().Expect(3, true).Expect(4, true).Verify( cq_.get(), std::chrono::system_clock::time_point::max(), lambda_3); @@ -887,6 +885,7 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->Finish(&recv_response, &recv_status, tag(4)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); @@ -903,7 +902,6 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { send_response.set_message(recv_request.message()); response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); EXPECT_EQ(send_response.message(), recv_response.message()); @@ -929,6 +927,7 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->ReadInitialMetadata(tag(4)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); @@ -937,10 +936,7 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) { srv_ctx.AddInitialMetadata(meta1.first, meta1.second); srv_ctx.AddInitialMetadata(meta2.first, meta2.second); response_writer.SendInitialMetadata(tag(3)); - Verifier().Expect(3, true).Verify(cq_.get()); - - response_reader->ReadInitialMetadata(tag(4)); - Verifier().Expect(4, true).Verify(cq_.get()); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); EXPECT_EQ(meta1.second, ToString(server_initial_metadata.find(meta1.first)->second)); @@ -976,6 +972,7 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->Finish(&recv_response, &recv_status, tag(5)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); @@ -988,7 +985,6 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) { srv_ctx.AddTrailingMetadata(meta1.first, meta1.second); srv_ctx.AddTrailingMetadata(meta2.first, meta2.second); response_writer.Finish(send_response, Status::OK, tag(4)); - response_reader->Finish(&recv_response, &recv_status, tag(5)); Verifier().Expect(4, true).Expect(5, true).Verify(cq_.get()); @@ -1036,6 +1032,7 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->ReadInitialMetadata(tag(4)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); @@ -1051,9 +1048,7 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { srv_ctx.AddInitialMetadata(meta3.first, meta3.second); srv_ctx.AddInitialMetadata(meta4.first, meta4.second); response_writer.SendInitialMetadata(tag(3)); - Verifier().Expect(3, true).Verify(cq_.get()); - response_reader->ReadInitialMetadata(tag(4)); - Verifier().Expect(4, true).Verify(cq_.get()); + Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); EXPECT_EQ(meta3.second, ToString(server_initial_metadata.find(meta3.first)->second)); @@ -1096,6 +1091,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) { send_request.set_message(GetParam().message_content); std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->Finish(&recv_response, &recv_status, tag(4)); srv_ctx.AsyncNotifyWhenDone(tag(5)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), @@ -1105,12 +1101,9 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) { EXPECT_EQ(send_request.message(), recv_request.message()); cli_ctx.TryCancel(); - Verifier().Expect(5, true).Verify(cq_.get()); + Verifier().Expect(5, true).Expect(4, true).Verify(cq_.get()); EXPECT_TRUE(srv_ctx.IsCancelled()); - response_reader->Finish(&recv_response, &recv_status, tag(4)); - Verifier().Expect(4, true).Verify(cq_.get()); - EXPECT_EQ(StatusCode::CANCELLED, recv_status.error_code()); } @@ -1131,6 +1124,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) { send_request.set_message(GetParam().message_content); std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + response_reader->Finish(&recv_response, &recv_status, tag(4)); srv_ctx.AsyncNotifyWhenDone(tag(5)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), @@ -1141,7 +1135,6 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) { send_response.set_message(recv_request.message()); response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); Verifier().Expect(3, true).Expect(4, true).Expect(5, true).Verify(cq_.get()); EXPECT_FALSE(srv_ctx.IsCancelled()); @@ -1223,8 +1216,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { srv_ctx.AsyncNotifyWhenDone(tag(11)); service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), tag(2)); - std::thread t1( - [this, &cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); }); + std::thread t1([&cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); }); Verifier().Expect(2, true).Verify(cq_.get()); t1.join(); @@ -1248,7 +1240,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { (server_try_cancel == CANCEL_BEFORE_PROCESSING); std::thread cli_thread([&cli_cq, &cli_stream, &expected_client_cq_result, - &ignore_client_cq_result, this] { + &ignore_client_cq_result] { EchoRequest send_request; // Client sends 3 messages (tags 3, 4 and 5) for (int tag_idx = 3; tag_idx <= 5; tag_idx++) { @@ -1379,8 +1371,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, cq_.get(), cq_.get(), tag(2)); - std::thread t1( - [this, &cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); }); + std::thread t1([&cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); }); Verifier().Expect(2, true).Verify(cq_.get()); t1.join(); @@ -1405,7 +1396,7 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { } std::thread cli_thread([&cli_cq, &cli_stream, &expected_client_cq_result, - &ignore_client_cq_result, this] { + &ignore_client_cq_result] { // Client attempts to read the three messages from the server for (int tag_idx = 6; tag_idx <= 8; tag_idx++) { EchoResponse recv_response; diff --git a/test/cpp/end2end/nonblocking_test.cc b/test/cpp/end2end/nonblocking_test.cc index cb75848337..d8337baca2 100644 --- a/test/cpp/end2end/nonblocking_test.cc +++ b/test/cpp/end2end/nonblocking_test.cc @@ -128,6 +128,7 @@ class NonblockingTest : public ::testing::Test { stub_->PrepareAsyncEcho(&cli_ctx, send_request, cq_.get())); response_reader->StartCall(); + response_reader->Finish(&recv_response, &recv_status, tag(4)); service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), cq_.get(), tag(2)); @@ -141,7 +142,6 @@ class NonblockingTest : public ::testing::Test { send_response.set_message(recv_request.message()); response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); int tagsum = 0; int tagprod = 1; diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index 294f1feb80..3b21c4c278 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -394,13 +394,13 @@ static void BM_PumpUnbalancedUnary_Trickle(benchmark::State& state) { stub->AsyncEcho(&cli_ctx, send_request, fixture->cq())); void* t; bool ok; + response_reader->Finish(&recv_response, &recv_status, tag(4)); TrickleCQNext(fixture.get(), &t, &ok, in_warmup ? -1 : state.iterations()); GPR_ASSERT(ok); GPR_ASSERT(t == tag(0) || t == tag(1)); intptr_t slot = reinterpret_cast<intptr_t>(t); ServerEnv* senv = server_env[slot]; senv->response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); for (int i = (1 << 3) | (1 << 4); i != 0;) { TrickleCQNext(fixture.get(), &t, &ok, in_warmup ? -1 : state.iterations()); diff --git a/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h index a85c33c320..843c8e1486 100644 --- a/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h +++ b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h @@ -78,6 +78,7 @@ static void BM_UnaryPingPong(benchmark::State& state) { ClientContextMutator cli_ctx_mut(&cli_ctx); std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub->AsyncEcho(&cli_ctx, send_request, fixture->cq())); + response_reader->Finish(&recv_response, &recv_status, tag(4)); void* t; bool ok; GPR_ASSERT(fixture->cq()->Next(&t, &ok)); @@ -87,7 +88,6 @@ static void BM_UnaryPingPong(benchmark::State& state) { ServerEnv* senv = server_env[slot]; ServerContextMutator svr_ctx_mut(&senv->ctx); senv->response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); for (int i = (1 << 3) | (1 << 4); i != 0;) { GPR_ASSERT(fixture->cq()->Next(&t, &ok)); GPR_ASSERT(ok); diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc new file mode 100644 index 0000000000..df93ff6f8d --- /dev/null +++ b/test/cpp/naming/address_sorting_test.cc @@ -0,0 +1,737 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <grpc/support/sync.h> +#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> + +#include <address_sorting/address_sorting.h> +#include "test/cpp/util/subprocess.h" +#include "test/cpp/util/test_config.h" + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gpr/host_port.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +namespace { + +struct TestAddress { + std::string dest_addr; + int family; +}; + +grpc_resolved_address TestAddressToGrpcResolvedAddress(TestAddress test_addr) { + char* host; + char* port; + grpc_resolved_address resolved_addr; + gpr_split_host_port(test_addr.dest_addr.c_str(), &host, &port); + if (test_addr.family == AF_INET) { + sockaddr_in in_dest; + memset(&in_dest, 0, sizeof(sockaddr_in)); + in_dest.sin_port = htons(atoi(port)); + in_dest.sin_family = AF_INET; + GPR_ASSERT(inet_pton(AF_INET, host, &in_dest.sin_addr) == 1); + memcpy(&resolved_addr.addr, &in_dest, sizeof(sockaddr_in)); + resolved_addr.len = sizeof(sockaddr_in); + } else { + GPR_ASSERT(test_addr.family == AF_INET6); + sockaddr_in6 in6_dest; + memset(&in6_dest, 0, sizeof(sockaddr_in6)); + in6_dest.sin6_port = htons(atoi(port)); + in6_dest.sin6_family = AF_INET6; + GPR_ASSERT(inet_pton(AF_INET6, host, &in6_dest.sin6_addr) == 1); + memcpy(&resolved_addr.addr, &in6_dest, sizeof(sockaddr_in6)); + resolved_addr.len = sizeof(sockaddr_in6); + } + gpr_free(host); + gpr_free(port); + return resolved_addr; +} + +class MockSourceAddrFactory : public address_sorting_source_addr_factory { + public: + MockSourceAddrFactory( + bool ipv4_supported, bool ipv6_supported, + const std::map<std::string, TestAddress>& dest_addr_to_src_addr) + : ipv4_supported_(ipv4_supported), + ipv6_supported_(ipv6_supported), + dest_addr_to_src_addr_(dest_addr_to_src_addr) {} + + bool GetSourceAddr(const address_sorting_address* dest_addr, + address_sorting_address* source_addr) { + if ((address_sorting_abstract_get_family(dest_addr) == + ADDRESS_SORTING_AF_INET && + !ipv4_supported_) || + (address_sorting_abstract_get_family(dest_addr) == + ADDRESS_SORTING_AF_INET6 && + !ipv6_supported_)) { + return false; + } + char* ip_addr_str; + grpc_resolved_address dest_addr_as_resolved_addr; + memcpy(&dest_addr_as_resolved_addr.addr, dest_addr, dest_addr->len); + dest_addr_as_resolved_addr.len = dest_addr->len; + grpc_sockaddr_to_string(&ip_addr_str, &dest_addr_as_resolved_addr, + false /* normalize */); + auto it = dest_addr_to_src_addr_.find(ip_addr_str); + if (it == dest_addr_to_src_addr_.end()) { + gpr_log(GPR_DEBUG, "can't find |%s| in dest to src map", ip_addr_str); + gpr_free(ip_addr_str); + return false; + } + gpr_free(ip_addr_str); + grpc_resolved_address source_addr_as_resolved_addr = + TestAddressToGrpcResolvedAddress(it->second); + memcpy(source_addr->addr, &source_addr_as_resolved_addr.addr, + source_addr_as_resolved_addr.len); + source_addr->len = source_addr_as_resolved_addr.len; + return true; + } + + private: + // user provided test config + bool ipv4_supported_; + bool ipv6_supported_; + std::map<std::string, TestAddress> dest_addr_to_src_addr_; +}; + +static bool mock_source_addr_factory_wrapper_get_source_addr( + address_sorting_source_addr_factory* factory, + const address_sorting_address* dest_addr, + address_sorting_address* source_addr) { + MockSourceAddrFactory* mock = + reinterpret_cast<MockSourceAddrFactory*>(factory); + return mock->GetSourceAddr(dest_addr, source_addr); +} + +void mock_source_addr_factory_wrapper_destroy( + address_sorting_source_addr_factory* factory) { + MockSourceAddrFactory* mock = + reinterpret_cast<MockSourceAddrFactory*>(factory); + delete mock; +} + +const address_sorting_source_addr_factory_vtable kMockSourceAddrFactoryVtable = + { + mock_source_addr_factory_wrapper_get_source_addr, + mock_source_addr_factory_wrapper_destroy, +}; + +void OverrideAddressSortingSourceAddrFactory( + bool ipv4_supported, bool ipv6_supported, + const std::map<std::string, TestAddress>& dest_addr_to_src_addr) { + address_sorting_source_addr_factory* factory = new MockSourceAddrFactory( + ipv4_supported, ipv6_supported, dest_addr_to_src_addr); + factory->vtable = &kMockSourceAddrFactoryVtable; + address_sorting_override_source_addr_factory_for_testing(factory); +} + +grpc_lb_addresses* BuildLbAddrInputs(std::vector<TestAddress> test_addrs) { + grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, nullptr); + lb_addrs->addresses = + (grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); + lb_addrs->num_addresses = test_addrs.size(); + for (size_t i = 0; i < test_addrs.size(); i++) { + lb_addrs->addresses[i].address = + TestAddressToGrpcResolvedAddress(test_addrs[i]); + } + return lb_addrs; +} + +void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, + std::vector<std::string> expected_addrs) { + EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); + for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + char* ip_addr_str; + grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, + false /* normalize */); + EXPECT_EQ(expected_addrs[i], ip_addr_str); + gpr_free(ip_addr_str); + } + grpc_core::ExecCtx exec_ctx; + grpc_lb_addresses_destroy(lb_addrs); +} + +} // namespace + +/* Tests for rule 1 */ +TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, + }); + auto* lb_addrs = BuildLbAddrInputs({ + {"1.2.3.4:443", AF_INET}, + {"5.6.7.8:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "1.2.3.4:443", + "5.6.7.8:443", + }); +} + +TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { + bool ipv4_supported = true; + bool ipv6_supported = false; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, + }); + auto lb_addrs = BuildLbAddrInputs({ + {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, + {"1.2.3.4:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "1.2.3.4:443", + "[2607:f8b0:400a:801::1002]:443", + }); +} + +TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { + bool ipv4_supported = false; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, + {"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, + {"1.2.3.4:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[2607:f8b0:400a:801::1002]:443", + "1.2.3.4:443", + }); +} + +/* Tests for rule 2 */ + +TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[2000:f8b0:400a:801::1002]:443", + {"[fec0::1000]:0", AF_INET6}}, // global and site-local scope + {"[fec0::5000]:443", + {"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[2000:f8b0:400a:801::1002]:443", AF_INET6}, + {"[fec0::5000]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[fec0::5000]:443", + "[2000:f8b0:400a:801::1002]:443", + }); +} + +/* Tests for rule 5 */ + +TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[2002::5001]:443", {"[2001::5002]:0", AF_INET6}}, + {"[2001::5001]:443", + {"[2001::5002]:0", AF_INET6}}, // matching labels + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[2002::5001]:443", AF_INET6}, + {"[2001::5001]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[2001::5001]:443", + "[2002::5001]:443", + }); +} + +/* Tests for rule 6 */ + +TEST(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, + {"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::5001]:443", AF_INET6}, + {"1.2.3.4:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs( + lb_addrs, { + // The AF_INET address should be IPv4-mapped by the sort, + // and IPv4-mapped + // addresses have higher precedence than 3ffe::/16 by spec. + "1.2.3.4:443", + "[3ffe::5001]:443", + }); +} + +TEST(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithV4CompatAndLocalhostAddress) { + bool ipv4_supported = true; + bool ipv6_supported = true; +// Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X. +#if GPR_APPLE == 1 + const char* v4_compat_dest = "[::0.0.0.2]:443"; + const char* v4_compat_src = "[::0.0.0.2]:0"; +#else + const char* v4_compat_dest = "[::2]:443"; + const char* v4_compat_src = "[::2]:0"; +#endif + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[::1]:443", {"[::1]:0", AF_INET6}}, + {v4_compat_dest, {v4_compat_src, AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {v4_compat_dest, AF_INET6}, + {"[::1]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[::1]:443", + v4_compat_dest, + }); +} + +TEST(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithCatchAllAndLocalhostAddress) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + // 1234::2 for src and dest to make sure that prefix matching has no + // influence on this test. + {"[1234::2]:443", {"[1234::2]:0", AF_INET6}}, + {"[::1]:443", {"[::1]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[1234::2]:443", AF_INET6}, + {"[::1]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs( + lb_addrs, + { + // ::1 should match the localhost precedence entry and be prioritized + "[::1]:443", + "[1234::2]:443", + }); +} + +TEST(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, + {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[2001::1234]:443", AF_INET6}, + {"[2000::5001]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs( + lb_addrs, { + // The 2000::/16 address should match the ::/0 prefix rule + "[2000::5001]:443", + "[2001::1234]:443", + }); +} + +TEST( + AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddressEnsurePrefixMatchHasNoEffect) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, + {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[2001::1231]:443", AF_INET6}, + {"[2000::5001]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[2000::5001]:443", + "[2001::1231]:443", + }); +} + +TEST(AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, + {"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[fec0::1234]:443", AF_INET6}, + {"[fc00::5001]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[fc00::5001]:443", + "[fec0::1234]:443", + }); +} + +TEST( + AddressSortingTest, + TestUsesDestinationWithHigherPrecedenceWithCatchAllAndAndV4MappedAddresses) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[::ffff:0.0.0.2]:443", {"[::ffff:0.0.0.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}, + {"[1234::2]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + // ::ffff:0:2 should match the v4-mapped + // precedence entry and be deprioritized. + "[1234::2]:443", + "[::ffff:0.0.0.2]:443", + }); +} + +/* Tests for rule 8 */ + +TEST(AddressSortingTest, TestPrefersSmallerScope) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + // Both of these destinations have the same precedence in default + // policy + // table. + {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, + {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::5001]:443", AF_INET6}, + {"[fec0::1234]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[fec0::1234]:443", + "[3ffe::5001]:443", + }); +} + +/* Tests for rule 9 */ + +TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + // Both of these destinations have the same precedence in default + // policy + // table. + {"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, + {"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe:5001::]:443", AF_INET6}, + {"[3ffe:1234::]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe:1234::]:443", + "[3ffe:5001::]:443", + }); +} + +TEST(AddressSortingTest, + TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, + {"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::5001]:443", AF_INET6}, + {"[3ffe::1234]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe::1234]:443", + "[3ffe::5001]:443", + }); +} + +TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, + {"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe:8000::]:443", AF_INET6}, + {"[3ffe:2000::]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe:2000::]:443", + "[3ffe:8000::]:443", + }); +} + +TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, + {"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe:6::]:443", AF_INET6}, + {"[3ffe:c::]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe:c::]:443", + "[3ffe:6::]:443", + }); +} + +TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe:1111:1111:1111::]:443", + {"[3ffe:1111:1111:1111::]:0", AF_INET6}}, + {"[3ffe:1111:1111:1110::]:443", + {"[3ffe:1111:1111:1111::]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe:1111:1111:1110::]:443", AF_INET6}, + {"[3ffe:1111:1111:1111::]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe:1111:1111:1111::]:443", + "[3ffe:1111:1111:1110::]:443", + }); +} + +/* Tests for rule 10 */ + +TEST(AddressSortingTest, TestStableSort) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, + {"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::1234]:443", AF_INET6}, + {"[3ffe::1235]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe::1234]:443", + "[3ffe::1235]:443", + }); +} + +TEST(AddressSortingTest, TestStableSortFiveElements) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[3ffe::1231]:443", {"[3ffe::1201]:0", AF_INET6}}, + {"[3ffe::1232]:443", {"[3ffe::1202]:0", AF_INET6}}, + {"[3ffe::1233]:443", {"[3ffe::1203]:0", AF_INET6}}, + {"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, + {"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::1231]:443", AF_INET6}, + {"[3ffe::1232]:443", AF_INET6}, + {"[3ffe::1233]:443", AF_INET6}, + {"[3ffe::1234]:443", AF_INET6}, + {"[3ffe::1235]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe::1231]:443", + "[3ffe::1232]:443", + "[3ffe::1233]:443", + "[3ffe::1234]:443", + "[3ffe::1235]:443", + }); +} + +TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[3ffe::1231]:443", AF_INET6}, + {"[3ffe::1232]:443", AF_INET6}, + {"[3ffe::1233]:443", AF_INET6}, + {"[3ffe::1234]:443", AF_INET6}, + {"[3ffe::1235]:443", AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[3ffe::1231]:443", + "[3ffe::1232]:443", + "[3ffe::1233]:443", + "[3ffe::1234]:443", + "[3ffe::1235]:443", + }); +} + +TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { + bool ipv4_supported = true; + bool ipv6_supported = true; + OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[::ffff:5.6.7.8]:443", AF_INET6}, + {"1.2.3.4:443", AF_INET}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, { + "[::ffff:5.6.7.8]:443", + "1.2.3.4:443", + }); +} + +TEST(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { + bool ipv4_supported = true; + bool ipv6_supported = true; +// Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X. +#if GPR_APPLE == 1 + const char* v4_compat_dest = "[::0.0.0.2]:443"; + const char* v4_compat_src = "[::0.0.0.3]:0"; +#else + const char* v4_compat_dest = "[::2]:443"; + const char* v4_compat_src = "[::3]:0"; +#endif + OverrideAddressSortingSourceAddrFactory( + ipv4_supported, ipv6_supported, + { + {"[fec0::2000]:443", {"[fec0::2001]:0", AF_INET6}}, + {v4_compat_dest, {v4_compat_src, AF_INET6}}, + }); + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + {"[fec0::2000]:443", AF_INET6}, + {v4_compat_dest, AF_INET6}, + }); + grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs); + VerifyLbAddrOutputs(lb_addrs, + { + // The sort should be stable since + // v4-compatible has same precedence as site-local. + "[fec0::2000]:443", + v4_compat_dest, + }); +} + +int main(int argc, char** argv) { + const char* resolver = gpr_getenv("GRPC_DNS_RESOLVER"); + if (resolver == nullptr || strlen(resolver) == 0) { + gpr_setenv("GRPC_DNS_RESOLVER", "ares"); + } else if (strcmp("ares", resolver)) { + gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver); + } + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + grpc_init(); + auto result = RUN_ALL_TESTS(); + grpc_shutdown(); + return result; +} diff --git a/test/cpp/naming/gen_build_yaml.py b/test/cpp/naming/gen_build_yaml.py index 91718156e9..adebc62084 100755 --- a/test/cpp/naming/gen_build_yaml.py +++ b/test/cpp/naming/gen_build_yaml.py @@ -182,6 +182,25 @@ def main(): '--running_under_bazel=false', ], } for unsecure_build_config_suffix in ['_unsecure', ''] + ] + [ + { + 'name': 'address_sorting_test' + unsecure_build_config_suffix, + 'build': 'test', + 'language': 'c++', + 'gtest': True, + 'run': True, + 'src': ['test/cpp/naming/address_sorting_test.cc'], + 'platforms': ['linux', 'posix', 'mac'], + 'deps': [ + 'grpc++_test_util' + unsecure_build_config_suffix, + 'grpc_test_util' + unsecure_build_config_suffix, + 'gpr_test_util', + 'grpc++' + unsecure_build_config_suffix, + 'grpc' + unsecure_build_config_suffix, + 'gpr', + 'grpc++_test_config', + ], + } for unsecure_build_config_suffix in ['_unsecure', ''] ] } diff --git a/test/cpp/naming/generate_resolver_component_tests.bzl b/test/cpp/naming/generate_resolver_component_tests.bzl index d0fb51439f..ebc167931d 100755 --- a/test/cpp/naming/generate_resolver_component_tests.bzl +++ b/test/cpp/naming/generate_resolver_component_tests.bzl @@ -17,6 +17,24 @@ load("//bazel:grpc_build_system.bzl", "grpc_sh_binary", "grpc_cc_test", "grpc_cc def generate_resolver_component_tests(): for unsecure_build_config_suffix in ['_unsecure', '']: + grpc_cc_test( + name = "address_sorting_test%s" % unsecure_build_config_suffix, + srcs = [ + "address_sorting_test.cc", + ], + external_deps = [ + "gmock", + ], + deps = [ + "//test/cpp/util:test_util%s" % unsecure_build_config_suffix, + "//test/core/util:grpc_test_util%s" % unsecure_build_config_suffix, + "//test/core/util:gpr_test_util", + "//:grpc++%s" % unsecure_build_config_suffix, + "//:grpc%s" % unsecure_build_config_suffix, + "//:gpr", + "//test/cpp/util:test_config", + ], + ) # meant to be invoked only through the top-level shell script driver grpc_cc_binary( name = "resolver_component_test%s" % unsecure_build_config_suffix, diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc index 5faa7ba757..0ea3181f7e 100644 --- a/test/cpp/performance/writes_per_rpc_test.cc +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -207,13 +207,13 @@ static double UnaryPingPong(int request_size, int response_size) { stub->AsyncEcho(&cli_ctx, send_request, fixture->cq())); void* t; bool ok; + response_reader->Finish(&recv_response, &recv_status, tag(4)); GPR_ASSERT(fixture->cq()->Next(&t, &ok)); GPR_ASSERT(ok); GPR_ASSERT(t == tag(0) || t == tag(1)); intptr_t slot = reinterpret_cast<intptr_t>(t); ServerEnv* senv = server_env[slot]; senv->response_writer.Finish(send_response, Status::OK, tag(3)); - response_reader->Finish(&recv_response, &recv_status, tag(4)); for (int i = (1 << 3) | (1 << 4); i != 0;) { GPR_ASSERT(fixture->cq()->Next(&t, &ok)); GPR_ASSERT(ok); diff --git a/test/cpp/qps/gen_build_yaml.py b/test/cpp/qps/gen_build_yaml.py index bd40d0a5a2..1ef8f65b0b 100755 --- a/test/cpp/qps/gen_build_yaml.py +++ b/test/cpp/qps/gen_build_yaml.py @@ -101,26 +101,24 @@ print yaml.dump({ } for scenario_json in scenario_config.CXXLanguage().scenarios() if 'inproc' in scenario_json.get('CATEGORIES', []) + ] + [ + { + 'name': 'json_run_localhost', + 'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'], + 'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)], + 'ci_platforms': ['linux'], + 'platforms': ['linux'], + 'flaky': False, + 'language': 'c++', + 'boringssl': True, + 'defaults': 'boringssl', + 'cpu_cost': guess_cpu(scenario_json, True), + 'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')), + 'timeout_seconds': 10*60, + 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []), + 'auto_timeout_scaling': False + } + for scenario_json in scenario_config.CXXLanguage().scenarios() + if 'scalable' in scenario_json.get('CATEGORIES', []) ] - # Disabled until https://github.com/grpc/grpc/issues/13122 is resolved. - # + [ - # { - # 'name': 'json_run_localhost', - # 'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'], - # 'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)], - # 'ci_platforms': ['linux'], - # 'platforms': ['linux'], - # 'flaky': False, - # 'language': 'c++', - # 'boringssl': True, - # 'defaults': 'boringssl', - # 'cpu_cost': guess_cpu(scenario_json, True), - # 'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')), - # 'timeout_seconds': 10*60, - # 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []), - # 'auto_timeout_scaling': False - # } - # for scenario_json in scenario_config.CXXLanguage().scenarios() - # if 'scalable' in scenario_json.get('CATEGORIES', []) - # ] }) diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD index 4f84c73820..f53bc7eb7f 100644 --- a/test/cpp/util/BUILD +++ b/test/cpp/util/BUILD @@ -85,6 +85,25 @@ grpc_cc_library( ) grpc_cc_library( + name = "channel_trace_proto_helper", + testonly = 1, + srcs = [ + "channel_trace_proto_helper.cc", + ], + hdrs = [ + "channel_trace_proto_helper.h", + ], + deps = [ + "//:grpc++", + "//src/proto/grpc/channelz:channelz_proto", + ], + external_deps = [ + "gtest", + "protobuf", + ], +) + +grpc_cc_library( name = "test_util_unsecure", srcs = GRPCXX_TESTUTIL_SRCS, hdrs = GRPCXX_TESTUTIL_HDRS, diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc new file mode 100644 index 0000000000..fbc9f1501c --- /dev/null +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -0,0 +1,56 @@ +/* + * + * 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 "test/cpp/util/channel_trace_proto_helper.h" + +#include <google/protobuf/text_format.h> +#include <google/protobuf/util/json_util.h> + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <gtest/gtest.h> + +#include "src/proto/grpc/channelz/channelz.pb.h" + +namespace grpc { +namespace testing { + +void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { + std::string tracer_json_str(tracer_json_c_str); + grpc::channelz::ChannelTrace channel_trace; + google::protobuf::util::JsonParseOptions parse_options; + // If the following line is failing, then uncomment the last line of the + // comment, and uncomment the lines that print the two strings. You can + // then compare the output, and determine what fields are missing. + // + // options.ignore_unknown_fields = true; + ASSERT_EQ(google::protobuf::util::JsonStringToMessage( + tracer_json_str, &channel_trace, parse_options), + google::protobuf::util::Status::OK); + std::string proto_json_str; + ASSERT_EQ(google::protobuf::util::MessageToJsonString(channel_trace, + &proto_json_str), + google::protobuf::util::Status::OK); + // uncomment these to compare the the json strings. + // gpr_log(GPR_ERROR, "tracer json: %s", tracer_json_str.c_str()); + // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str()); + ASSERT_EQ(tracer_json_str, proto_json_str); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h new file mode 100644 index 0000000000..d7043d9f06 --- /dev/null +++ b/test/cpp/util/channel_trace_proto_helper.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H +#define GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H + +namespace grpc { +namespace testing { + +void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H diff --git a/test/distrib/php/run_distrib_test_macos.sh b/test/distrib/php/run_distrib_test_macos.sh new file mode 100755 index 0000000000..8def049860 --- /dev/null +++ b/test/distrib/php/run_distrib_test_macos.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# 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. + +set -ex + +cd "$(dirname "$0")" + +cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz . + +find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \ + xargs sudo pecl install + +php -d extension=grpc.so -d max_execution_time=300 distribtest.php |