aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/core/channel/BUILD29
-rw-r--r--test/core/channel/channel_trace_test.cc240
-rw-r--r--test/core/channel/status_util_test.cc (renamed from test/core/client_channel/status_util_test.cc)2
-rw-r--r--test/core/client_channel/BUILD12
-rw-r--r--test/core/end2end/BUILD17
-rw-r--r--test/core/end2end/fuzzers/BUILD2
-rw-r--r--test/core/end2end/h2_ssl_session_reuse_test.cc280
-rw-r--r--test/core/end2end/no_server_test.cc70
-rw-r--r--test/core/end2end/tests/bad_ping.cc164
-rw-r--r--test/core/end2end/tests/keepalive_timeout.cc2
-rw-r--r--test/core/gprpp/inlined_vector_test.cc7
-rw-r--r--test/core/security/security_connector_test.cc27
-rw-r--r--test/core/surface/public_headers_must_be_c89.c5
-rw-r--r--test/core/tsi/BUILD14
-rw-r--r--test/core/tsi/ssl_session_cache_test.cc154
-rw-r--r--test/core/tsi/ssl_transport_security_test.cc197
-rw-r--r--test/core/util/grpc_fuzzer.bzl4
-rw-r--r--test/cpp/common/alarm_test.cc16
-rw-r--r--test/cpp/end2end/async_end2end_test.cc45
-rw-r--r--test/cpp/end2end/nonblocking_test.cc2
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_trickle.cc2
-rw-r--r--test/cpp/microbenchmarks/fullstack_unary_ping_pong.h2
-rw-r--r--test/cpp/naming/address_sorting_test.cc737
-rwxr-xr-xtest/cpp/naming/gen_build_yaml.py19
-rwxr-xr-xtest/cpp/naming/generate_resolver_component_tests.bzl18
-rw-r--r--test/cpp/performance/writes_per_rpc_test.cc2
-rwxr-xr-xtest/cpp/qps/gen_build_yaml.py40
-rw-r--r--test/cpp/util/BUILD19
-rw-r--r--test/cpp/util/channel_trace_proto_helper.cc56
-rw-r--r--test/cpp/util/channel_trace_proto_helper.h30
-rwxr-xr-xtest/distrib/php/run_distrib_test_macos.sh25
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