aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/core/census/BUILD93
-rw-r--r--test/core/channel/BUILD54
-rw-r--r--test/core/channel/channel_stack_test.c2
-rw-r--r--test/core/client_channel/BUILD54
-rw-r--r--test/core/client_channel/parse_address_test.c116
-rw-r--r--test/core/client_channel/resolvers/BUILD51
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_connectivity_test.c41
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_test.c16
-rw-r--r--test/core/client_channel/resolvers/sockaddr_resolver_test.c21
-rw-r--r--test/core/client_channel/uri_fuzzer_test.c5
-rw-r--r--test/core/client_channel/uri_parser_test.c23
-rw-r--r--test/core/compression/BUILD66
-rw-r--r--test/core/end2end/BUILD4
-rw-r--r--test/core/end2end/bad_server_response_test.c10
-rw-r--r--test/core/end2end/end2end_nosec_tests.c8
-rw-r--r--test/core/end2end/end2end_tests.c8
-rw-r--r--test/core/end2end/fake_resolver.c2
-rw-r--r--test/core/end2end/fixtures/h2_http_proxy.c2
-rw-r--r--test/core/end2end/fixtures/http_proxy_fixture.c (renamed from test/core/end2end/fixtures/http_proxy.c)6
-rw-r--r--test/core/end2end/fixtures/http_proxy_fixture.h (renamed from test/core/end2end/fixtures/http_proxy.h)0
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960bin0 -> 405 bytes
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296bin0 -> 298 bytes
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448bin0 -> 384 bytes
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary2
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py3
-rwxr-xr-xtest/core/end2end/generate_tests.bzl1
-rw-r--r--test/core/end2end/goaway_server_test.c6
-rw-r--r--test/core/end2end/tests/filter_call_init_fails.c2
-rw-r--r--test/core/end2end/tests/filter_causes_close.c2
-rw-r--r--test/core/end2end/tests/filter_latency.c2
-rw-r--r--test/core/end2end/tests/keepalive_timeout.c240
-rw-r--r--test/core/end2end/tests/load_reporting_hook.c29
-rw-r--r--test/core/end2end/tests/network_status_change.c5
-rw-r--r--test/core/end2end/tests/streaming_error_response.c3
-rw-r--r--test/core/fling/BUILD62
-rw-r--r--test/core/fling/fling_stream_test.c81
-rw-r--r--test/core/handshake/BUILD64
-rw-r--r--test/core/handshake/client_ssl.c38
-rw-r--r--test/core/http/BUILD55
-rw-r--r--test/core/http/httpcli_test.c4
-rw-r--r--test/core/http/httpscli_test.c4
-rw-r--r--test/core/internal_api_canaries/iomgr.c119
-rw-r--r--test/core/internal_api_canaries/transport.c81
-rw-r--r--test/core/iomgr/BUILD181
-rw-r--r--test/core/iomgr/combiner_test.c8
-rw-r--r--test/core/iomgr/endpoint_pair_test.c2
-rw-r--r--test/core/iomgr/error_test.c219
-rw-r--r--test/core/iomgr/ev_epoll_linux_test.c2
-rw-r--r--test/core/iomgr/fd_posix_test.c2
-rw-r--r--test/core/iomgr/pollset_set_test.c13
-rw-r--r--test/core/iomgr/resolve_address_posix_test.c4
-rw-r--r--test/core/iomgr/resolve_address_test.c57
-rw-r--r--test/core/iomgr/sockaddr_utils_test.c16
-rw-r--r--test/core/iomgr/tcp_client_posix_test.c15
-rw-r--r--test/core/iomgr/tcp_client_uv_test.c223
-rw-r--r--test/core/iomgr/tcp_posix_test.c2
-rw-r--r--test/core/iomgr/tcp_server_posix_test.c299
-rw-r--r--test/core/iomgr/tcp_server_uv_test.c339
-rw-r--r--test/core/iomgr/timer_list_test.c11
-rw-r--r--test/core/iomgr/udp_server_test.c2
-rw-r--r--test/core/json/BUILD31
-rw-r--r--test/core/memory_usage/client.c24
-rw-r--r--test/core/network_benchmarks/BUILD37
-rw-r--r--test/core/security/BUILD104
-rw-r--r--test/core/security/jwt_verifier_test.c16
-rw-r--r--test/core/security/oauth2_utils.c2
-rw-r--r--test/core/security/print_google_default_creds_token.c2
-rw-r--r--test/core/security/secure_endpoint_test.c2
-rw-r--r--test/core/security/verify_jwt.c7
-rw-r--r--test/core/slice/BUILD54
-rw-r--r--test/core/slice/percent_encoding_test.c1
-rw-r--r--test/core/support/BUILD9
-rw-r--r--test/core/support/alloc_test.c2
-rw-r--r--test/core/support/spinlock_test.c161
-rw-r--r--test/core/surface/BUILD188
-rw-r--r--test/core/surface/completion_queue_test.c223
-rw-r--r--test/core/surface/completion_queue_threading_test.c290
-rw-r--r--test/core/surface/concurrent_connectivity_test.c2
-rw-r--r--test/core/surface/public_headers_must_be_c89.c1
-rw-r--r--test/core/transport/BUILD79
-rw-r--r--test/core/transport/chttp2/BUILD55
-rw-r--r--test/core/transport/connectivity_state_test.c3
-rw-r--r--test/core/transport/stream_owned_slice_test.c (renamed from test/core/internal_api_canaries/support.c)42
-rw-r--r--test/core/tsi/BUILD37
-rw-r--r--test/core/util/BUILD3
-rw-r--r--test/core/util/memory_counters.c54
-rw-r--r--test/core/util/memory_counters.h10
-rw-r--r--test/core/util/mock_endpoint.c6
-rw-r--r--test/core/util/passthru_endpoint.c6
-rw-r--r--test/core/util/port.c (renamed from test/core/util/port_uv.c)52
-rw-r--r--test/core/util/port_posix.c256
-rw-r--r--test/core/util/port_server_client.c27
-rw-r--r--test/core/util/port_server_client.h7
-rw-r--r--test/core/util/port_windows.c247
-rw-r--r--test/core/util/test_config.c16
-rw-r--r--test/core/util/test_tcp_server.c2
-rw-r--r--test/core/util/trickle_endpoint.c195
-rw-r--r--test/core/util/trickle_endpoint.h46
-rw-r--r--test/cpp/codegen/BUILD77
-rw-r--r--test/cpp/codegen/compiler_test_golden2
-rw-r--r--test/cpp/codegen/golden_file_test.cc12
-rw-r--r--test/cpp/common/BUILD36
-rw-r--r--test/cpp/common/channel_filter_test.cc2
-rw-r--r--test/cpp/end2end/BUILD323
-rw-r--r--test/cpp/end2end/end2end_test.cc3
-rw-r--r--test/cpp/end2end/health_service_end2end_test.cc323
-rw-r--r--test/cpp/end2end/test_service_impl.cc4
-rw-r--r--test/cpp/interop/client.cc2
-rw-r--r--test/cpp/interop/http2_client.cc104
-rw-r--r--test/cpp/interop/http2_client.h3
-rw-r--r--test/cpp/interop/reconnect_interop_client.cc2
-rw-r--r--test/cpp/microbenchmarks/bm_call_create.cc463
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_hpack.cc449
-rw-r--r--test/cpp/microbenchmarks/bm_closure.cc444
-rw-r--r--test/cpp/microbenchmarks/bm_cq.cc150
-rw-r--r--test/cpp/microbenchmarks/bm_error.cc312
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack.cc898
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc197
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc197
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_trickle.cc219
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc205
-rw-r--r--test/cpp/microbenchmarks/bm_metadata.cc332
-rw-r--r--test/cpp/microbenchmarks/bm_pollset.cc254
-rw-r--r--test/cpp/microbenchmarks/fullstack_context_mutators.h158
-rw-r--r--test/cpp/microbenchmarks/fullstack_fixtures.h244
-rw-r--r--test/cpp/microbenchmarks/helpers.cc (renamed from test/cpp/qps/qps_test_with_poll.cc)78
-rw-r--r--test/cpp/microbenchmarks/helpers.h93
-rw-r--r--test/cpp/microbenchmarks/representative_server_initial_metadata.headers4
-rw-r--r--test/cpp/microbenchmarks/representative_server_trailing_metadata.headers3
-rw-r--r--test/cpp/qps/client_async.cc4
-rw-r--r--test/cpp/qps/client_sync.cc15
-rw-r--r--test/cpp/qps/server_sync.cc4
-rw-r--r--test/cpp/server/server_builder_test.cc96
-rw-r--r--test/cpp/util/BUILD85
134 files changed, 8591 insertions, 2285 deletions
diff --git a/test/core/census/BUILD b/test/core/census/BUILD
new file mode 100644
index 0000000000..49680ab91f
--- /dev/null
+++ b/test/core/census/BUILD
@@ -0,0 +1,93 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "context_test",
+ srcs = ["context_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "mlog_test",
+ srcs = ["mlog_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "resource_test",
+ srcs = ["resource_test.c"],
+ copts = ["-std=c99"],
+ data = [
+ ":data/resource_empty_name.pb",
+ ":data/resource_full.pb",
+ ":data/resource_minimal_good.pb",
+ ":data/resource_no_name.pb",
+ ":data/resource_no_numerator.pb",
+ ":data/resource_no_unit.pb",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "trace_context_test",
+ srcs = ["trace_context_test.c"],
+ copts = ["-std=c99"],
+ data = [
+ ":data/context_empty.pb",
+ ":data/context_full.pb",
+ ":data/context_no_span_options.pb",
+ ":data/context_span_only.pb",
+ ":data/context_trace_only.pb",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
new file mode 100644
index 0000000000..c6590465f1
--- /dev/null
+++ b/test/core/channel/BUILD
@@ -0,0 +1,54 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "channel_args_test",
+ srcs = ["channel_args_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "channel_stack_test",
+ srcs = ["channel_stack_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index dd9c544524..76bb57346c 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -57,7 +57,7 @@ static grpc_error *channel_init_func(grpc_exec_ctx *exec_ctx,
static grpc_error *call_init_func(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_call_element_args *args) {
+ const grpc_call_element_args *args) {
++*(int *)(elem->channel_data);
*(int *)(elem->call_data) = 0;
return GRPC_ERROR_NONE;
diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD
new file mode 100644
index 0000000000..a29e9aca4e
--- /dev/null
+++ b/test/core/client_channel/BUILD
@@ -0,0 +1,54 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+grpc_fuzzer(
+ name = "uri_fuzzer_test",
+ srcs = ["uri_fuzzer_test.c"],
+ deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+ corpus = "uri_corpus",
+ copts = ["-std=c99"],
+)
+
+cc_test(
+ name = "lb_policies_test",
+ srcs = ["lb_policies_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:cq_verifier"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "set_initial_connect_string_test",
+ srcs = ["set_initial_connect_string_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/client_channel/parse_address_test.c b/test/core/client_channel/parse_address_test.c
new file mode 100644
index 0000000000..37dd0fba52
--- /dev/null
+++ b/test/core/client_channel/parse_address_test.c
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/client_channel/parse_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include <string.h>
+#ifdef GRPC_HAVE_UNIX_SOCKET
+#include <sys/un.h>
+#endif
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/socket_utils.h"
+#include "test/core/util/test_config.h"
+
+#ifdef GRPC_HAVE_UNIX_SOCKET
+
+static void test_parse_unix(const char *uri_text, const char *pathname) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
+ grpc_resolved_address addr;
+
+ GPR_ASSERT(1 == parse_unix(uri, &addr));
+ struct sockaddr_un *addr_un = (struct sockaddr_un *)addr.addr;
+ GPR_ASSERT(AF_UNIX == addr_un->sun_family);
+ GPR_ASSERT(0 == strcmp(addr_un->sun_path, pathname));
+
+ grpc_uri_destroy(uri);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+#else /* GRPC_HAVE_UNIX_SOCKET */
+
+static void test_parse_unix(const char *uri_text, const char *pathname) {}
+
+#endif /* GRPC_HAVE_UNIX_SOCKET */
+
+static void test_parse_ipv4(const char *uri_text, const char *host,
+ unsigned short port) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
+ grpc_resolved_address addr;
+ char ntop_buf[INET_ADDRSTRLEN];
+
+ GPR_ASSERT(1 == parse_ipv4(uri, &addr));
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)addr.addr;
+ GPR_ASSERT(AF_INET == addr_in->sin_family);
+ GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET, &addr_in->sin_addr, ntop_buf,
+ sizeof(ntop_buf)));
+ GPR_ASSERT(0 == strcmp(ntop_buf, host));
+ GPR_ASSERT(ntohs(addr_in->sin_port) == port);
+
+ grpc_uri_destroy(uri);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_parse_ipv6(const char *uri_text, const char *host,
+ unsigned short port, uint32_t scope_id) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
+ grpc_resolved_address addr;
+ char ntop_buf[INET6_ADDRSTRLEN];
+
+ GPR_ASSERT(1 == parse_ipv6(uri, &addr));
+ struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr.addr;
+ GPR_ASSERT(AF_INET6 == addr_in6->sin6_family);
+ GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET6, &addr_in6->sin6_addr, ntop_buf,
+ sizeof(ntop_buf)));
+ GPR_ASSERT(0 == strcmp(ntop_buf, host));
+ GPR_ASSERT(ntohs(addr_in6->sin6_port) == port);
+ GPR_ASSERT(addr_in6->sin6_scope_id == scope_id);
+
+ grpc_uri_destroy(uri);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+
+ test_parse_unix("unix:/path/name", "/path/name");
+ test_parse_ipv4("ipv4:192.0.2.1:12345", "192.0.2.1", 12345);
+ test_parse_ipv6("ipv6:[2001:db8::1]:12345", "2001:db8::1", 12345, 0);
+ test_parse_ipv6("ipv6:[2001:db8::1%252]:12345", "2001:db8::1", 12345, 2);
+}
diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD
new file mode 100644
index 0000000000..af37072e3a
--- /dev/null
+++ b/test/core/client_channel/resolvers/BUILD
@@ -0,0 +1,51 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "dns_resolver_connectivity_test",
+ srcs = ["dns_resolver_connectivity_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "dns_resolver_test",
+ srcs = ["dns_resolver_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "sockaddr_resolver_test",
+ srcs = ["sockaddr_resolver_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
index cfd37052de..187757d5b3 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
@@ -36,14 +36,17 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
+#include "src/core/ext/client_channel/resolver.h"
#include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
#include "test/core/util/test_config.h"
static gpr_mu g_mu;
static bool g_fail_resolution = true;
+static grpc_combiner *g_combiner;
static grpc_error *my_resolve_address(const char *name, const char *addr,
grpc_resolved_addresses **addrs) {
@@ -66,11 +69,12 @@ static grpc_error *my_resolve_address(const char *name, const char *addr,
static grpc_resolver *create_resolver(grpc_exec_ctx *exec_ctx,
const char *name) {
grpc_resolver_factory *factory = grpc_resolver_factory_lookup("dns");
- grpc_uri *uri = grpc_uri_parse(name, 0);
+ grpc_uri *uri = grpc_uri_parse(exec_ctx, name, 0);
GPR_ASSERT(uri);
grpc_resolver_args args;
memset(&args, 0, sizeof(args));
args.uri = uri;
+ args.combiner = g_combiner;
grpc_resolver *resolver =
grpc_resolver_factory_create_resolver(exec_ctx, factory, &args);
grpc_resolver_factory_unref(factory);
@@ -96,11 +100,41 @@ static bool wait_loop(int deadline_seconds, gpr_event *ev) {
return false;
}
+typedef struct next_args {
+ grpc_resolver *resolver;
+ grpc_channel_args **result;
+ grpc_closure *on_complete;
+} next_args;
+
+static void call_resolver_next_now_lock_taken(grpc_exec_ctx *exec_ctx,
+ void *arg,
+ grpc_error *error_unused) {
+ next_args *a = arg;
+ grpc_resolver_next_locked(exec_ctx, a->resolver, a->result, a->on_complete);
+ gpr_free(a);
+}
+
+static void call_resolver_next_after_locking(grpc_exec_ctx *exec_ctx,
+ grpc_resolver *resolver,
+ grpc_channel_args **result,
+ grpc_closure *on_complete) {
+ next_args *a = gpr_malloc(sizeof(*a));
+ a->resolver = resolver;
+ a->result = result;
+ a->on_complete = on_complete;
+ grpc_closure_sched(
+ exec_ctx,
+ grpc_closure_create(call_resolver_next_now_lock_taken, a,
+ grpc_combiner_scheduler(resolver->combiner, false)),
+ GRPC_ERROR_NONE);
+}
+
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
gpr_mu_init(&g_mu);
+ g_combiner = grpc_combiner_create(NULL);
grpc_blocking_resolve_address = my_resolve_address;
grpc_channel_args *result = (grpc_channel_args *)1;
@@ -108,7 +142,7 @@ int main(int argc, char **argv) {
grpc_resolver *resolver = create_resolver(&exec_ctx, "dns:test");
gpr_event ev1;
gpr_event_init(&ev1);
- grpc_resolver_next(
+ call_resolver_next_after_locking(
&exec_ctx, resolver, &result,
grpc_closure_create(on_done, &ev1, grpc_schedule_on_exec_ctx));
grpc_exec_ctx_flush(&exec_ctx);
@@ -117,7 +151,7 @@ int main(int argc, char **argv) {
gpr_event ev2;
gpr_event_init(&ev2);
- grpc_resolver_next(
+ call_resolver_next_after_locking(
&exec_ctx, resolver, &result,
grpc_closure_create(on_done, &ev2, grpc_schedule_on_exec_ctx));
grpc_exec_ctx_flush(&exec_ctx);
@@ -126,6 +160,7 @@ int main(int argc, char **argv) {
grpc_channel_args_destroy(&exec_ctx, result);
GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test");
+ GRPC_COMBINER_UNREF(&exec_ctx, g_combiner, "test");
grpc_exec_ctx_finish(&exec_ctx);
grpc_shutdown();
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.c b/test/core/client_channel/resolvers/dns_resolver_test.c
index 5603a57b5f..919a85d58f 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_test.c
@@ -36,11 +36,14 @@
#include <grpc/support/log.h>
#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "test/core/util/test_config.h"
+static grpc_combiner *g_combiner;
+
static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_uri *uri = grpc_uri_parse(string, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, string, 0);
grpc_resolver_args args;
grpc_resolver *resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
@@ -48,6 +51,7 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
args.uri = uri;
+ args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
GPR_ASSERT(resolver != NULL);
GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds");
@@ -57,7 +61,7 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
static void test_fails(grpc_resolver_factory *factory, const char *string) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_uri *uri = grpc_uri_parse(string, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, string, 0);
grpc_resolver_args args;
grpc_resolver *resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
@@ -65,6 +69,7 @@ static void test_fails(grpc_resolver_factory *factory, const char *string) {
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
args.uri = uri;
+ args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
GPR_ASSERT(resolver == NULL);
grpc_uri_destroy(uri);
@@ -76,6 +81,8 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
+ g_combiner = grpc_combiner_create(NULL);
+
dns = grpc_resolver_factory_lookup("dns");
test_succeeds(dns, "dns:10.2.1.1");
@@ -84,6 +91,11 @@ int main(int argc, char **argv) {
test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
grpc_resolver_factory_unref(dns);
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_COMBINER_UNREF(&exec_ctx, g_combiner, "test");
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
grpc_shutdown();
return 0;
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.c b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
index 10df78537c..bc4f02c339 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.c
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
@@ -39,9 +39,12 @@
#include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "test/core/util/test_config.h"
+static grpc_combiner *g_combiner;
+
typedef struct on_resolution_arg {
char *expected_server_name;
grpc_channel_args *resolver_result;
@@ -54,7 +57,7 @@ void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_uri *uri = grpc_uri_parse(string, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, string, 0);
grpc_resolver_args args;
grpc_resolver *resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
@@ -62,6 +65,7 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
args.uri = uri;
+ args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
GPR_ASSERT(resolver != NULL);
@@ -71,8 +75,8 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
grpc_closure *on_resolution = grpc_closure_create(
on_resolution_cb, &on_res_arg, grpc_schedule_on_exec_ctx);
- grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result,
- on_resolution);
+ grpc_resolver_next_locked(&exec_ctx, resolver, &on_res_arg.resolver_result,
+ on_resolution);
GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds");
grpc_exec_ctx_finish(&exec_ctx);
grpc_uri_destroy(uri);
@@ -80,7 +84,7 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
static void test_fails(grpc_resolver_factory *factory, const char *string) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_uri *uri = grpc_uri_parse(string, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, string, 0);
grpc_resolver_args args;
grpc_resolver *resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
@@ -88,6 +92,7 @@ static void test_fails(grpc_resolver_factory *factory, const char *string) {
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
args.uri = uri;
+ args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
GPR_ASSERT(resolver == NULL);
grpc_uri_destroy(uri);
@@ -99,6 +104,8 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
+ g_combiner = grpc_combiner_create(NULL);
+
ipv4 = grpc_resolver_factory_lookup("ipv4");
ipv6 = grpc_resolver_factory_lookup("ipv6");
@@ -118,6 +125,12 @@ int main(int argc, char **argv) {
grpc_resolver_factory_unref(ipv4);
grpc_resolver_factory_unref(ipv6);
+
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_COMBINER_UNREF(&exec_ctx, g_combiner, "test");
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
grpc_shutdown();
return 0;
diff --git a/test/core/client_channel/uri_fuzzer_test.c b/test/core/client_channel/uri_fuzzer_test.c
index d2e3fb40ea..baadd4fc65 100644
--- a/test/core/client_channel/uri_fuzzer_test.c
+++ b/test/core/client_channel/uri_fuzzer_test.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
bool squelch = true;
bool leak_check = true;
@@ -47,10 +48,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy(s, data, size);
s[size] = 0;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_uri *x;
- if ((x = grpc_uri_parse(s, 1))) {
+ if ((x = grpc_uri_parse(&exec_ctx, s, 1))) {
grpc_uri_destroy(x);
}
+ grpc_exec_ctx_finish(&exec_ctx);
gpr_free(s);
return 0;
}
diff --git a/test/core/client_channel/uri_parser_test.c b/test/core/client_channel/uri_parser_test.c
index 5f32d3270c..8a127f72eb 100644
--- a/test/core/client_channel/uri_parser_test.c
+++ b/test/core/client_channel/uri_parser_test.c
@@ -37,29 +37,35 @@
#include <grpc/support/log.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
#include "test/core/util/test_config.h"
static void test_succeeds(const char *uri_text, const char *scheme,
const char *authority, const char *path,
const char *query, const char *fragment) {
- grpc_uri *uri = grpc_uri_parse(uri_text, 0);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp(scheme, uri->scheme));
GPR_ASSERT(0 == strcmp(authority, uri->authority));
GPR_ASSERT(0 == strcmp(path, uri->path));
GPR_ASSERT(0 == strcmp(query, uri->query));
GPR_ASSERT(0 == strcmp(fragment, uri->fragment));
+ grpc_exec_ctx_finish(&exec_ctx);
grpc_uri_destroy(uri);
}
static void test_fails(const char *uri_text) {
- GPR_ASSERT(NULL == grpc_uri_parse(uri_text, 0));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GPR_ASSERT(NULL == grpc_uri_parse(&exec_ctx, uri_text, 0));
+ grpc_exec_ctx_finish(&exec_ctx);
}
static void test_query_parts() {
{
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
const char *uri_text = "http://foo/path?a&b=B&c=&#frag";
- grpc_uri *uri = grpc_uri_parse(uri_text, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp("http", uri->scheme));
@@ -86,12 +92,14 @@ static void test_query_parts() {
GPR_ASSERT(NULL == grpc_uri_get_query_arg(uri, ""));
GPR_ASSERT(0 == strcmp("frag", uri->fragment));
+ grpc_exec_ctx_finish(&exec_ctx);
grpc_uri_destroy(uri);
}
{
/* test the current behavior of multiple query part values */
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
const char *uri_text = "http://auth/path?foo=bar=baz&foobar==";
- grpc_uri *uri = grpc_uri_parse(uri_text, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp("http", uri->scheme));
@@ -103,12 +111,14 @@ static void test_query_parts() {
GPR_ASSERT(0 == strcmp("bar", grpc_uri_get_query_arg(uri, "foo")));
GPR_ASSERT(0 == strcmp("", grpc_uri_get_query_arg(uri, "foobar")));
+ grpc_exec_ctx_finish(&exec_ctx);
grpc_uri_destroy(uri);
}
{
/* empty query */
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
const char *uri_text = "http://foo/path";
- grpc_uri *uri = grpc_uri_parse(uri_text, 0);
+ grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp("http", uri->scheme));
@@ -119,6 +129,7 @@ static void test_query_parts() {
GPR_ASSERT(NULL == uri->query_parts);
GPR_ASSERT(NULL == uri->query_parts_values);
GPR_ASSERT(0 == strcmp("", uri->fragment));
+ grpc_exec_ctx_finish(&exec_ctx);
grpc_uri_destroy(uri);
}
}
@@ -142,6 +153,8 @@ int main(int argc, char **argv) {
test_succeeds("http:?legit#twice", "http", "", "", "legit", "twice");
test_succeeds("http://foo?bar#lol?", "http", "foo", "", "bar", "lol?");
test_succeeds("http://foo?bar#lol?/", "http", "foo", "", "bar", "lol?/");
+ test_succeeds("ipv6:[2001:db8::1%252]:12345", "ipv6", "",
+ "[2001:db8::1%2]:12345", "", "");
test_fails("xyz");
test_fails("http:?dangling-pct-%0");
diff --git a/test/core/compression/BUILD b/test/core/compression/BUILD
new file mode 100644
index 0000000000..9ddb4c52b4
--- /dev/null
+++ b/test/core/compression/BUILD
@@ -0,0 +1,66 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "algorithm_test",
+ srcs = ["algorithm_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "compression_test",
+ srcs = ["compression_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "message_compress_test",
+ srcs = ["message_compress_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
index a40fb8e083..0cef7aa01d 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -63,8 +63,8 @@ cc_library(
cc_library(
name = 'http_proxy',
- hdrs = ['fixtures/http_proxy.h'],
- srcs = ['fixtures/http_proxy.c'],
+ hdrs = ['fixtures/http_proxy_fixture.h'],
+ srcs = ['fixtures/http_proxy_fixture.c'],
copts = ['-std=c99'],
deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
)
diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c
index 42d960c428..39a98e84ca 100644
--- a/test/core/end2end/bad_server_response_test.c
+++ b/test/core/end2end/bad_server_response_test.c
@@ -82,7 +82,9 @@
#define HTTP1_DETAIL_MSG "Trying to connect an http1.x server"
/* TODO(zyc) Check the content of incomming data instead of using this length */
-#define EXPECTED_INCOMING_DATA_LENGTH (size_t)310
+/* The 'bad' server will start sending responses after reading this amount of
+ * data from the client. */
+#define SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD (size_t)200
struct rpc_state {
char *target;
@@ -134,8 +136,10 @@ static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
}
gpr_log(GPR_DEBUG, "got %" PRIuPTR " bytes, expected %" PRIuPTR " bytes",
- state.incoming_data_length, EXPECTED_INCOMING_DATA_LENGTH);
- if (state.incoming_data_length >= EXPECTED_INCOMING_DATA_LENGTH) {
+ state.incoming_data_length,
+ SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD);
+ if (state.incoming_data_length >=
+ SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD) {
handle_write(exec_ctx);
} else {
grpc_endpoint_read(exec_ctx, state.tcp, &state.temp_incoming_buffer,
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index fdfa31b5fb..b351bdee27 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -89,6 +89,8 @@ extern void idempotent_request(grpc_end2end_test_config config);
extern void idempotent_request_pre_init(void);
extern void invoke_large_request(grpc_end2end_test_config config);
extern void invoke_large_request_pre_init(void);
+extern void keepalive_timeout(grpc_end2end_test_config config);
+extern void keepalive_timeout_pre_init(void);
extern void large_metadata(grpc_end2end_test_config config);
extern void large_metadata_pre_init(void);
extern void load_reporting_hook(grpc_end2end_test_config config);
@@ -168,6 +170,7 @@ void grpc_end2end_tests_pre_init(void) {
hpack_size_pre_init();
idempotent_request_pre_init();
invoke_large_request_pre_init();
+ keepalive_timeout_pre_init();
large_metadata_pre_init();
load_reporting_hook_pre_init();
max_concurrent_streams_pre_init();
@@ -225,6 +228,7 @@ void grpc_end2end_tests(int argc, char **argv,
hpack_size(config);
idempotent_request(config);
invoke_large_request(config);
+ keepalive_timeout(config);
large_metadata(config);
load_reporting_hook(config);
max_concurrent_streams(config);
@@ -343,6 +347,10 @@ void grpc_end2end_tests(int argc, char **argv,
invoke_large_request(config);
continue;
}
+ if (0 == strcmp("keepalive_timeout", argv[i])) {
+ keepalive_timeout(config);
+ continue;
+ }
if (0 == strcmp("large_metadata", argv[i])) {
large_metadata(config);
continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index f529d6a899..199c09ec96 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -91,6 +91,8 @@ extern void idempotent_request(grpc_end2end_test_config config);
extern void idempotent_request_pre_init(void);
extern void invoke_large_request(grpc_end2end_test_config config);
extern void invoke_large_request_pre_init(void);
+extern void keepalive_timeout(grpc_end2end_test_config config);
+extern void keepalive_timeout_pre_init(void);
extern void large_metadata(grpc_end2end_test_config config);
extern void large_metadata_pre_init(void);
extern void load_reporting_hook(grpc_end2end_test_config config);
@@ -171,6 +173,7 @@ void grpc_end2end_tests_pre_init(void) {
hpack_size_pre_init();
idempotent_request_pre_init();
invoke_large_request_pre_init();
+ keepalive_timeout_pre_init();
large_metadata_pre_init();
load_reporting_hook_pre_init();
max_concurrent_streams_pre_init();
@@ -229,6 +232,7 @@ void grpc_end2end_tests(int argc, char **argv,
hpack_size(config);
idempotent_request(config);
invoke_large_request(config);
+ keepalive_timeout(config);
large_metadata(config);
load_reporting_hook(config);
max_concurrent_streams(config);
@@ -351,6 +355,10 @@ void grpc_end2end_tests(int argc, char **argv,
invoke_large_request(config);
continue;
}
+ if (0 == strcmp("keepalive_timeout", argv[i])) {
+ keepalive_timeout(config);
+ continue;
+ }
if (0 == strcmp("large_metadata", argv[i])) {
large_metadata(config);
continue;
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 4f05f69f01..8a37531449 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -213,7 +213,7 @@ static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx,
r->channel_args = grpc_channel_args_copy(args->args);
r->addresses = addresses;
gpr_mu_init(&r->mu);
- grpc_resolver_init(&r->base, &fake_resolver_vtable);
+ grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner);
return &r->base;
}
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
index 44b223664a..55c65fa70e 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.c
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -49,7 +49,7 @@
#include "src/core/lib/support/env.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/server.h"
-#include "test/core/end2end/fixtures/http_proxy.h"
+#include "test/core/end2end/fixtures/http_proxy_fixture.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy_fixture.c
index 6fdc86fc12..bcd1c9914b 100644
--- a/test/core/end2end/fixtures/http_proxy.c
+++ b/test/core/end2end/fixtures/http_proxy_fixture.c
@@ -31,7 +31,7 @@
*
*/
-#include "test/core/end2end/fixtures/http_proxy.h"
+#include "test/core/end2end/fixtures/http_proxy_fixture.h"
#include "src/core/lib/iomgr/sockaddr.h"
@@ -110,7 +110,7 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
grpc_endpoint_destroy(exec_ctx, conn->client_endpoint);
if (conn->server_endpoint != NULL)
grpc_endpoint_destroy(exec_ctx, conn->server_endpoint);
- grpc_pollset_set_destroy(conn->pollset_set);
+ grpc_pollset_set_destroy(exec_ctx, conn->pollset_set);
grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx,
&conn->client_deferred_write_buffer);
@@ -454,7 +454,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) {
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(port == proxy_port);
// Start server.
- proxy->pollset = gpr_malloc(grpc_pollset_size());
+ proxy->pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(proxy->pollset, &proxy->mu);
grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1, on_accept,
proxy);
diff --git a/test/core/end2end/fixtures/http_proxy.h b/test/core/end2end/fixtures/http_proxy_fixture.h
index cd47b432af..cd47b432af 100644
--- a/test/core/end2end/fixtures/http_proxy.h
+++ b/test/core/end2end/fixtures/http_proxy_fixture.h
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960
new file mode 100644
index 0000000000..70ca3a336e
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296
new file mode 100644
index 0000000000..65cc6a2209
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448
new file mode 100644
index 0000000000..49c02c2f12
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448
Binary files differ
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 81a2419d12..6b96785419 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -15,7 +15,6 @@
"\x0Auser-agent"
"\x04host"
"\x08lb-token"
-"\x0Blb-cost-bin"
"\x0Cgrpc-timeout"
"\x10grpc-tracing-bin"
"\x0Egrpc-stats-bin"
@@ -153,7 +152,6 @@
"\x00\x13if-unmodified-since\x00"
"\x00\x0Dlast-modified\x00"
"\x00\x08lb-token\x00"
-"\x00\x0Blb-cost-bin\x00"
"\x00\x04link\x00"
"\x00\x08location\x00"
"\x00\x0Cmax-forwards\x00"
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index bcb7136eaa..0c749537e6 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -91,6 +91,7 @@ LOWCPU = 0.1
# maps test names to options
END2END_TESTS = {
+ 'authority_not_supported': default_test_options,
'bad_hostname': default_test_options,
'binary_metadata': default_test_options,
'resource_quota_server': default_test_options._replace(large_writes=True,
@@ -118,6 +119,7 @@ END2END_TESTS = {
'high_initial_seqno': default_test_options,
'idempotent_request': default_test_options,
'invoke_large_request': default_test_options,
+ 'keepalive_timeout': default_test_options._replace(proxyable=False),
'large_metadata': default_test_options,
'max_concurrent_streams': default_test_options._replace(proxyable=False),
'max_message_length': default_test_options,
@@ -142,7 +144,6 @@ END2END_TESTS = {
'simple_request': default_test_options,
'streaming_error_response': default_test_options,
'trailing_metadata': default_test_options,
- 'authority_not_supported': default_test_options,
'write_buffering': default_test_options,
'write_buffering_at_end': default_test_options,
}
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 95c06de73f..431c6995ba 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -106,6 +106,7 @@ END2END_TESTS = {
'high_initial_seqno': test_options(),
'idempotent_request': test_options(),
'invoke_large_request': test_options(),
+ 'keepalive_timeout': test_options(proxyable=False),
'large_metadata': test_options(),
'max_concurrent_streams': test_options(proxyable=False),
'max_message_length': test_options(),
diff --git a/test/core/end2end/goaway_server_test.c b/test/core/end2end/goaway_server_test.c
index c67c1f145a..a9634bfbae 100644
--- a/test/core/end2end/goaway_server_test.c
+++ b/test/core/end2end/goaway_server_test.c
@@ -31,6 +31,12 @@
*
*/
+/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+ using that endpoint. Because of various transitive includes in uv.h,
+ including windows.h on Windows, uv.h must be included before other system
+ headers. Therefore, sockaddr.h must always be included first */
+#include "src/core/lib/iomgr/sockaddr.h"
+
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index 7e189164b2..d2d6e82d57 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -205,7 +205,7 @@ static void test_request(grpc_end2end_test_config config) {
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_call_element_args *args) {
+ const grpc_call_element_args *args) {
return grpc_error_set_int(GRPC_ERROR_CREATE("access denied"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_PERMISSION_DENIED);
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index 308b4de71b..25e606556d 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -230,7 +230,7 @@ static void start_transport_stream_op(grpc_exec_ctx *exec_ctx,
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_call_element_args *args) {
+ const grpc_call_element_args *args) {
return GRPC_ERROR_NONE;
}
diff --git a/test/core/end2end/tests/filter_latency.c b/test/core/end2end/tests/filter_latency.c
index 13d2ae012c..d05e9e79a1 100644
--- a/test/core/end2end/tests/filter_latency.c
+++ b/test/core/end2end/tests/filter_latency.c
@@ -260,7 +260,7 @@ static void test_request(grpc_end2end_test_config config) {
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_call_element_args *args) {
+ const grpc_call_element_args *args) {
return GRPC_ERROR_NONE;
}
diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c
new file mode 100644
index 0000000000..4296be3619
--- /dev/null
+++ b/test/core/end2end/tests/keepalive_timeout.c
@@ -0,0 +1,240 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/support/env.h"
+#include "test/core/end2end/cq_verifier.h"
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+ const char *test_name,
+ grpc_channel_args *client_args,
+ grpc_channel_args *server_args) {
+ grpc_end2end_test_fixture f;
+ gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+ f = config.create_fixture(client_args, server_args);
+ config.init_server(&f, server_args);
+ config.init_client(&f, client_args);
+ return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+ return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+ grpc_event ev;
+ do {
+ ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+ } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+ if (!f->server) return;
+ grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+ GPR_ASSERT(
+ grpc_completion_queue_pluck(f->cq, tag(1000), five_seconds_time(), NULL)
+ .type == GRPC_OP_COMPLETE);
+ grpc_server_destroy(f->server);
+ f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+ if (!f->client) return;
+ grpc_channel_destroy(f->client);
+ f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+ shutdown_server(f);
+ shutdown_client(f);
+
+ grpc_completion_queue_shutdown(f->cq);
+ drain_cq(f->cq);
+ grpc_completion_queue_destroy(f->cq);
+}
+
+/* Client sends a request, server replies with a payload, then waits for the
+ keepalive watchdog timeouts before returning status. */
+static void test_keepalive_timeout(grpc_end2end_test_config config) {
+ grpc_call *c;
+ grpc_call *s;
+ grpc_slice response_payload_slice =
+ grpc_slice_from_copied_string("hello world");
+ grpc_byte_buffer *response_payload =
+ grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+ gpr_timespec deadline = five_seconds_time();
+
+ grpc_arg keepalive_args[2];
+ keepalive_args[0].type = GRPC_ARG_INTEGER;
+ keepalive_args[0].key = GRPC_ARG_HTTP2_KEEPALIVE_TIME;
+ keepalive_args[0].value.integer = 2;
+ keepalive_args[1].type = GRPC_ARG_INTEGER;
+ keepalive_args[1].key = GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT;
+ keepalive_args[1].value.integer = 0;
+
+ grpc_channel_args *client_args = NULL;
+ client_args = grpc_channel_args_copy_and_add(client_args, keepalive_args, 2);
+
+ grpc_end2end_test_fixture f =
+ begin_test(config, "keepalive_timeout", client_args, NULL);
+ cq_verifier *cqv = cq_verifier_create(f.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_byte_buffer *response_payload_recv = NULL;
+ grpc_call_details call_details;
+ grpc_status_code status;
+ grpc_call_error error;
+ grpc_slice details;
+
+ c = grpc_channel_create_call(
+ f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+ grpc_slice_from_static_string("/foo"),
+ get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+ NULL);
+ 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++;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op++;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+ op++;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message.recv_message = &response_payload_recv;
+ op++;
+ error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+ f.server, &s, &call_details,
+ &request_metadata_recv, f.cq, f.cq, tag(101)));
+ CQ_EXPECT_COMPLETION(cqv, tag(101), 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++;
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message.send_message = response_payload;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+ cq_verify(cqv);
+
+ CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+ cq_verify(cqv);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ 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++;
+ error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+ cq_verify(cqv);
+
+ char *details_str = grpc_slice_to_c_string(details);
+ char *method_str = grpc_slice_to_c_string(call_details.method);
+ GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+ GPR_ASSERT(0 == grpc_slice_str_cmp(details, "keepalive watchdog timeout"));
+ GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+ validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+ config);
+
+ gpr_free(details_str);
+ gpr_free(method_str);
+
+ 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_destroy(c);
+ grpc_call_destroy(s);
+
+ cq_verifier_destroy(cqv);
+
+ grpc_byte_buffer_destroy(response_payload);
+ grpc_byte_buffer_destroy(response_payload_recv);
+
+ if (client_args != NULL) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_channel_args_destroy(&exec_ctx, client_args);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
+void keepalive_timeout(grpc_end2end_test_config config) {
+ test_keepalive_timeout(config);
+}
+
+void keepalive_timeout_pre_init(void) {}
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index 085a563fb8..d1ee26fe50 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -31,23 +31,24 @@
*
*/
-#include "test/core/end2end/end2end_tests.h"
-
#include <string.h>
#include <grpc/byte_buffer.h>
+#include <grpc/load_reporting.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
-#include "test/core/end2end/cq_verifier.h"
#include "src/core/ext/load_reporting/load_reporting.h"
#include "src/core/ext/load_reporting/load_reporting_filter.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/end2end_tests.h"
+
enum { TIMEOUT = 200000 };
static void *tag(intptr_t t) { return (void *)t; }
@@ -124,7 +125,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void request_response_with_payload(
grpc_end2end_test_config config, grpc_end2end_test_fixture f,
const char *method_name, const char *request_msg, const char *response_msg,
- grpc_metadata *initial_lr_metadata, grpc_metadata *trailing_lr_metadata) {
+ grpc_metadata *initial_lr_metadata,
+ grpc_load_reporting_cost_context *cost_ctx) {
grpc_slice request_payload_slice = grpc_slice_from_static_string(request_msg);
grpc_slice response_payload_slice =
grpc_slice_from_static_string(response_msg);
@@ -237,9 +239,8 @@ static void request_response_with_payload(
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
- GPR_ASSERT(trailing_lr_metadata != NULL);
- op->data.send_status_from_server.trailing_metadata_count = 1;
- op->data.send_status_from_server.trailing_metadata = trailing_lr_metadata;
+ GPR_ASSERT(cost_ctx != NULL);
+ grpc_call_set_load_reporting_cost_context(s, cost_ctx);
op->data.send_status_from_server.status = GRPC_STATUS_OK;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
@@ -293,21 +294,21 @@ static void test_load_reporting_hook(grpc_end2end_test_config config) {
const char *response_msg = "... and the response from the server";
grpc_metadata initial_lr_metadata;
- grpc_metadata trailing_lr_metadata;
initial_lr_metadata.key = GRPC_MDSTR_LB_TOKEN;
initial_lr_metadata.value = grpc_slice_from_static_string("client-token");
memset(&initial_lr_metadata.internal_data, 0,
sizeof(initial_lr_metadata.internal_data));
- trailing_lr_metadata.key = GRPC_MDSTR_LB_COST_BIN;
- trailing_lr_metadata.value = grpc_slice_from_static_string("server-token");
- memset(&trailing_lr_metadata.internal_data, 0,
- sizeof(trailing_lr_metadata.internal_data));
+ grpc_load_reporting_cost_context *cost_ctx = gpr_malloc(sizeof(*cost_ctx));
+ memset(cost_ctx, 0, sizeof(*cost_ctx));
+ cost_ctx->values_count = 1;
+ cost_ctx->values =
+ gpr_malloc(sizeof(*cost_ctx->values) * cost_ctx->values_count);
+ cost_ctx->values[0] = grpc_slice_from_static_string("cost-token");
request_response_with_payload(config, f, method_name, request_msg,
- response_msg, &initial_lr_metadata,
- &trailing_lr_metadata);
+ response_msg, &initial_lr_metadata, cost_ctx);
end_test(&f);
{
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index 9cef02b2b3..7540ce93a1 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -212,8 +212,11 @@ static void test_invoke_network_status_change(grpc_end2end_test_config config) {
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
+ // TODO(makdharma) Update this when the shutdown_all_endpoints is implemented.
// Expected behavior of a RPC when network is lost.
- GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+ // GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+ GPR_ASSERT(status == GRPC_STATUS_OK);
+
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
index 42055907c8..2b9c404b15 100644
--- a/test/core/end2end/tests/streaming_error_response.c
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -31,6 +31,9 @@
*
*/
+/** \file Verify that status ordering rules are obeyed.
+ \ref doc/status_ordering.md */
+
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
diff --git a/test/core/fling/BUILD b/test/core/fling/BUILD
new file mode 100644
index 0000000000..0b0ebcb252
--- /dev/null
+++ b/test/core/fling/BUILD
@@ -0,0 +1,62 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+cc_binary(
+ name = "client",
+ srcs = ["client.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ testonly = 1,
+ copts = ['-std=c99']
+)
+
+cc_binary(
+ name = "server",
+ srcs = ["server.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ testonly = 1,
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "fling",
+ srcs = ["fling_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ data = [":client", ":server"]
+)
+
+cc_test(
+ name = "fling_stream",
+ srcs = ["fling_stream_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ data = [":client", ":server"]
+)
diff --git a/test/core/fling/fling_stream_test.c b/test/core/fling/fling_stream_test.c
index 7e4daaa84f..948659ab2f 100644
--- a/test/core/fling/fling_stream_test.c
+++ b/test/core/fling/fling_stream_test.c
@@ -31,22 +31,13 @@
*
*/
-#ifndef _POSIX_SOURCE
-#define _POSIX_SOURCE
-#endif
-
-#include <assert.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
#include "src/core/lib/support/string.h"
#include "test/core/util/port.h"
@@ -57,10 +48,7 @@ int main(int argc, char **argv) {
int port = grpc_pick_unused_port_or_die();
char *args[10];
int status;
- pid_t svr, cli;
- /* seed rng with pid, so we don't end up with the same random numbers as a
- concurrently running test binary */
- srand((unsigned)getpid());
+ gpr_subprocess *svr, *cli;
/* figure out where we are */
if (lslash) {
memcpy(root, me, (size_t)(lslash - me));
@@ -69,45 +57,38 @@ int main(int argc, char **argv) {
strcpy(root, ".");
}
/* start the server */
- svr = fork();
- if (svr == 0) {
- gpr_asprintf(&args[0], "%s/fling_server", root);
- args[1] = "--bind";
- gpr_join_host_port(&args[2], "::", port);
- args[3] = "--no-secure";
- args[4] = 0;
- execv(args[0], args);
+ gpr_asprintf(&args[0], "%s/fling_server%s", root,
+ gpr_subprocess_binary_extension());
+ args[1] = "--bind";
+ gpr_join_host_port(&args[2], "::", port);
+ args[3] = "--no-secure";
+ svr = gpr_subprocess_create(4, (const char **)args);
+ gpr_free(args[0]);
+ gpr_free(args[2]);
- gpr_free(args[0]);
- gpr_free(args[2]);
- return 1;
- }
- /* wait a little */
- sleep(2);
/* start the client */
- cli = fork();
- if (cli == 0) {
- gpr_asprintf(&args[0], "%s/fling_client", root);
- args[1] = "--target";
- gpr_join_host_port(&args[2], "127.0.0.1", port);
- args[3] = "--scenario=ping-pong-stream";
- args[4] = "--no-secure";
- args[5] = 0;
- execv(args[0], args);
+ gpr_asprintf(&args[0], "%s/fling_client%s", root,
+ gpr_subprocess_binary_extension());
+ args[1] = "--target";
+ gpr_join_host_port(&args[2], "127.0.0.1", port);
+ args[3] = "--scenario=ping-pong-stream";
+ args[4] = "--no-secure";
+ args[5] = 0;
+ cli = gpr_subprocess_create(6, (const char **)args);
+ gpr_free(args[0]);
+ gpr_free(args[2]);
- gpr_free(args[0]);
- gpr_free(args[2]);
- return 1;
- }
/* wait for completion */
printf("waiting for client\n");
- if (waitpid(cli, &status, 0) == -1) return 2;
- if (!WIFEXITED(status)) return 4;
- if (WEXITSTATUS(status)) return WEXITSTATUS(status);
- printf("waiting for server\n");
- kill(svr, SIGINT);
- if (waitpid(svr, &status, 0) == -1) return 2;
- if (!WIFEXITED(status)) return 4;
- if (WEXITSTATUS(status)) return WEXITSTATUS(status);
- return 0;
+ if ((status = gpr_subprocess_join(cli))) {
+ gpr_subprocess_destroy(cli);
+ gpr_subprocess_destroy(svr);
+ return status;
+ }
+ gpr_subprocess_destroy(cli);
+
+ gpr_subprocess_interrupt(svr);
+ status = gpr_subprocess_join(svr);
+ gpr_subprocess_destroy(svr);
+ return status;
}
diff --git a/test/core/handshake/BUILD b/test/core/handshake/BUILD
new file mode 100644
index 0000000000..eb8f3a9beb
--- /dev/null
+++ b/test/core/handshake/BUILD
@@ -0,0 +1,64 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "client_ssl",
+ srcs = ["client_ssl.c"],
+ copts = ["-std=c99"],
+ data = [
+ "//src/core/lib/tsi/test_creds:ca.pem",
+ "//src/core/lib/tsi/test_creds:server1.key",
+ "//src/core/lib/tsi/test_creds:server1.pem",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "server_ssl",
+ srcs = ["server_ssl.c"],
+ copts = ["-std=c99"],
+ data = [
+ "//src/core/lib/tsi/test_creds:ca.pem",
+ "//src/core/lib/tsi/test_creds:server1.key",
+ "//src/core/lib/tsi/test_creds:server1.pem",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/handshake/client_ssl.c b/test/core/handshake/client_ssl.c
index a22133e629..5cfe60de4b 100644
--- a/test/core/handshake/client_ssl.c
+++ b/test/core/handshake/client_ssl.c
@@ -31,6 +31,11 @@
*
*/
+#include "src/core/lib/iomgr/port.h"
+
+// This test won't work except with posix sockets enabled
+#ifdef GRPC_POSIX_SOCKET
+
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
@@ -59,13 +64,17 @@ typedef struct {
char *alpn_preferred;
} server_args;
-// From https://wiki.openssl.org/index.php/Simple_TLS_Server.
-static int create_socket(int port) {
+// Based on https://wiki.openssl.org/index.php/Simple_TLS_Server.
+// Pick an arbitrary unused port and return it in *out_port. Return
+// an fd>=0 on success.
+static int create_socket(int *out_port) {
int s;
struct sockaddr_in addr;
+ socklen_t addr_len;
+ *out_port = -1;
addr.sin_family = AF_INET;
- addr.sin_port = htons((uint16_t)port);
+ addr.sin_port = 0;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
@@ -76,7 +85,7 @@ static int create_socket(int port) {
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Unable to bind");
- gpr_log(GPR_ERROR, "Unable to bind to %d", port);
+ gpr_log(GPR_ERROR, "%s", "Unable to bind to any port");
close(s);
return -1;
}
@@ -87,6 +96,16 @@ static int create_socket(int port) {
return -1;
}
+ addr_len = sizeof(addr);
+ if (getsockname(s, (struct sockaddr *)&addr, &addr_len) != 0 ||
+ addr_len > sizeof(addr)) {
+ perror("getsockname");
+ gpr_log(GPR_ERROR, "%s", "Unable to get socket local address");
+ close(s);
+ return -1;
+ }
+
+ *out_port = ntohs(addr.sin_port);
return s;
}
@@ -215,13 +234,12 @@ static bool client_ssl_test(char *server_alpn_preferred) {
int server_socket = -1;
int socket_retries = 30;
while (server_socket == -1 && socket_retries-- > 0) {
- port = grpc_pick_unused_port_or_die();
- server_socket = create_socket(port);
+ server_socket = create_socket(&port);
if (server_socket == -1) {
sleep(1);
}
}
- GPR_ASSERT(server_socket > 0);
+ GPR_ASSERT(server_socket > 0 && port > 0);
// Launch the TLS server thread.
gpr_thd_options thdopt = gpr_thd_options_default();
@@ -311,3 +329,9 @@ int main(int argc, char *argv[]) {
GPR_ASSERT(!client_ssl_test("foo"));
return 0;
}
+
+#else /* GRPC_POSIX_SOCKET */
+
+int main(int argc, char **argv) { return 1; }
+
+#endif /* GRPC_POSIX_SOCKET */
diff --git a/test/core/http/BUILD b/test/core/http/BUILD
index 037ede3cd1..abfa759179 100644
--- a/test/core/http/BUILD
+++ b/test/core/http/BUILD
@@ -47,3 +47,58 @@ grpc_fuzzer(
copts = ["-std=c99"],
)
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+cc_test(
+ name = "httpcli_test",
+ srcs = ["httpcli_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ copts = ['-std=c99'],
+ data = ['test_server.py']
+)
+
+cc_test(
+ name = "httpscli_test",
+ srcs = ["httpscli_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ copts = ['-std=c99'],
+ data = ['test_server.py']
+)
+
+cc_test(
+ name = "parser_test",
+ srcs = ["parser_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/http/httpcli_test.c b/test/core/http/httpcli_test.c
index 6cc00f871d..f690dbaffb 100644
--- a/test/core/http/httpcli_test.c
+++ b/test/core/http/httpcli_test.c
@@ -202,14 +202,14 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
grpc_httpcli_context_init(&g_context);
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &g_mu);
g_pops = grpc_polling_entity_create_from_pollset(pollset);
test_get(port);
test_post(port);
- grpc_httpcli_context_destroy(&g_context);
+ grpc_httpcli_context_destroy(&exec_ctx, &g_context);
grpc_closure_init(&destroyed, destroy_pops, &g_pops,
grpc_schedule_on_exec_ctx);
grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
index e1a26d91e9..549411037e 100644
--- a/test/core/http/httpscli_test.c
+++ b/test/core/http/httpscli_test.c
@@ -205,14 +205,14 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
grpc_httpcli_context_init(&g_context);
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &g_mu);
g_pops = grpc_polling_entity_create_from_pollset(pollset);
test_get(port);
test_post(port);
- grpc_httpcli_context_destroy(&g_context);
+ grpc_httpcli_context_destroy(&exec_ctx, &g_context);
grpc_closure_init(&destroyed, destroy_pops, &g_pops,
grpc_schedule_on_exec_ctx);
grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
diff --git a/test/core/internal_api_canaries/iomgr.c b/test/core/internal_api_canaries/iomgr.c
deleted file mode 100644
index d73d5c175c..0000000000
--- a/test/core/internal_api_canaries/iomgr.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/iomgr/iomgr.h"
-#include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/endpoint.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/executor.h"
-
-/*******************************************************************************
- * NOTE: If this test fails to compile, then the api changes are likely to cause
- * merge failures downstream. Please pay special attention to reviewing
- * these changes, and solicit help as appropriate when merging downstream.
- *
- * This test is NOT expected to be run directly.
- ******************************************************************************/
-
-static void test_code(void) {
- /* iomgr.h */
- grpc_iomgr_init();
- grpc_iomgr_shutdown(NULL);
-
- /* closure.h */
- grpc_closure closure;
- closure.cb = NULL;
- closure.cb_arg = NULL;
- closure.next_data.scratch = 0;
-
- grpc_closure_list closure_list = GRPC_CLOSURE_LIST_INIT;
- closure_list.head = NULL;
- closure_list.tail = NULL;
-
- grpc_closure_init(&closure, NULL, NULL, grpc_schedule_on_exec_ctx);
-
- grpc_closure_create(NULL, NULL, grpc_schedule_on_exec_ctx);
-
- grpc_closure_list_move(NULL, NULL);
- grpc_closure_list_append(NULL, NULL, GRPC_ERROR_CREATE("Foo"));
- grpc_closure_list_empty(closure_list);
-
- /* exec_ctx.h */
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_exec_ctx_flush(&exec_ctx);
- grpc_exec_ctx_finish(&exec_ctx);
- grpc_closure_sched(&exec_ctx, &closure, GRPC_ERROR_CREATE("Foo"));
- grpc_closure_list_sched(&exec_ctx, &closure_list);
-
- /* endpoint.h */
- grpc_endpoint endpoint;
- grpc_endpoint_vtable vtable = {grpc_endpoint_read,
- grpc_endpoint_write,
- grpc_endpoint_get_workqueue,
- grpc_endpoint_add_to_pollset,
- grpc_endpoint_add_to_pollset_set,
- grpc_endpoint_shutdown,
- grpc_endpoint_destroy,
- grpc_endpoint_get_resource_user,
- grpc_endpoint_get_peer,
- grpc_endpoint_get_fd};
- endpoint.vtable = &vtable;
-
- grpc_endpoint_read(&exec_ctx, &endpoint, NULL, NULL);
- grpc_endpoint_get_peer(&endpoint);
- grpc_endpoint_write(&exec_ctx, &endpoint, NULL, NULL);
- grpc_endpoint_shutdown(&exec_ctx, &endpoint, GRPC_ERROR_CANCELLED);
- grpc_endpoint_destroy(&exec_ctx, &endpoint);
- grpc_endpoint_add_to_pollset(&exec_ctx, &endpoint, NULL);
- grpc_endpoint_add_to_pollset_set(&exec_ctx, &endpoint, NULL);
-
- /* executor.h */
- grpc_executor_init();
- grpc_executor_shutdown(NULL);
-
- /* pollset.h */
- grpc_pollset_size();
- grpc_pollset_init(NULL, NULL);
- grpc_pollset_shutdown(NULL, NULL, NULL);
- grpc_pollset_reset(NULL);
- grpc_pollset_destroy(NULL);
- GRPC_ERROR_UNREF(grpc_pollset_work(NULL, NULL, NULL,
- gpr_now(GPR_CLOCK_REALTIME),
- gpr_now(GPR_CLOCK_MONOTONIC)));
- GRPC_ERROR_UNREF(grpc_pollset_kick(NULL, NULL));
-}
-
-int main(void) {
- if (false) test_code();
- return 0;
-}
diff --git a/test/core/internal_api_canaries/transport.c b/test/core/internal_api_canaries/transport.c
deleted file mode 100644
index 2989f59535..0000000000
--- a/test/core/internal_api_canaries/transport.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*******************************************************************************
- * NOTE: If this test fails to compile, then the api changes are likely to cause
- * merge failures downstream. Please pay special attention to reviewing
- * these changes, and solicit help as appropriate when merging downstream.
- *
- * This test is NOT expected to be run directly.
- ******************************************************************************/
-
-#include "src/core/lib/transport/transport.h"
-#include "src/core/lib/transport/transport_impl.h"
-
-static void test_code(void) {
- /* transport_impl.h */
- grpc_transport transport;
- grpc_transport_vtable vtable = {12345,
- grpc_transport_init_stream,
- grpc_transport_set_pollset,
- grpc_transport_perform_stream_op,
- grpc_transport_perform_op,
- grpc_transport_destroy_stream,
- grpc_transport_destroy,
- grpc_transport_get_peer};
- transport.vtable = &vtable;
-
- /* transport.h */
- GRPC_STREAM_REF_INIT(NULL, 0, NULL, NULL, "xyz");
- GPR_ASSERT(0 == grpc_transport_stream_size(NULL));
- GPR_ASSERT(grpc_transport_init_stream(&transport, NULL, NULL, NULL, NULL));
- grpc_transport_set_pollset(&transport, NULL, NULL, NULL);
- grpc_transport_destroy_stream(&transport, NULL, NULL);
- grpc_transport_stream_op_finish_with_failure(NULL, NULL);
- grpc_transport_stream_op_add_cancellation(NULL, GRPC_STATUS_UNAVAILABLE);
- grpc_transport_stream_op_add_close(NULL, GRPC_STATUS_UNAVAILABLE,
- grpc_transport_op_string(NULL));
- grpc_transport_perform_stream_op(&transport, NULL, NULL, NULL);
- grpc_transport_perform_op(&transport, NULL, NULL);
- grpc_transport_ping(&transport, NULL);
- grpc_transport_goaway(&transport, GRPC_STATUS_UNAVAILABLE,
- grpc_slice_malloc(0));
- grpc_transport_close(&transport);
- grpc_transport_destroy(&transport, NULL);
- GPR_ASSERT("xyz" == grpc_transport_get_peer(&transport, NULL));
-}
-
-int main(void) {
- if (false) test_code();
- return 0;
-}
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
new file mode 100644
index 0000000000..0cf93e73f5
--- /dev/null
+++ b/test/core/iomgr/BUILD
@@ -0,0 +1,181 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+cc_library(
+ name = "endpoint_tests",
+ srcs = ["endpoint_tests.c"],
+ hdrs = ["endpoint_tests.h"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ visibility = ["//test:__subpackages__"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "combiner_test",
+ srcs = ["combiner_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "endpoint_pair_test",
+ srcs = ["endpoint_pair_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", ":endpoint_tests"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "ev_epoll_linux_test",
+ srcs = ["ev_epoll_linux_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "fd_conservation_posix_test",
+ srcs = ["fd_conservation_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "fd_posix_test",
+ srcs = ["fd_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "load_file_test",
+ srcs = ["load_file_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "pollset_set_test",
+ srcs = ["pollset_set_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "resolve_address_posix_test",
+ srcs = ["resolve_address_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "resolve_address_test",
+ srcs = ["resolve_address_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "resource_quota_test",
+ srcs = ["resource_quota_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "sockaddr_utils_test",
+ srcs = ["sockaddr_utils_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "socket_utils_test",
+ srcs = ["socket_utils_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "tcp_client_posix_test",
+ srcs = ["tcp_client_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "tcp_posix_test",
+ srcs = ["tcp_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", ":endpoint_tests"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "tcp_server_posix_test",
+ srcs = ["tcp_server_posix_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "time_averaged_stats_test",
+ srcs = ["time_averaged_stats_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "timer_heap_test",
+ srcs = ["timer_heap_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "timer_list_test",
+ srcs = ["timer_list_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "udp_server_test",
+ srcs = ["udp_server_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "wakeup_fd_cv_test",
+ srcs = ["wakeup_fd_cv_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c
index 4c9275a673..bc4d2af8ac 100644
--- a/test/core/iomgr/combiner_test.c
+++ b/test/core/iomgr/combiner_test.c
@@ -44,7 +44,7 @@
static void test_no_op(void) {
gpr_log(GPR_DEBUG, "test_no_op");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_combiner_destroy(&exec_ctx, grpc_combiner_create(NULL));
+ GRPC_COMBINER_UNREF(&exec_ctx, grpc_combiner_create(NULL), "test_no_op");
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -65,7 +65,7 @@ static void test_execute_one(void) {
GRPC_ERROR_NONE);
grpc_exec_ctx_flush(&exec_ctx);
GPR_ASSERT(done);
- grpc_combiner_destroy(&exec_ctx, lock);
+ GRPC_COMBINER_UNREF(&exec_ctx, lock, "test_execute_one");
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -125,7 +125,7 @@ static void test_execute_many(void) {
gpr_thd_join(thds[i]);
}
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_combiner_destroy(&exec_ctx, lock);
+ GRPC_COMBINER_UNREF(&exec_ctx, lock, "test_execute_many");
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -153,7 +153,7 @@ static void test_execute_finally(void) {
GRPC_ERROR_NONE);
grpc_exec_ctx_flush(&exec_ctx);
GPR_ASSERT(got_in_finally);
- grpc_combiner_destroy(&exec_ctx, lock);
+ GRPC_COMBINER_UNREF(&exec_ctx, lock, "test_execute_finally");
grpc_exec_ctx_finish(&exec_ctx);
}
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index f02171f2ef..4b98ef257e 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -78,7 +78,7 @@ int main(int argc, char **argv) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
grpc_endpoint_tests(configs[0], g_pollset, g_mu);
grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
diff --git a/test/core/iomgr/error_test.c b/test/core/iomgr/error_test.c
new file mode 100644
index 0000000000..2a6b1b17fd
--- /dev/null
+++ b/test/core/iomgr/error_test.c
@@ -0,0 +1,219 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/error.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include <string.h>
+
+#include "test/core/util/test_config.h"
+
+static void test_set_get_int() {
+ grpc_error* error = GRPC_ERROR_CREATE("Test");
+ GPR_ASSERT(error);
+ intptr_t i = 0;
+ GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_FILE_LINE, &i));
+ GPR_ASSERT(i); // line set will never be 0
+ GPR_ASSERT(!grpc_error_get_int(error, GRPC_ERROR_INT_ERRNO, &i));
+ GPR_ASSERT(!grpc_error_get_int(error, GRPC_ERROR_INT_SIZE, &i));
+
+ intptr_t errnumber = 314;
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, errnumber);
+ GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_ERRNO, &i));
+ GPR_ASSERT(i == errnumber);
+
+ intptr_t http = 2;
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_HTTP2_ERROR, http);
+ GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &i));
+ GPR_ASSERT(i == http);
+
+ GRPC_ERROR_UNREF(error);
+}
+
+static void test_set_get_str() {
+ grpc_error* error = GRPC_ERROR_CREATE("Test");
+
+ GPR_ASSERT(!grpc_error_get_str(error, GRPC_ERROR_STR_SYSCALL));
+ GPR_ASSERT(!grpc_error_get_str(error, GRPC_ERROR_STR_TSI_ERROR));
+
+ const char* c = grpc_error_get_str(error, GRPC_ERROR_STR_FILE);
+ GPR_ASSERT(c);
+ GPR_ASSERT(strstr(c, "error_test.c")); // __FILE__ expands differently on
+ // Windows. All should at least
+ // contain error_test.c
+
+ c = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, "Test"));
+
+ error =
+ grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, "longer message");
+ c = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, "longer message"));
+
+ GRPC_ERROR_UNREF(error);
+}
+
+static void test_copy_and_unref() {
+ // error1 has one ref
+ grpc_error* error1 = grpc_error_set_str(
+ GRPC_ERROR_CREATE("Test"), GRPC_ERROR_STR_GRPC_MESSAGE, "message");
+ const char* c = grpc_error_get_str(error1, GRPC_ERROR_STR_GRPC_MESSAGE);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, "message"));
+
+ // error 1 has two refs
+ GRPC_ERROR_REF(error1);
+ // this gives error3 a ref to the new error, and decrements error1 to one ref
+ grpc_error* error3 =
+ grpc_error_set_str(error1, GRPC_ERROR_STR_SYSCALL, "syscall");
+ GPR_ASSERT(error3 != error1); // should not be the same because of extra ref
+ c = grpc_error_get_str(error3, GRPC_ERROR_STR_GRPC_MESSAGE);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, "message"));
+
+ // error 1 should not have a syscall but 3 should
+ GPR_ASSERT(!grpc_error_get_str(error1, GRPC_ERROR_STR_SYSCALL));
+ c = grpc_error_get_str(error3, GRPC_ERROR_STR_SYSCALL);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, "syscall"));
+
+ GRPC_ERROR_UNREF(error1);
+ GRPC_ERROR_UNREF(error3);
+}
+
+static void test_create_referencing() {
+ grpc_error* child = grpc_error_set_str(
+ GRPC_ERROR_CREATE("Child"), GRPC_ERROR_STR_GRPC_MESSAGE, "message");
+ grpc_error* parent = GRPC_ERROR_CREATE_REFERENCING("Parent", &child, 1);
+ GPR_ASSERT(parent);
+
+ GRPC_ERROR_UNREF(child);
+ GRPC_ERROR_UNREF(parent);
+}
+
+static void test_create_referencing_many() {
+ grpc_error* children[3];
+ children[0] = grpc_error_set_str(GRPC_ERROR_CREATE("Child1"),
+ GRPC_ERROR_STR_GRPC_MESSAGE, "message");
+ children[1] = grpc_error_set_int(GRPC_ERROR_CREATE("Child2"),
+ GRPC_ERROR_INT_HTTP2_ERROR, 5);
+ children[2] = grpc_error_set_str(GRPC_ERROR_CREATE("Child3"),
+ GRPC_ERROR_STR_GRPC_MESSAGE, "message 3");
+
+ grpc_error* parent = GRPC_ERROR_CREATE_REFERENCING("Parent", children, 3);
+ GPR_ASSERT(parent);
+
+ for (size_t i = 0; i < 3; ++i) {
+ GRPC_ERROR_UNREF(children[i]);
+ }
+ GRPC_ERROR_UNREF(parent);
+}
+
+static void print_error_string() {
+ grpc_error* error =
+ grpc_error_set_int(GRPC_ERROR_CREATE("Error"), GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED);
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_SIZE, 666);
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, "message");
+ // gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
+ GRPC_ERROR_UNREF(error);
+}
+
+static void print_error_string_reference() {
+ grpc_error* children[2];
+ children[0] = grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE("1"), GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED),
+ GRPC_ERROR_STR_GRPC_MESSAGE, "message for child 1");
+ children[1] = grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE("2sd"), GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_INTERNAL),
+ GRPC_ERROR_STR_GRPC_MESSAGE, "message for child 2");
+
+ grpc_error* parent = GRPC_ERROR_CREATE_REFERENCING("Parent", children, 2);
+
+ gpr_log(GPR_DEBUG, "%s", grpc_error_string(parent));
+
+ for (size_t i = 0; i < 2; ++i) {
+ GRPC_ERROR_UNREF(children[i]);
+ }
+ GRPC_ERROR_UNREF(parent);
+}
+
+static void test_os_error() {
+ int fake_errno = 5;
+ const char* syscall = "syscall name";
+ grpc_error* error = GRPC_OS_ERROR(fake_errno, syscall);
+
+ intptr_t i = 0;
+ GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_ERRNO, &i));
+ GPR_ASSERT(i == fake_errno);
+
+ const char* c = grpc_error_get_str(error, GRPC_ERROR_STR_SYSCALL);
+ GPR_ASSERT(c);
+ GPR_ASSERT(!strcmp(c, syscall));
+ GRPC_ERROR_UNREF(error);
+}
+
+static void test_special() {
+ grpc_error* error = GRPC_ERROR_NONE;
+ error = grpc_error_add_child(error, GRPC_ERROR_CREATE("test child"));
+ intptr_t i;
+ GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &i));
+ GPR_ASSERT(i == GRPC_STATUS_OK);
+ GRPC_ERROR_UNREF(error);
+}
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+ test_set_get_int();
+ test_set_get_str();
+ test_copy_and_unref();
+ print_error_string();
+ print_error_string_reference();
+ test_os_error();
+ test_create_referencing();
+ test_create_referencing_many();
+ test_special();
+ grpc_shutdown();
+
+ return 0;
+}
diff --git a/test/core/iomgr/ev_epoll_linux_test.c b/test/core/iomgr/ev_epoll_linux_test.c
index 5b05ea3338..4ec959995b 100644
--- a/test/core/iomgr/ev_epoll_linux_test.c
+++ b/test/core/iomgr/ev_epoll_linux_test.c
@@ -104,7 +104,7 @@ static void test_fd_cleanup(grpc_exec_ctx *exec_ctx, test_fd *tfds,
static void test_pollset_init(test_pollset *pollsets, int num_pollsets) {
int i;
for (i = 0; i < num_pollsets; i++) {
- pollsets[i].pollset = gpr_malloc(grpc_pollset_size());
+ pollsets[i].pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollsets[i].pollset, &pollsets[i].mu);
}
}
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index 4726e935d8..c1a0ef54d3 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -543,7 +543,7 @@ int main(int argc, char **argv) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_test_init(argc, argv);
grpc_iomgr_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
test_grpc_fd();
test_grpc_fd_change();
diff --git a/test/core/iomgr/pollset_set_test.c b/test/core/iomgr/pollset_set_test.c
index 40fa858602..f27e9db8c9 100644
--- a/test/core/iomgr/pollset_set_test.c
+++ b/test/core/iomgr/pollset_set_test.c
@@ -59,10 +59,11 @@ void init_test_pollset_sets(test_pollset_set *pollset_sets, const int num_pss) {
}
}
-void cleanup_test_pollset_sets(test_pollset_set *pollset_sets,
+void cleanup_test_pollset_sets(grpc_exec_ctx *exec_ctx,
+ test_pollset_set *pollset_sets,
const int num_pss) {
for (int i = 0; i < num_pss; i++) {
- grpc_pollset_set_destroy(pollset_sets[i].pss);
+ grpc_pollset_set_destroy(exec_ctx, pollset_sets[i].pss);
pollset_sets[i].pss = NULL;
}
}
@@ -78,7 +79,7 @@ typedef struct test_pollset {
static void init_test_pollsets(test_pollset *pollsets, const int num_pollsets) {
for (int i = 0; i < num_pollsets; i++) {
- pollsets[i].ps = gpr_malloc(grpc_pollset_size());
+ pollsets[i].ps = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollsets[i].ps, &pollsets[i].mu);
}
}
@@ -297,7 +298,7 @@ static void pollset_set_test_basic() {
cleanup_test_fds(&exec_ctx, tfds, num_fds);
cleanup_test_pollsets(&exec_ctx, pollsets, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
+ cleanup_test_pollset_sets(&exec_ctx, pollset_sets, num_pss);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -372,7 +373,7 @@ void pollset_set_test_dup_fds() {
cleanup_test_fds(&exec_ctx, tfds, num_fds);
cleanup_test_pollsets(&exec_ctx, &pollset, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
+ cleanup_test_pollset_sets(&exec_ctx, pollset_sets, num_pss);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -437,7 +438,7 @@ void pollset_set_test_empty_pollset() {
cleanup_test_fds(&exec_ctx, tfds, num_fds);
cleanup_test_pollsets(&exec_ctx, pollsets, num_ps);
- cleanup_test_pollset_sets(&pollset_set, num_pss);
+ cleanup_test_pollset_sets(&exec_ctx, &pollset_set, num_pss);
grpc_exec_ctx_finish(&exec_ctx);
}
diff --git a/test/core/iomgr/resolve_address_posix_test.c b/test/core/iomgr/resolve_address_posix_test.c
index a4feff8b00..fa88aca431 100644
--- a/test/core/iomgr/resolve_address_posix_test.c
+++ b/test/core/iomgr/resolve_address_posix_test.c
@@ -63,7 +63,7 @@ static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
void args_init(grpc_exec_ctx *exec_ctx, args_struct *args) {
gpr_event_init(&args->ev);
- args->pollset = gpr_malloc(grpc_pollset_size());
+ args->pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(args->pollset, &args->mu);
args->pollset_set = grpc_pollset_set_create();
grpc_pollset_set_add_pollset(exec_ctx, args->pollset_set, args->pollset);
@@ -74,7 +74,7 @@ void args_finish(grpc_exec_ctx *exec_ctx, args_struct *args) {
GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
grpc_resolved_addresses_destroy(args->addrs);
grpc_pollset_set_del_pollset(exec_ctx, args->pollset_set, args->pollset);
- grpc_pollset_set_destroy(args->pollset_set);
+ grpc_pollset_set_destroy(exec_ctx, args->pollset_set);
grpc_closure do_nothing_cb;
grpc_closure_init(&do_nothing_cb, do_nothing, NULL,
grpc_schedule_on_exec_ctx);
diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c
index 54de9a20e1..ea79adc090 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -35,7 +35,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
@@ -58,18 +57,19 @@ static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
void args_init(grpc_exec_ctx *exec_ctx, args_struct *args) {
gpr_event_init(&args->ev);
- args->pollset = gpr_malloc(grpc_pollset_size());
+ args->pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(args->pollset, &args->mu);
args->pollset_set = grpc_pollset_set_create();
grpc_pollset_set_add_pollset(exec_ctx, args->pollset_set, args->pollset);
args->addrs = NULL;
+ gpr_atm_rel_store(&args->done_atm, 0);
}
void args_finish(grpc_exec_ctx *exec_ctx, args_struct *args) {
GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
grpc_resolved_addresses_destroy(args->addrs);
grpc_pollset_set_del_pollset(exec_ctx, args->pollset_set, args->pollset);
- grpc_pollset_set_destroy(args->pollset_set);
+ grpc_pollset_set_destroy(exec_ctx, args->pollset_set);
grpc_closure do_nothing_cb;
grpc_closure_init(&do_nothing_cb, do_nothing, NULL,
grpc_schedule_on_exec_ctx);
@@ -85,8 +85,7 @@ static gpr_timespec n_sec_deadline(int seconds) {
gpr_time_from_seconds(seconds, GPR_TIMESPAN));
}
-static void actually_poll(void *argsp) {
- args_struct *args = argsp;
+static void poll_pollset_until_request_done(args_struct *args) {
gpr_timespec deadline = n_sec_deadline(10);
while (true) {
bool done = gpr_atm_acq_load(&args->done_atm) != 0;
@@ -111,12 +110,6 @@ static void actually_poll(void *argsp) {
gpr_event_set(&args->ev, (void *)1);
}
-static void poll_pollset_until_request_done(args_struct *args) {
- gpr_atm_rel_store(&args->done_atm, 0);
- gpr_thd_id id;
- gpr_thd_new(&id, actually_poll, args, NULL);
-}
-
static void must_succeed(grpc_exec_ctx *exec_ctx, void *argsp,
grpc_error *err) {
args_struct *args = argsp;
@@ -124,23 +117,30 @@ static void must_succeed(grpc_exec_ctx *exec_ctx, void *argsp,
GPR_ASSERT(args->addrs != NULL);
GPR_ASSERT(args->addrs->naddrs > 0);
gpr_atm_rel_store(&args->done_atm, 1);
+ gpr_mu_lock(args->mu);
+ GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, NULL));
+ gpr_mu_unlock(args->mu);
}
static void must_fail(grpc_exec_ctx *exec_ctx, void *argsp, grpc_error *err) {
args_struct *args = argsp;
GPR_ASSERT(err != GRPC_ERROR_NONE);
gpr_atm_rel_store(&args->done_atm, 1);
+ gpr_mu_lock(args->mu);
+ GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(args->pollset, NULL));
+ gpr_mu_unlock(args->mu);
}
static void test_localhost(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, "localhost:1", NULL, args.pollset_set,
grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -149,24 +149,40 @@ static void test_default_port(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, "localhost", "1", args.pollset_set,
grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
-static void test_missing_default_port(void) {
+static void test_non_numeric_default_port(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
+ grpc_resolve_address(
+ &exec_ctx, "localhost", "https", args.pollset_set,
+ grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
+ &args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
poll_pollset_until_request_done(&args);
+ args_finish(&exec_ctx, &args);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_missing_default_port(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ args_struct args;
+ args_init(&exec_ctx, &args);
grpc_resolve_address(
&exec_ctx, "localhost", NULL, args.pollset_set,
grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -175,11 +191,12 @@ static void test_ipv6_with_port(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, "[2001:db8::1]:1", NULL, args.pollset_set,
grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -193,11 +210,12 @@ static void test_ipv6_without_port(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, kCases[i], "80", args.pollset_set,
grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -212,11 +230,12 @@ static void test_invalid_ip_addresses(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, kCases[i], NULL, args.pollset_set,
grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -231,11 +250,12 @@ static void test_unparseable_hostports(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
args_struct args;
args_init(&exec_ctx, &args);
- poll_pollset_until_request_done(&args);
grpc_resolve_address(
&exec_ctx, kCases[i], "1", args.pollset_set,
grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
&args.addrs);
+ grpc_exec_ctx_flush(&exec_ctx);
+ poll_pollset_until_request_done(&args);
args_finish(&exec_ctx, &args);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -247,6 +267,7 @@ int main(int argc, char **argv) {
grpc_iomgr_init();
test_localhost();
test_default_port();
+ test_non_numeric_default_port();
test_missing_default_port();
test_ipv6_with_port();
test_ipv6_without_port();
diff --git a/test/core/iomgr/sockaddr_utils_test.c b/test/core/iomgr/sockaddr_utils_test.c
index 8569c697fe..70a6c323e5 100644
--- a/test/core/iomgr/sockaddr_utils_test.c
+++ b/test/core/iomgr/sockaddr_utils_test.c
@@ -70,6 +70,12 @@ static grpc_resolved_address make_addr6(const uint8_t *data, size_t data_len) {
return resolved_addr6;
}
+static void set_addr6_scope_id(grpc_resolved_address *addr, uint32_t scope_id) {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr->addr;
+ GPR_ASSERT(addr6->sin6_family == AF_INET6);
+ addr6->sin6_scope_id = scope_id;
+}
+
static const uint8_t kMapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xff, 0xff, 192, 0, 2, 1};
@@ -222,6 +228,16 @@ static void test_sockaddr_to_string(void) {
expect_sockaddr_str("[2001:db8::1]:12345", &input6, 1);
expect_sockaddr_uri("ipv6:[2001:db8::1]:12345", &input6);
+ set_addr6_scope_id(&input6, 2);
+ expect_sockaddr_str("[2001:db8::1%252]:12345", &input6, 0);
+ expect_sockaddr_str("[2001:db8::1%252]:12345", &input6, 1);
+ expect_sockaddr_uri("ipv6:[2001:db8::1%252]:12345", &input6);
+
+ set_addr6_scope_id(&input6, 101);
+ expect_sockaddr_str("[2001:db8::1%25101]:12345", &input6, 0);
+ expect_sockaddr_str("[2001:db8::1%25101]:12345", &input6, 1);
+ expect_sockaddr_uri("ipv6:[2001:db8::1%25101]:12345", &input6);
+
input6 = make_addr6(kMapped, sizeof(kMapped));
expect_sockaddr_str("[::ffff:192.0.2.1]:12345", &input6, 0);
expect_sockaddr_str("192.0.2.1:12345", &input6, 1);
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index dcdff8efb1..b324b5a65e 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -31,6 +31,11 @@
*
*/
+#include "src/core/lib/iomgr/port.h"
+
+// This test won't work except with posix sockets enabled
+#ifdef GRPC_POSIX_SOCKET
+
#include "src/core/lib/iomgr/tcp_client.h"
#include <errno.h>
@@ -200,14 +205,14 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
g_pollset_set = grpc_pollset_set_create();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
grpc_pollset_set_add_pollset(&exec_ctx, g_pollset_set, g_pollset);
grpc_exec_ctx_finish(&exec_ctx);
test_succeeds();
gpr_log(GPR_ERROR, "End of first test");
test_fails();
- grpc_pollset_set_destroy(g_pollset_set);
+ grpc_pollset_set_destroy(&exec_ctx, g_pollset_set);
grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
grpc_schedule_on_exec_ctx);
grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
@@ -216,3 +221,9 @@ int main(int argc, char **argv) {
gpr_free(g_pollset);
return 0;
}
+
+#else /* GRPC_POSIX_SOCKET */
+
+int main(int argc, char **argv) { return 1; }
+
+#endif /* GRPC_POSIX_SOCKET */
diff --git a/test/core/iomgr/tcp_client_uv_test.c b/test/core/iomgr/tcp_client_uv_test.c
new file mode 100644
index 0000000000..064119f11b
--- /dev/null
+++ b/test/core/iomgr/tcp_client_uv_test.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+// This test won't work except with libuv
+#ifdef GRPC_UV
+
+#include <uv.h>
+
+#include <string.h>
+
+#include "src/core/lib/iomgr/tcp_client.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "test/core/util/test_config.h"
+
+static gpr_mu *g_mu;
+static grpc_pollset *g_pollset;
+static int g_connections_complete = 0;
+static grpc_endpoint *g_connecting = NULL;
+
+static gpr_timespec test_deadline(void) {
+ return grpc_timeout_seconds_to_deadline(10);
+}
+
+static void finish_connection() {
+ gpr_mu_lock(g_mu);
+ g_connections_complete++;
+ GPR_ASSERT(
+ GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL)));
+ gpr_mu_unlock(g_mu);
+}
+
+static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ GPR_ASSERT(g_connecting != NULL);
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ grpc_endpoint_shutdown(exec_ctx, g_connecting,
+ GRPC_ERROR_CREATE("must_succeed called"));
+ grpc_endpoint_destroy(exec_ctx, g_connecting);
+ g_connecting = NULL;
+ finish_connection();
+}
+
+static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ GPR_ASSERT(g_connecting == NULL);
+ GPR_ASSERT(error != GRPC_ERROR_NONE);
+ finish_connection();
+}
+
+static void close_cb(uv_handle_t *handle) { gpr_free(handle); }
+
+static void connection_cb(uv_stream_t *server, int status) {
+ uv_tcp_t *client_handle = gpr_malloc(sizeof(uv_tcp_t));
+ GPR_ASSERT(0 == status);
+ GPR_ASSERT(0 == uv_tcp_init(uv_default_loop(), client_handle));
+ GPR_ASSERT(0 == uv_accept(server, (uv_stream_t *)client_handle));
+ uv_close((uv_handle_t *)client_handle, close_cb);
+}
+
+void test_succeeds(void) {
+ grpc_resolved_address resolved_addr;
+ struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
+ uv_tcp_t *svr_handle = gpr_malloc(sizeof(uv_tcp_t));
+ int connections_complete_before;
+ grpc_closure done;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ gpr_log(GPR_DEBUG, "test_succeeds");
+
+ memset(&resolved_addr, 0, sizeof(resolved_addr));
+ resolved_addr.len = sizeof(struct sockaddr_in);
+ addr->sin_family = AF_INET;
+
+ /* create a dummy server */
+ GPR_ASSERT(0 == uv_tcp_init(uv_default_loop(), svr_handle));
+ GPR_ASSERT(0 == uv_tcp_bind(svr_handle, (struct sockaddr *)addr, 0));
+ GPR_ASSERT(0 == uv_listen((uv_stream_t *)svr_handle, 1, connection_cb));
+
+ gpr_mu_lock(g_mu);
+ connections_complete_before = g_connections_complete;
+ gpr_mu_unlock(g_mu);
+
+ /* connect to it */
+ GPR_ASSERT(uv_tcp_getsockname(svr_handle, (struct sockaddr *)addr,
+ (int *)&resolved_addr.len) == 0);
+ grpc_closure_init(&done, must_succeed, NULL, grpc_schedule_on_exec_ctx);
+ grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, NULL, NULL,
+ &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+ gpr_mu_lock(g_mu);
+
+ while (g_connections_complete == connections_complete_before) {
+ grpc_pollset_worker *worker = NULL;
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "pollset_work",
+ grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+ gpr_now(GPR_CLOCK_MONOTONIC),
+ grpc_timeout_seconds_to_deadline(5))));
+ gpr_mu_unlock(g_mu);
+ grpc_exec_ctx_flush(&exec_ctx);
+ gpr_mu_lock(g_mu);
+ }
+
+ // This will get cleaned up when the pollset runs again or gets shutdown
+ uv_close((uv_handle_t *)svr_handle, close_cb);
+
+ gpr_mu_unlock(g_mu);
+
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void test_fails(void) {
+ grpc_resolved_address resolved_addr;
+ struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
+ int connections_complete_before;
+ grpc_closure done;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ gpr_log(GPR_DEBUG, "test_fails");
+
+ memset(&resolved_addr, 0, sizeof(resolved_addr));
+ resolved_addr.len = sizeof(struct sockaddr_in);
+ addr->sin_family = AF_INET;
+
+ gpr_mu_lock(g_mu);
+ connections_complete_before = g_connections_complete;
+ gpr_mu_unlock(g_mu);
+
+ /* connect to a broken address */
+ grpc_closure_init(&done, must_fail, NULL, grpc_schedule_on_exec_ctx);
+ grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, NULL, NULL,
+ &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+ gpr_mu_lock(g_mu);
+
+ /* wait for the connection callback to finish */
+ while (g_connections_complete == connections_complete_before) {
+ grpc_pollset_worker *worker = NULL;
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ gpr_timespec polling_deadline = test_deadline();
+ if (!grpc_timer_check(&exec_ctx, now, &polling_deadline)) {
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "pollset_work", grpc_pollset_work(&exec_ctx, g_pollset, &worker, now,
+ polling_deadline)));
+ }
+ gpr_mu_unlock(g_mu);
+ grpc_exec_ctx_flush(&exec_ctx);
+ gpr_mu_lock(g_mu);
+ }
+
+ gpr_mu_unlock(g_mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
+ grpc_error *error) {
+ grpc_pollset_destroy(p);
+}
+
+int main(int argc, char **argv) {
+ grpc_closure destroyed;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_test_init(argc, argv);
+ grpc_init();
+ g_pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset_init(g_pollset, &g_mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+ test_succeeds();
+ gpr_log(GPR_ERROR, "End of first test");
+ test_fails();
+ grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_shutdown();
+ gpr_free(g_pollset);
+ return 0;
+}
+
+#else /* GRPC_UV */
+
+int main(int argc, char **argv) { return 1; }
+
+#endif /* GRPC_UV */
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 99ecd581c6..5a55be888f 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -561,7 +561,7 @@ int main(int argc, char **argv) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
grpc_endpoint_tests(configs[0], g_pollset, g_mu);
run_tests();
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 7122cd1e86..6e514324a5 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -39,9 +39,12 @@
#include "src/core/lib/iomgr/tcp_server.h"
#include <errno.h>
+#include <ifaddrs.h>
#include <netinet/in.h>
+#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
#include <grpc/grpc.h>
@@ -50,6 +53,7 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -62,7 +66,7 @@ static gpr_mu *g_mu;
static grpc_pollset *g_pollset;
static int g_nconnects = 0;
-typedef struct on_connect_result {
+typedef struct {
/* Owns a ref to server. */
grpc_tcp_server *server;
unsigned port_index;
@@ -70,15 +74,41 @@ typedef struct on_connect_result {
int server_fd;
} on_connect_result;
-typedef struct server_weak_ref {
+typedef struct {
grpc_tcp_server *server;
/* arg is this server_weak_ref. */
grpc_closure server_shutdown;
} server_weak_ref;
+#define MAX_URI 1024
+typedef struct {
+ grpc_resolved_address addr;
+ char str[MAX_URI];
+} test_addr;
+
+#define MAX_ADDRS 100
+typedef struct {
+ size_t naddrs;
+ test_addr addrs[MAX_ADDRS];
+} test_addrs;
+
static on_connect_result g_result = {NULL, 0, 0, -1};
+static char family_name_buf[1024];
+static const char *sock_family_name(int family) {
+ if (family == AF_INET) {
+ return "AF_INET";
+ } else if (family == AF_INET6) {
+ return "AF_INET6";
+ } else if (family == AF_UNSPEC) {
+ return "AF_UNSPEC";
+ } else {
+ sprintf(family_name_buf, "%d", family);
+ return family_name_buf;
+ }
+}
+
static void on_connect_result_init(on_connect_result *result) {
result->server = NULL;
result->port_index = 0;
@@ -118,6 +148,18 @@ static void server_weak_ref_set(server_weak_ref *weak_ref,
weak_ref->server = server;
}
+static void test_addr_init_str(test_addr *addr) {
+ char *str = NULL;
+ if (grpc_sockaddr_to_string(&str, &addr->addr, 0) != -1) {
+ size_t str_len;
+ memcpy(addr->str, str, (str_len = strnlen(str, sizeof(addr->str) - 1)));
+ addr->str[str_len] = '\0';
+ gpr_free(str);
+ } else {
+ addr->str[0] = '\0';
+ }
+}
+
static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
grpc_pollset *pollset,
grpc_tcp_server_acceptor *acceptor) {
@@ -168,7 +210,7 @@ static void test_no_op_with_port(void) {
memset(&resolved_addr, 0, sizeof(resolved_addr));
resolved_addr.len = sizeof(struct sockaddr_in);
addr->sin_family = AF_INET;
- int port;
+ int port = -1;
GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) ==
GRPC_ERROR_NONE &&
port > 0);
@@ -185,7 +227,7 @@ static void test_no_op_with_port_and_start(void) {
GPR_ASSERT(GRPC_ERROR_NONE ==
grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
LOG_TEST("test_no_op_with_port_and_start");
- int port;
+ int port = -1;
memset(&resolved_addr, 0, sizeof(resolved_addr));
resolved_addr.len = sizeof(struct sockaddr_in);
@@ -200,74 +242,115 @@ static void test_no_op_with_port_and_start(void) {
grpc_exec_ctx_finish(&exec_ctx);
}
-static void tcp_connect(grpc_exec_ctx *exec_ctx, const struct sockaddr *remote,
- socklen_t remote_len, on_connect_result *result) {
+static grpc_error *tcp_connect(grpc_exec_ctx *exec_ctx, const test_addr *remote,
+ on_connect_result *result) {
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
- int clifd = socket(remote->sa_family, SOCK_STREAM, 0);
+ int clifd;
int nconnects_before;
+ const struct sockaddr *remote_addr =
+ (const struct sockaddr *)remote->addr.addr;
+ gpr_log(GPR_INFO, "Connecting to %s", remote->str);
gpr_mu_lock(g_mu);
nconnects_before = g_nconnects;
on_connect_result_init(&g_result);
- GPR_ASSERT(clifd >= 0);
- gpr_log(GPR_DEBUG, "start connect");
- GPR_ASSERT(connect(clifd, remote, remote_len) == 0);
+ clifd = socket(remote_addr->sa_family, SOCK_STREAM, 0);
+ if (clifd < 0) {
+ gpr_mu_unlock(g_mu);
+ return GRPC_OS_ERROR(errno, "Failed to create socket");
+ }
+ gpr_log(GPR_DEBUG, "start connect to %s", remote->str);
+ if (connect(clifd, remote_addr, (socklen_t)remote->addr.len) != 0) {
+ gpr_mu_unlock(g_mu);
+ close(clifd);
+ return GRPC_OS_ERROR(errno, "connect");
+ }
gpr_log(GPR_DEBUG, "wait");
while (g_nconnects == nconnects_before &&
gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
grpc_pollset_worker *worker = NULL;
- GPR_ASSERT(GRPC_LOG_IF_ERROR(
- "pollset_work",
- grpc_pollset_work(exec_ctx, g_pollset, &worker,
- gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+ grpc_error *err;
+ if ((err = grpc_pollset_work(exec_ctx, g_pollset, &worker,
+ gpr_now(GPR_CLOCK_MONOTONIC), deadline)) !=
+ GRPC_ERROR_NONE) {
+ gpr_mu_unlock(g_mu);
+ close(clifd);
+ return err;
+ }
gpr_mu_unlock(g_mu);
grpc_exec_ctx_finish(exec_ctx);
gpr_mu_lock(g_mu);
}
gpr_log(GPR_DEBUG, "wait done");
- GPR_ASSERT(g_nconnects == nconnects_before + 1);
+ if (g_nconnects != nconnects_before + 1) {
+ gpr_mu_unlock(g_mu);
+ close(clifd);
+ return GRPC_ERROR_CREATE("Didn't connect");
+ }
close(clifd);
*result = g_result;
gpr_mu_unlock(g_mu);
+ gpr_log(GPR_INFO, "Result (%d, %d) fd %d", result->port_index,
+ result->fd_index, result->server_fd);
+ grpc_tcp_server_unref(exec_ctx, result->server);
+ return GRPC_ERROR_NONE;
}
-/* Tests a tcp server with multiple ports. TODO(daniel-j-born): Multiple fds for
- the same port should be tested. */
-static void test_connect(unsigned n) {
+/* Tests a tcp server on "::" listeners with multiple ports. If channel_args is
+ non-NULL, pass them to the server. If dst_addrs is non-NULL, use valid addrs
+ as destination addrs (port is not set). If dst_addrs is NULL, use listener
+ addrs as destination addrs. If test_dst_addrs is true, test connectivity with
+ each destination address, set grpc_resolved_address::len=0 for failures, but
+ don't fail the overall unitest. */
+static void test_connect(size_t num_connects,
+ const grpc_channel_args *channel_args,
+ test_addrs *dst_addrs, bool test_dst_addrs) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_resolved_address resolved_addr;
grpc_resolved_address resolved_addr1;
- struct sockaddr_storage *addr = (struct sockaddr_storage *)resolved_addr.addr;
- struct sockaddr_storage *addr1 =
+ struct sockaddr_storage *const addr =
+ (struct sockaddr_storage *)resolved_addr.addr;
+ struct sockaddr_storage *const addr1 =
(struct sockaddr_storage *)resolved_addr1.addr;
unsigned svr_fd_count;
+ int port;
int svr_port;
unsigned svr1_fd_count;
int svr1_port;
grpc_tcp_server *s;
+ const unsigned num_ports = 2;
GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
- unsigned i;
+ grpc_tcp_server_create(&exec_ctx, NULL, channel_args, &s));
+ unsigned port_num;
server_weak_ref weak_ref;
server_weak_ref_init(&weak_ref);
+ server_weak_ref_set(&weak_ref, s);
LOG_TEST("test_connect");
- gpr_log(GPR_INFO, "clients=%d", n);
+ gpr_log(GPR_INFO,
+ "clients=%lu, num chan args=%lu, remote IP=%s, test_dst_addrs=%d",
+ (unsigned long)num_connects,
+ (unsigned long)(channel_args != NULL ? channel_args->num_args : 0),
+ dst_addrs != NULL ? "<specific>" : "::", test_dst_addrs);
memset(&resolved_addr, 0, sizeof(resolved_addr));
memset(&resolved_addr1, 0, sizeof(resolved_addr1));
resolved_addr.len = sizeof(struct sockaddr_storage);
resolved_addr1.len = sizeof(struct sockaddr_storage);
addr->ss_family = addr1->ss_family = AF_INET;
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_tcp_server_add_port(s, &resolved_addr, &svr_port));
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "grpc_tcp_server_add_port",
+ grpc_tcp_server_add_port(s, &resolved_addr, &svr_port)));
+ gpr_log(GPR_INFO, "Allocated port %d", svr_port);
GPR_ASSERT(svr_port > 0);
/* Cannot use wildcard (port==0), because add_port() will try to reuse the
same port as a previous add_port(). */
svr1_port = grpc_pick_unused_port_or_die();
+ GPR_ASSERT(svr1_port > 0);
+ gpr_log(GPR_INFO, "Picked unused port %d", svr1_port);
grpc_sockaddr_set_port(&resolved_addr1, svr1_port);
- GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr1, &svr_port) ==
+ GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr1, &port) ==
GRPC_ERROR_NONE &&
- svr_port == svr1_port);
+ port == svr1_port);
/* Bad port_index. */
GPR_ASSERT(grpc_tcp_server_port_fd_count(s, 2) == 0);
@@ -283,58 +366,70 @@ static void test_connect(unsigned n) {
svr1_fd_count = grpc_tcp_server_port_fd_count(s, 1);
GPR_ASSERT(svr1_fd_count >= 1);
- for (i = 0; i < svr_fd_count; ++i) {
- int fd = grpc_tcp_server_port_fd(s, 0, i);
- GPR_ASSERT(fd >= 0);
- if (i == 0) {
- GPR_ASSERT(getsockname(fd, (struct sockaddr *)addr,
- (socklen_t *)&resolved_addr.len) == 0);
- GPR_ASSERT(resolved_addr.len <= sizeof(*addr));
- }
- }
- for (i = 0; i < svr1_fd_count; ++i) {
- int fd = grpc_tcp_server_port_fd(s, 1, i);
- GPR_ASSERT(fd >= 0);
- if (i == 0) {
- GPR_ASSERT(getsockname(fd, (struct sockaddr *)addr1,
- (socklen_t *)&resolved_addr1.len) == 0);
- GPR_ASSERT(resolved_addr1.len <= sizeof(*addr1));
- }
- }
-
grpc_tcp_server_start(&exec_ctx, s, &g_pollset, 1, on_connect, NULL);
- for (i = 0; i < n; i++) {
- on_connect_result result;
- int svr_fd;
- on_connect_result_init(&result);
- tcp_connect(&exec_ctx, (struct sockaddr *)addr,
- (socklen_t)resolved_addr.len, &result);
- GPR_ASSERT(result.server_fd >= 0);
- svr_fd = result.server_fd;
- GPR_ASSERT(grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) ==
- result.server_fd);
- GPR_ASSERT(result.port_index == 0);
- GPR_ASSERT(result.fd_index < svr_fd_count);
- GPR_ASSERT(result.server == s);
- if (weak_ref.server == NULL) {
- server_weak_ref_set(&weak_ref, result.server);
+ if (dst_addrs != NULL) {
+ int ports[] = {svr_port, svr1_port};
+ for (port_num = 0; port_num < num_ports; ++port_num) {
+ size_t dst_idx;
+ size_t num_tested = 0;
+ for (dst_idx = 0; dst_idx < dst_addrs->naddrs; ++dst_idx) {
+ test_addr dst = dst_addrs->addrs[dst_idx];
+ on_connect_result result;
+ grpc_error *err;
+ if (dst.addr.len == 0) {
+ gpr_log(GPR_DEBUG, "Skipping test of non-functional local IP %s",
+ dst.str);
+ continue;
+ }
+ GPR_ASSERT(grpc_sockaddr_set_port(&dst.addr, ports[port_num]));
+ test_addr_init_str(&dst);
+ ++num_tested;
+ on_connect_result_init(&result);
+ if ((err = tcp_connect(&exec_ctx, &dst, &result)) == GRPC_ERROR_NONE &&
+ result.server_fd >= 0 && result.server == s) {
+ continue;
+ }
+ gpr_log(GPR_ERROR, "Failed to connect to %s: %s", dst.str,
+ grpc_error_string(err));
+ GPR_ASSERT(test_dst_addrs);
+ dst_addrs->addrs[dst_idx].addr.len = 0;
+ GRPC_ERROR_UNREF(err);
+ }
+ GPR_ASSERT(num_tested > 0);
+ }
+ } else {
+ for (port_num = 0; port_num < num_ports; ++port_num) {
+ const unsigned num_fds = grpc_tcp_server_port_fd_count(s, port_num);
+ unsigned fd_num;
+ for (fd_num = 0; fd_num < num_fds; ++fd_num) {
+ int fd = grpc_tcp_server_port_fd(s, port_num, fd_num);
+ size_t connect_num;
+ test_addr dst;
+ GPR_ASSERT(fd >= 0);
+ dst.addr.len = sizeof(dst.addr.addr);
+ GPR_ASSERT(getsockname(fd, (struct sockaddr *)dst.addr.addr,
+ (socklen_t *)&dst.addr.len) == 0);
+ GPR_ASSERT(dst.addr.len <= sizeof(dst.addr.addr));
+ test_addr_init_str(&dst);
+ gpr_log(GPR_INFO, "(%d, %d) fd %d family %s listening on %s", port_num,
+ fd_num, fd, sock_family_name(addr->ss_family), dst.str);
+ for (connect_num = 0; connect_num < num_connects; ++connect_num) {
+ on_connect_result result;
+ on_connect_result_init(&result);
+ GPR_ASSERT(GRPC_LOG_IF_ERROR("tcp_connect",
+ tcp_connect(&exec_ctx, &dst, &result)));
+ GPR_ASSERT(result.server_fd == fd);
+ GPR_ASSERT(result.port_index == port_num);
+ GPR_ASSERT(result.fd_index == fd_num);
+ GPR_ASSERT(result.server == s);
+ GPR_ASSERT(
+ grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) ==
+ result.server_fd);
+ }
+ }
}
- grpc_tcp_server_unref(&exec_ctx, result.server);
-
- on_connect_result_init(&result);
- tcp_connect(&exec_ctx, (struct sockaddr *)addr1,
- (socklen_t)resolved_addr1.len, &result);
- GPR_ASSERT(result.server_fd >= 0);
- GPR_ASSERT(result.server_fd != svr_fd);
- GPR_ASSERT(grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) ==
- result.server_fd);
- GPR_ASSERT(result.port_index == 1);
- GPR_ASSERT(result.fd_index < svr_fd_count);
- GPR_ASSERT(result.server == s);
- grpc_tcp_server_unref(&exec_ctx, result.server);
}
-
/* Weak ref to server valid until final unref. */
GPR_ASSERT(weak_ref.server != NULL);
GPR_ASSERT(grpc_tcp_server_port_fd(s, 0, 0) >= 0);
@@ -354,25 +449,71 @@ static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
int main(int argc, char **argv) {
grpc_closure destroyed;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_arg chan_args[] = {
+ {GRPC_ARG_INTEGER, GRPC_ARG_EXPAND_WILDCARD_ADDRS, {.integer = 1}}};
+ const grpc_channel_args channel_args = {1, chan_args};
+ struct ifaddrs *ifa = NULL;
+ struct ifaddrs *ifa_it;
+ // Zalloc dst_addrs to avoid oversized frames.
+ test_addrs *dst_addrs = gpr_zalloc(sizeof(*dst_addrs));
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
test_no_op();
test_no_op_with_start();
test_no_op_with_port();
test_no_op_with_port_and_start();
- test_connect(1);
- test_connect(10);
+
+ if (getifaddrs(&ifa) != 0 || ifa == NULL) {
+ gpr_log(GPR_ERROR, "getifaddrs: %s", strerror(errno));
+ return EXIT_FAILURE;
+ }
+ dst_addrs->naddrs = 0;
+ for (ifa_it = ifa; ifa_it != NULL && dst_addrs->naddrs < MAX_ADDRS;
+ ifa_it = ifa_it->ifa_next) {
+ if (ifa_it->ifa_addr == NULL) {
+ continue;
+ } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
+ dst_addrs->addrs[dst_addrs->naddrs].addr.len = sizeof(struct sockaddr_in);
+ } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
+ dst_addrs->addrs[dst_addrs->naddrs].addr.len =
+ sizeof(struct sockaddr_in6);
+ } else {
+ continue;
+ }
+ memcpy(dst_addrs->addrs[dst_addrs->naddrs].addr.addr, ifa_it->ifa_addr,
+ dst_addrs->addrs[dst_addrs->naddrs].addr.len);
+ GPR_ASSERT(
+ grpc_sockaddr_set_port(&dst_addrs->addrs[dst_addrs->naddrs].addr, 0));
+ test_addr_init_str(&dst_addrs->addrs[dst_addrs->naddrs]);
+ ++dst_addrs->naddrs;
+ }
+ freeifaddrs(ifa);
+ ifa = NULL;
+
+ /* Connect to same addresses as listeners. */
+ test_connect(1, NULL, NULL, false);
+ test_connect(10, NULL, NULL, false);
+
+ /* Set dst_addrs->addrs[i].len=0 for dst_addrs that are unreachable with a
+ "::" listener. */
+ test_connect(1, NULL, dst_addrs, true);
+
+ /* Test connect(2) with dst_addrs. */
+ test_connect(1, &channel_args, dst_addrs, false);
+ /* Test connect(2) with dst_addrs. */
+ test_connect(10, &channel_args, dst_addrs, false);
grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
grpc_schedule_on_exec_ctx);
grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
grpc_exec_ctx_finish(&exec_ctx);
grpc_shutdown();
+ gpr_free(dst_addrs);
gpr_free(g_pollset);
- return 0;
+ return EXIT_SUCCESS;
}
#else /* GRPC_POSIX_SOCKET */
diff --git a/test/core/iomgr/tcp_server_uv_test.c b/test/core/iomgr/tcp_server_uv_test.c
new file mode 100644
index 0000000000..0fc74599ea
--- /dev/null
+++ b/test/core/iomgr/tcp_server_uv_test.c
@@ -0,0 +1,339 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+// This test won't work except with libuv
+#ifdef GRPC_UV
+
+#include <uv.h>
+
+#include "src/core/lib/iomgr/tcp_server.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.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"
+
+#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x)
+
+static gpr_mu *g_mu;
+static grpc_pollset *g_pollset;
+static int g_nconnects = 0;
+
+typedef struct on_connect_result {
+ /* Owns a ref to server. */
+ grpc_tcp_server *server;
+ unsigned port_index;
+ unsigned fd_index;
+} on_connect_result;
+
+typedef struct server_weak_ref {
+ grpc_tcp_server *server;
+
+ /* arg is this server_weak_ref. */
+ grpc_closure server_shutdown;
+} server_weak_ref;
+
+static on_connect_result g_result = {NULL, 0, 0};
+
+static void on_connect_result_init(on_connect_result *result) {
+ result->server = NULL;
+ result->port_index = 0;
+ result->fd_index = 0;
+}
+
+static void on_connect_result_set(on_connect_result *result,
+ const grpc_tcp_server_acceptor *acceptor) {
+ result->server = grpc_tcp_server_ref(acceptor->from_server);
+ result->port_index = acceptor->port_index;
+ result->fd_index = acceptor->fd_index;
+}
+
+static void server_weak_ref_shutdown(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ server_weak_ref *weak_ref = arg;
+ weak_ref->server = NULL;
+}
+
+static void server_weak_ref_init(server_weak_ref *weak_ref) {
+ weak_ref->server = NULL;
+ grpc_closure_init(&weak_ref->server_shutdown, server_weak_ref_shutdown,
+ weak_ref, grpc_schedule_on_exec_ctx);
+}
+
+/* Make weak_ref->server_shutdown a shutdown_starting cb on server.
+ grpc_tcp_server promises that the server object will live until
+ weak_ref->server_shutdown has returned. A strong ref on grpc_tcp_server
+ should be held until server_weak_ref_set() returns to avoid a race where the
+ server is deleted before the shutdown_starting cb is added. */
+static void server_weak_ref_set(server_weak_ref *weak_ref,
+ grpc_tcp_server *server) {
+ grpc_tcp_server_shutdown_starting_add(server, &weak_ref->server_shutdown);
+ weak_ref->server = server;
+}
+
+static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
+ grpc_pollset *pollset,
+ grpc_tcp_server_acceptor *acceptor) {
+ grpc_endpoint_shutdown(exec_ctx, tcp, GRPC_ERROR_CREATE("Connected"));
+ grpc_endpoint_destroy(exec_ctx, tcp);
+
+ on_connect_result temp_result;
+ on_connect_result_set(&temp_result, acceptor);
+ gpr_free(acceptor);
+
+ gpr_mu_lock(g_mu);
+ g_result = temp_result;
+ g_nconnects++;
+ GPR_ASSERT(
+ GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL)));
+ gpr_mu_unlock(g_mu);
+}
+
+static void test_no_op(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_tcp_server *s;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
+ grpc_tcp_server_unref(&exec_ctx, s);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_no_op_with_start(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_tcp_server *s;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
+ LOG_TEST("test_no_op_with_start");
+ grpc_tcp_server_start(&exec_ctx, s, NULL, 0, on_connect, NULL);
+ grpc_tcp_server_unref(&exec_ctx, s);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_no_op_with_port(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resolved_address resolved_addr;
+ struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
+ grpc_tcp_server *s;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
+ LOG_TEST("test_no_op_with_port");
+
+ memset(&resolved_addr, 0, sizeof(resolved_addr));
+ resolved_addr.len = sizeof(struct sockaddr_in);
+ addr->sin_family = AF_INET;
+ int port;
+ GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) ==
+ GRPC_ERROR_NONE &&
+ port > 0);
+
+ grpc_tcp_server_unref(&exec_ctx, s);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_no_op_with_port_and_start(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resolved_address resolved_addr;
+ struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
+ grpc_tcp_server *s;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
+ LOG_TEST("test_no_op_with_port_and_start");
+ int port;
+
+ memset(&resolved_addr, 0, sizeof(resolved_addr));
+ resolved_addr.len = sizeof(struct sockaddr_in);
+ addr->sin_family = AF_INET;
+ GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) ==
+ GRPC_ERROR_NONE &&
+ port > 0);
+
+ grpc_tcp_server_start(&exec_ctx, s, NULL, 0, on_connect, NULL);
+
+ grpc_tcp_server_unref(&exec_ctx, s);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void connect_cb(uv_connect_t *req, int status) {
+ GPR_ASSERT(status == 0);
+ gpr_free(req);
+}
+
+static void close_cb(uv_handle_t *handle) { gpr_free(handle); }
+
+static void tcp_connect(grpc_exec_ctx *exec_ctx, const struct sockaddr *remote,
+ socklen_t remote_len, on_connect_result *result) {
+ gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
+ uv_tcp_t *client_handle = gpr_malloc(sizeof(uv_tcp_t));
+ uv_connect_t *req = gpr_malloc(sizeof(uv_connect_t));
+ int nconnects_before;
+
+ gpr_mu_lock(g_mu);
+ nconnects_before = g_nconnects;
+ on_connect_result_init(&g_result);
+ GPR_ASSERT(uv_tcp_init(uv_default_loop(), client_handle) == 0);
+ gpr_log(GPR_DEBUG, "start connect");
+ GPR_ASSERT(uv_tcp_connect(req, client_handle, remote, connect_cb) == 0);
+ gpr_log(GPR_DEBUG, "wait");
+ while (g_nconnects == nconnects_before &&
+ gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
+ grpc_pollset_worker *worker = NULL;
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "pollset_work",
+ grpc_pollset_work(exec_ctx, g_pollset, &worker,
+ gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+ gpr_mu_unlock(g_mu);
+ grpc_exec_ctx_finish(exec_ctx);
+ gpr_mu_lock(g_mu);
+ }
+ gpr_log(GPR_DEBUG, "wait done");
+ GPR_ASSERT(g_nconnects == nconnects_before + 1);
+ uv_close((uv_handle_t *)client_handle, close_cb);
+ *result = g_result;
+
+ gpr_mu_unlock(g_mu);
+}
+
+/* Tests a tcp server with multiple ports. */
+static void test_connect(unsigned n) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resolved_address resolved_addr;
+ grpc_resolved_address resolved_addr1;
+ struct sockaddr_storage *addr = (struct sockaddr_storage *)resolved_addr.addr;
+ struct sockaddr_storage *addr1 =
+ (struct sockaddr_storage *)resolved_addr1.addr;
+ int svr_port;
+ int svr1_port;
+ grpc_tcp_server *s;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
+ unsigned i;
+ server_weak_ref weak_ref;
+ server_weak_ref_init(&weak_ref);
+ LOG_TEST("test_connect");
+ gpr_log(GPR_INFO, "clients=%d", n);
+ memset(&resolved_addr, 0, sizeof(resolved_addr));
+ memset(&resolved_addr1, 0, sizeof(resolved_addr1));
+ resolved_addr.len = sizeof(struct sockaddr_storage);
+ resolved_addr1.len = sizeof(struct sockaddr_storage);
+ addr->ss_family = addr1->ss_family = AF_INET;
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_add_port(s, &resolved_addr, &svr_port));
+ GPR_ASSERT(svr_port > 0);
+ GPR_ASSERT(uv_ip6_addr("::", svr_port, (struct sockaddr_in6 *)addr) == 0);
+ /* Cannot use wildcard (port==0), because add_port() will try to reuse the
+ same port as a previous add_port(). */
+ svr1_port = grpc_pick_unused_port_or_die();
+ grpc_sockaddr_set_port(&resolved_addr1, svr1_port);
+ GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr1, &svr_port) ==
+ GRPC_ERROR_NONE &&
+ svr_port == svr1_port);
+
+ grpc_tcp_server_start(&exec_ctx, s, &g_pollset, 1, on_connect, NULL);
+
+ GPR_ASSERT(uv_ip6_addr("::", svr_port, (struct sockaddr_in6 *)addr1) == 0);
+
+ for (i = 0; i < n; i++) {
+ on_connect_result result;
+ on_connect_result_init(&result);
+ tcp_connect(&exec_ctx, (struct sockaddr *)addr,
+ (socklen_t)resolved_addr.len, &result);
+ GPR_ASSERT(result.port_index == 0);
+ GPR_ASSERT(result.server == s);
+ if (weak_ref.server == NULL) {
+ server_weak_ref_set(&weak_ref, result.server);
+ }
+ grpc_tcp_server_unref(&exec_ctx, result.server);
+
+ on_connect_result_init(&result);
+ tcp_connect(&exec_ctx, (struct sockaddr *)addr1,
+ (socklen_t)resolved_addr1.len, &result);
+ GPR_ASSERT(result.port_index == 1);
+ GPR_ASSERT(result.server == s);
+ grpc_tcp_server_unref(&exec_ctx, result.server);
+ }
+
+ /* Weak ref to server valid until final unref. */
+ GPR_ASSERT(weak_ref.server != NULL);
+
+ grpc_tcp_server_unref(&exec_ctx, s);
+ grpc_exec_ctx_finish(&exec_ctx);
+
+ /* Weak ref lost. */
+ GPR_ASSERT(weak_ref.server == NULL);
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
+ grpc_error *error) {
+ grpc_pollset_destroy(p);
+}
+
+int main(int argc, char **argv) {
+ grpc_closure destroyed;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_test_init(argc, argv);
+ grpc_init();
+ g_pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset_init(g_pollset, &g_mu);
+
+ test_no_op();
+ test_no_op_with_start();
+ test_no_op_with_port();
+ test_no_op_with_port_and_start();
+ test_connect(1);
+ test_connect(10);
+
+ grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_shutdown();
+ gpr_free(g_pollset);
+ return 0;
+}
+
+#else /* GRPC_UV */
+
+int main(int argc, char **argv) { return 1; }
+
+#endif /* GRPC_UV */
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 8d7ac3fdaa..85ad5277cc 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -31,6 +31,11 @@
*
*/
+#include "src/core/lib/iomgr/port.h"
+
+// This test only works with the generic timer implementation
+#ifdef GRPC_TIMER_USE_GENERIC
+
#include "src/core/lib/iomgr/timer.h"
#include <string.h>
@@ -169,3 +174,9 @@ int main(int argc, char **argv) {
destruction_test();
return 0;
}
+
+#else /* GRPC_TIMER_USE_GENERIC */
+
+int main(int argc, char **argv) { return 1; }
+
+#endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index ba572017a2..d57a37b2a9 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -237,7 +237,7 @@ int main(int argc, char **argv) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
test_no_op();
diff --git a/test/core/json/BUILD b/test/core/json/BUILD
index 05d4c6e0c5..f5a877e6af 100644
--- a/test/core/json/BUILD
+++ b/test/core/json/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2016, Google Inc.
+# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -39,3 +39,32 @@ grpc_fuzzer(
copts = ["-std=c99"],
)
+cc_binary(
+ name = "json_rewrite",
+ srcs = ["json_rewrite.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ testonly = 1,
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "json_rewrite_test",
+ srcs = ["json_rewrite_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99'],
+ data = ["rewrite_test_input.json", "rewrite_test_output_condensed.json", "rewrite_test_output_indented.json", ":json_stream_error_test"]
+)
+
+cc_test(
+ name = "json_stream_error_test",
+ srcs = ["json_stream_error_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "json_test",
+ srcs = ["json_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/memory_usage/client.c b/test/core/memory_usage/client.c
index 09f0e2d867..107abbc1b3 100644
--- a/test/core/memory_usage/client.c
+++ b/test/core/memory_usage/client.c
@@ -43,6 +43,7 @@
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
+#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#include "test/core/util/memory_counters.h"
#include "test/core/util/test_config.h"
@@ -310,6 +311,29 @@ int main(int argc, char **argv) {
server_calls_end.total_size_relative -
after_server_create.total_size_relative);
+ const char *csv_file = "memory_usage.csv";
+ FILE *csv = fopen(csv_file, "w");
+ if (csv) {
+ char *env_build = gpr_getenv("BUILD_NUMBER");
+ char *env_job = gpr_getenv("JOB_NAME");
+ fprintf(csv, "%f,%zi,%zi,%f,%zi,%s,%s\n",
+ (double)(client_calls_inflight.total_size_relative -
+ client_benchmark_calls_start.total_size_relative) /
+ benchmark_iterations,
+ client_channel_end.total_size_relative -
+ client_channel_start.total_size_relative,
+ after_server_create.total_size_relative -
+ before_server_create.total_size_relative,
+ (double)(server_calls_inflight.total_size_relative -
+ server_benchmark_calls_start.total_size_relative) /
+ benchmark_iterations,
+ server_calls_end.total_size_relative -
+ after_server_create.total_size_relative,
+ env_build == NULL ? "" : env_build, env_job == NULL ? "" : env_job);
+ fclose(csv);
+ gpr_log(GPR_INFO, "Summary written to %s", csv_file);
+ }
+
grpc_memory_counters_destroy();
return 0;
}
diff --git a/test/core/network_benchmarks/BUILD b/test/core/network_benchmarks/BUILD
new file mode 100644
index 0000000000..a5209de4c9
--- /dev/null
+++ b/test/core/network_benchmarks/BUILD
@@ -0,0 +1,37 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_binary(
+ name = "low_level_ping_pong",
+ srcs = ["low_level_ping_pong.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/security/BUILD b/test/core/security/BUILD
new file mode 100644
index 0000000000..e750c39b7c
--- /dev/null
+++ b/test/core/security/BUILD
@@ -0,0 +1,104 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+grpc_fuzzer(
+ name = "ssl_server_fuzzer",
+ srcs = ["ssl_server_fuzzer.c"],
+ deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+ corpus = "corpus",
+ copts = ["-std=c99"],
+)
+
+cc_library(
+ name = "oauth2_utils",
+ srcs = ["oauth2_utils.c"],
+ hdrs = ["oauth2_utils.h"],
+ deps = ["//:grpc"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "auth_context_test",
+ srcs = ["auth_context_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "b64_test",
+ srcs = ["b64_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "credentials_test",
+ srcs = ["credentials_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "secure_endpoint_test",
+ srcs = ["secure_endpoint_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/iomgr:endpoint_tests"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "security_connector_test",
+ srcs = ["security_connector_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_binary(
+ name = "create_jwt",
+ srcs = ["create_jwt.c"],
+ deps = ["//:grpc", "//:gpr"],
+ copts = ['-std=c99']
+)
+
+cc_binary(
+ name = "fetch_oauth2",
+ srcs = ["fetch_oauth2.c"],
+ deps = ["//:grpc", "//:gpr", ":oauth2_utils"],
+ copts = ['-std=c99']
+)
+
+cc_binary(
+ name = "verify_jwt",
+ srcs = ["verify_jwt.c"],
+ deps = ["//:grpc", "//:gpr"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index a9bd976a39..0a73f67528 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -386,9 +386,9 @@ static void test_jwt_verifier_google_email_issuer_success(void) {
GPR_ASSERT(jwt != NULL);
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_success, (void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -420,9 +420,9 @@ static void test_jwt_verifier_custom_email_issuer_success(void) {
GPR_ASSERT(jwt != NULL);
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_success, (void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -469,9 +469,9 @@ static void test_jwt_verifier_url_issuer_success(void) {
GPR_ASSERT(jwt != NULL);
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_success, (void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -511,9 +511,9 @@ static void test_jwt_verifier_url_issuer_bad_config(void) {
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_key_retrieval_error,
(void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -534,9 +534,9 @@ static void test_jwt_verifier_bad_json_key(void) {
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_key_retrieval_error,
(void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -588,9 +588,9 @@ static void test_jwt_verifier_bad_signature(void) {
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
on_verification_bad_signature,
(void *)expected_user_data);
- grpc_exec_ctx_finish(&exec_ctx);
gpr_free(jwt);
- grpc_jwt_verifier_destroy(verifier);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
+ grpc_exec_ctx_finish(&exec_ctx);
grpc_httpcli_set_override(NULL, NULL);
}
@@ -619,8 +619,8 @@ static void test_jwt_verifier_bad_format(void) {
grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, "bad jwt",
expected_audience, on_verification_bad_format,
(void *)expected_user_data);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
grpc_exec_ctx_finish(&exec_ctx);
- grpc_jwt_verifier_destroy(verifier);
grpc_httpcli_set_override(NULL, NULL);
}
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index ff77af908a..f0550db1d0 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -87,7 +87,7 @@ char *grpc_test_fetch_oauth2_token_with_credentials(
grpc_closure do_nothing_closure;
grpc_auth_metadata_context null_ctx = {"", "", NULL, NULL};
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &request.mu);
request.pops = grpc_polling_entity_create_from_pollset(pollset);
request.is_done = 0;
diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c
index ea136fbdcf..b6421f19ab 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -98,7 +98,7 @@ int main(int argc, char **argv) {
goto end;
}
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &sync.mu);
sync.pops = grpc_polling_entity_create_from_pollset(pollset);
sync.is_done = 0;
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 97e9c3d6db..d2b76bae39 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -190,7 +190,7 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = gpr_malloc(grpc_pollset_size());
+ g_pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(g_pollset, &g_mu);
grpc_endpoint_tests(configs[0], g_pollset, g_mu);
test_leftover(configs[1], 1);
diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c
index bbd4a67ac1..f8a7d64809 100644
--- a/test/core/security/verify_jwt.c
+++ b/test/core/security/verify_jwt.c
@@ -106,7 +106,7 @@ int main(int argc, char **argv) {
grpc_init();
- sync.pollset = gpr_malloc(grpc_pollset_size());
+ sync.pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(sync.pollset, &sync.mu);
sync.is_done = 0;
@@ -123,14 +123,15 @@ int main(int argc, char **argv) {
gpr_inf_future(GPR_CLOCK_MONOTONIC))))
sync.is_done = true;
gpr_mu_unlock(sync.mu);
- grpc_exec_ctx_finish(&exec_ctx);
+ grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(sync.mu);
}
gpr_mu_unlock(sync.mu);
gpr_free(sync.pollset);
- grpc_jwt_verifier_destroy(verifier);
+ grpc_jwt_verifier_destroy(&exec_ctx, verifier);
+ grpc_exec_ctx_finish(&exec_ctx);
gpr_cmdline_destroy(cl);
grpc_shutdown();
return !sync.success;
diff --git a/test/core/slice/BUILD b/test/core/slice/BUILD
new file mode 100644
index 0000000000..67a4706348
--- /dev/null
+++ b/test/core/slice/BUILD
@@ -0,0 +1,54 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
+
+grpc_fuzzer(
+ name = "percent_decode_fuzzer",
+ srcs = ["percent_decode_fuzzer.c"],
+ deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+ corpus = "response_corpus",
+ copts = ["-std=c99"],
+)
+
+cc_test(
+ name = "percent_encoding_test",
+ srcs = ["percent_encoding_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "slice_buffer_test",
+ srcs = ["slice_string_helpers_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/slice/percent_encoding_test.c b/test/core/slice/percent_encoding_test.c
index 222e695fd4..89f8154955 100644
--- a/test/core/slice/percent_encoding_test.c
+++ b/test/core/slice/percent_encoding_test.c
@@ -146,6 +146,7 @@ int main(int argc, char **argv) {
TEST_VECTOR("\x0f", "%0F", grpc_url_percent_encoding_unreserved_bytes);
TEST_VECTOR("\xff", "%FF", grpc_url_percent_encoding_unreserved_bytes);
TEST_VECTOR("\xee", "%EE", grpc_url_percent_encoding_unreserved_bytes);
+ TEST_VECTOR("%2", "%252", grpc_url_percent_encoding_unreserved_bytes);
TEST_NONCONFORMANT_VECTOR("%", "%",
grpc_url_percent_encoding_unreserved_bytes);
TEST_NONCONFORMANT_VECTOR("%A", "%A",
diff --git a/test/core/support/BUILD b/test/core/support/BUILD
index dfe952eb37..3183510db9 100644
--- a/test/core/support/BUILD
+++ b/test/core/support/BUILD
@@ -27,6 +27,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+licenses(["notice"]) # 3-clause BSD
+
cc_test(
name = "alloc_test",
srcs = ["alloc_test.c"],
@@ -119,6 +121,13 @@ cc_test(
)
cc_test(
+ name = "spinlock_test",
+ srcs = ["spinlock_test.c"],
+ deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
name = "sync_test",
srcs = ["sync_test.c"],
deps = ["//:gpr", "//test/core/util:gpr_test_util"],
diff --git a/test/core/support/alloc_test.c b/test/core/support/alloc_test.c
index 451c580054..72e99de867 100644
--- a/test/core/support/alloc_test.c
+++ b/test/core/support/alloc_test.c
@@ -47,7 +47,7 @@ static void test_custom_allocs() {
const gpr_allocation_functions default_fns = gpr_get_allocation_functions();
intptr_t addr_to_free = 0;
char *i;
- gpr_allocation_functions fns = {fake_malloc, fake_realloc, fake_free};
+ gpr_allocation_functions fns = {fake_malloc, NULL, fake_realloc, fake_free};
gpr_set_allocation_functions(fns);
GPR_ASSERT((void *)(size_t)0xdeadbeef == gpr_malloc(0xdeadbeef));
diff --git a/test/core/support/spinlock_test.c b/test/core/support/spinlock_test.c
new file mode 100644
index 0000000000..c70e76c7ea
--- /dev/null
+++ b/test/core/support/spinlock_test.c
@@ -0,0 +1,161 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test of gpr synchronization support. */
+
+#include "src/core/lib/support/spinlock.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "test/core/util/test_config.h"
+
+/* ------------------------------------------------- */
+/* Tests for gpr_spinlock. */
+struct test {
+ int thread_count; /* number of threads */
+ gpr_thd_id *threads;
+
+ int64_t iterations; /* number of iterations per thread */
+ int64_t counter;
+ int incr_step; /* how much to increment/decrement refcount each time */
+
+ gpr_spinlock mu; /* protects iterations, counter */
+};
+
+/* Return pointer to a new struct test. */
+static struct test *test_new(int threads, int64_t iterations, int incr_step) {
+ struct test *m = gpr_malloc(sizeof(*m));
+ m->thread_count = threads;
+ m->threads = gpr_malloc(sizeof(*m->threads) * (size_t)threads);
+ m->iterations = iterations;
+ m->counter = 0;
+ m->thread_count = 0;
+ m->incr_step = incr_step;
+ m->mu = GPR_SPINLOCK_INITIALIZER;
+ return m;
+}
+
+/* Return pointer to a new struct test. */
+static void test_destroy(struct test *m) {
+ gpr_free(m->threads);
+ gpr_free(m);
+}
+
+/* Create m->threads threads, each running (*body)(m) */
+static void test_create_threads(struct test *m, void (*body)(void *arg)) {
+ int i;
+ for (i = 0; i != m->thread_count; i++) {
+ gpr_thd_options opt = gpr_thd_options_default();
+ gpr_thd_options_set_joinable(&opt);
+ GPR_ASSERT(gpr_thd_new(&m->threads[i], body, m, &opt));
+ }
+}
+
+/* Wait until all threads report done. */
+static void test_wait(struct test *m) {
+ int i;
+ for (i = 0; i != m->thread_count; i++) {
+ gpr_thd_join(m->threads[i]);
+ }
+}
+
+/* Test several threads running (*body)(struct test *m) for increasing settings
+ of m->iterations, until about timeout_s to 2*timeout_s seconds have elapsed.
+ If extra!=NULL, run (*extra)(m) in an additional thread.
+ incr_step controls by how much m->refcount should be incremented/decremented
+ (if at all) each time in the tests.
+ */
+static void test(const char *name, void (*body)(void *m), int timeout_s,
+ int incr_step) {
+ int64_t iterations = 1024;
+ struct test *m;
+ gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
+ gpr_timespec time_taken;
+ gpr_timespec deadline = gpr_time_add(
+ start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
+ fprintf(stderr, "%s:", name);
+ while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
+ iterations <<= 1;
+ fprintf(stderr, " %ld", (long)iterations);
+ m = test_new(10, iterations, incr_step);
+ test_create_threads(m, body);
+ test_wait(m);
+ if (m->counter != m->thread_count * m->iterations * m->incr_step) {
+ fprintf(stderr, "counter %ld threads %d iterations %ld\n",
+ (long)m->counter, m->thread_count, (long)m->iterations);
+ GPR_ASSERT(0);
+ }
+ test_destroy(m);
+ }
+ time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
+ fprintf(stderr, " done %lld.%09d s\n", (long long)time_taken.tv_sec,
+ (int)time_taken.tv_nsec);
+}
+
+/* Increment m->counter on each iteration; then mark thread as done. */
+static void inc(void *v /*=m*/) {
+ struct test *m = v;
+ int64_t i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_spinlock_lock(&m->mu);
+ m->counter++;
+ gpr_spinlock_unlock(&m->mu);
+ }
+}
+
+/* Increment m->counter under lock acquired with trylock, m->iterations times;
+ then mark thread as done. */
+static void inctry(void *v /*=m*/) {
+ struct test *m = v;
+ int64_t i;
+ for (i = 0; i != m->iterations;) {
+ if (gpr_spinlock_trylock(&m->mu)) {
+ m->counter++;
+ gpr_spinlock_unlock(&m->mu);
+ i++;
+ }
+ }
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+ grpc_test_init(argc, argv);
+ test("spinlock", &inc, 1, 1);
+ test("spinlock try", &inctry, 1, 1);
+ return 0;
+}
diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD
new file mode 100644
index 0000000000..3d5e26ced3
--- /dev/null
+++ b/test/core/surface/BUILD
@@ -0,0 +1,188 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "alarm_test",
+ srcs = ["alarm_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "grpc_byte_buffer_reader_test",
+ srcs = ["byte_buffer_reader_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "channel_create_test",
+ srcs = ["channel_create_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "grpc_completion_queue_test",
+ srcs = ["completion_queue_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "concurrent_connectivity_test",
+ srcs = ["concurrent_connectivity_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "init_test",
+ srcs = ["init_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "grpc_invalid_channel_args_test",
+ srcs = ["invalid_channel_args_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "lame_client_test",
+ srcs = ["lame_client_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/end2end:cq_verifier",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "public_headers_must_be_c89",
+ srcs = ["public_headers_must_be_c89.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "secure_channel_create_test",
+ srcs = ["secure_channel_create_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "sequential_connectivity_test",
+ srcs = ["sequential_connectivity_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/end2end:ssl_test_data",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "server_chttp2_test",
+ srcs = ["server_chttp2_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+cc_test(
+ name = "server_test",
+ srcs = ["server_test.c"],
+ copts = ["-std=c99"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index b8ea90921a..07f6a9869b 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -35,7 +35,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/lib/iomgr/iomgr.h"
@@ -194,223 +193,6 @@ static void test_pluck_after_shutdown(void) {
grpc_completion_queue_destroy(cc);
}
-struct thread_state {
- grpc_completion_queue *cc;
- void *tag;
-};
-
-static void pluck_one(void *arg) {
- struct thread_state *state = arg;
- grpc_completion_queue_pluck(state->cc, state->tag,
- gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-}
-
-static void test_too_many_plucks(void) {
- grpc_event ev;
- grpc_completion_queue *cc;
- void *tags[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
- grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
- gpr_thd_id thread_ids[GPR_ARRAY_SIZE(tags)];
- struct thread_state thread_states[GPR_ARRAY_SIZE(tags)];
- gpr_thd_options thread_options = gpr_thd_options_default();
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- unsigned i, j;
-
- LOG_TEST("test_too_many_plucks");
-
- cc = grpc_completion_queue_create(NULL);
- gpr_thd_options_set_joinable(&thread_options);
-
- for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
- tags[i] = create_test_tag();
- for (j = 0; j < i; j++) {
- GPR_ASSERT(tags[i] != tags[j]);
- }
- thread_states[i].cc = cc;
- thread_states[i].tag = tags[i];
- gpr_thd_new(thread_ids + i, pluck_one, thread_states + i, &thread_options);
- }
-
- /* wait until all other threads are plucking */
- gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1000));
-
- ev = grpc_completion_queue_pluck(cc, create_test_tag(),
- gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT);
-
- for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
- grpc_cq_begin_op(cc, tags[i]);
- grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
- do_nothing_end_completion, NULL, &completions[i]);
- }
-
- for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
- gpr_thd_join(thread_ids[i]);
- }
-
- shutdown_and_destroy(cc);
- grpc_exec_ctx_finish(&exec_ctx);
-}
-
-#define TEST_THREAD_EVENTS 10000
-
-typedef struct test_thread_options {
- gpr_event on_started;
- gpr_event *phase1;
- gpr_event on_phase1_done;
- gpr_event *phase2;
- gpr_event on_finished;
- size_t events_triggered;
- int id;
- grpc_completion_queue *cc;
-} test_thread_options;
-
-gpr_timespec ten_seconds_time(void) {
- return grpc_timeout_seconds_to_deadline(10);
-}
-
-static void free_completion(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_cq_completion *completion) {
- gpr_free(completion);
-}
-
-static void producer_thread(void *arg) {
- test_thread_options *opt = arg;
- int i;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- gpr_log(GPR_INFO, "producer %d started", opt->id);
- gpr_event_set(&opt->on_started, (void *)(intptr_t)1);
- GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
-
- gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
- for (i = 0; i < TEST_THREAD_EVENTS; i++) {
- grpc_cq_begin_op(opt->cc, (void *)(intptr_t)1);
- }
-
- gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
- gpr_event_set(&opt->on_phase1_done, (void *)(intptr_t)1);
- GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
-
- gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
- for (i = 0; i < TEST_THREAD_EVENTS; i++) {
- grpc_cq_end_op(&exec_ctx, opt->cc, (void *)(intptr_t)1, GRPC_ERROR_NONE,
- free_completion, NULL,
- gpr_malloc(sizeof(grpc_cq_completion)));
- opt->events_triggered++;
- grpc_exec_ctx_finish(&exec_ctx);
- }
-
- gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
- gpr_event_set(&opt->on_finished, (void *)(intptr_t)1);
- grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void consumer_thread(void *arg) {
- test_thread_options *opt = arg;
- grpc_event ev;
-
- gpr_log(GPR_INFO, "consumer %d started", opt->id);
- gpr_event_set(&opt->on_started, (void *)(intptr_t)1);
- GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
-
- gpr_log(GPR_INFO, "consumer %d phase 1", opt->id);
-
- gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id);
- gpr_event_set(&opt->on_phase1_done, (void *)(intptr_t)1);
- GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
-
- gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
- for (;;) {
- ev = grpc_completion_queue_next(opt->cc, ten_seconds_time(), NULL);
- switch (ev.type) {
- case GRPC_OP_COMPLETE:
- GPR_ASSERT(ev.success);
- opt->events_triggered++;
- break;
- case GRPC_QUEUE_SHUTDOWN:
- gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id);
- gpr_event_set(&opt->on_finished, (void *)(intptr_t)1);
- return;
- case GRPC_QUEUE_TIMEOUT:
- gpr_log(GPR_ERROR, "Invalid timeout received");
- abort();
- }
- }
-}
-
-static void test_threading(size_t producers, size_t consumers) {
- test_thread_options *options =
- gpr_malloc((producers + consumers) * sizeof(test_thread_options));
- gpr_event phase1 = GPR_EVENT_INIT;
- gpr_event phase2 = GPR_EVENT_INIT;
- grpc_completion_queue *cc = grpc_completion_queue_create(NULL);
- size_t i;
- size_t total_consumed = 0;
- static int optid = 101;
-
- gpr_log(GPR_INFO, "%s: %" PRIuPTR " producers, %" PRIuPTR " consumers",
- "test_threading", producers, consumers);
-
- /* start all threads: they will wait for phase1 */
- for (i = 0; i < producers + consumers; i++) {
- gpr_thd_id id;
- gpr_event_init(&options[i].on_started);
- gpr_event_init(&options[i].on_phase1_done);
- gpr_event_init(&options[i].on_finished);
- options[i].phase1 = &phase1;
- options[i].phase2 = &phase2;
- options[i].events_triggered = 0;
- options[i].cc = cc;
- options[i].id = optid++;
- GPR_ASSERT(gpr_thd_new(&id,
- i < producers ? producer_thread : consumer_thread,
- options + i, NULL));
- gpr_event_wait(&options[i].on_started, ten_seconds_time());
- }
-
- /* start phase1: producers will pre-declare all operations they will
- complete */
- gpr_log(GPR_INFO, "start phase 1");
- gpr_event_set(&phase1, (void *)(intptr_t)1);
-
- gpr_log(GPR_INFO, "wait phase 1");
- for (i = 0; i < producers + consumers; i++) {
- GPR_ASSERT(gpr_event_wait(&options[i].on_phase1_done, ten_seconds_time()));
- }
- gpr_log(GPR_INFO, "done phase 1");
-
- /* start phase2: operations will complete, and consumers will consume them */
- gpr_log(GPR_INFO, "start phase 2");
- gpr_event_set(&phase2, (void *)(intptr_t)1);
-
- /* in parallel, we shutdown the completion channel - all events should still
- be consumed */
- grpc_completion_queue_shutdown(cc);
-
- /* join all threads */
- gpr_log(GPR_INFO, "wait phase 2");
- for (i = 0; i < producers + consumers; i++) {
- GPR_ASSERT(gpr_event_wait(&options[i].on_finished, ten_seconds_time()));
- }
- gpr_log(GPR_INFO, "done phase 2");
-
- /* destroy the completion channel */
- grpc_completion_queue_destroy(cc);
-
- /* verify that everything was produced and consumed */
- for (i = 0; i < producers + consumers; i++) {
- if (i < producers) {
- GPR_ASSERT(options[i].events_triggered == TEST_THREAD_EVENTS);
- } else {
- total_consumed += options[i].events_triggered;
- }
- }
- GPR_ASSERT(total_consumed == producers * TEST_THREAD_EVENTS);
-
- gpr_free(options);
-}
-
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
@@ -422,11 +204,6 @@ int main(int argc, char **argv) {
test_cq_end_op();
test_pluck();
test_pluck_after_shutdown();
- test_too_many_plucks();
- test_threading(1, 1);
- test_threading(1, 10);
- test_threading(10, 1);
- test_threading(10, 10);
grpc_shutdown();
return 0;
}
diff --git a/test/core/surface/completion_queue_threading_test.c b/test/core/surface/completion_queue_threading_test.c
new file mode 100644
index 0000000000..2d55ead843
--- /dev/null
+++ b/test/core/surface/completion_queue_threading_test.c
@@ -0,0 +1,290 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/completion_queue.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/iomgr.h"
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
+
+static void *create_test_tag(void) {
+ static intptr_t i = 0;
+ return (void *)(++i);
+}
+
+/* helper for tests to shutdown correctly and tersely */
+static void shutdown_and_destroy(grpc_completion_queue *cc) {
+ grpc_event ev;
+ grpc_completion_queue_shutdown(cc);
+ ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+ GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
+ grpc_completion_queue_destroy(cc);
+}
+
+static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_cq_completion *c) {}
+
+struct thread_state {
+ grpc_completion_queue *cc;
+ void *tag;
+};
+
+static void pluck_one(void *arg) {
+ struct thread_state *state = arg;
+ grpc_completion_queue_pluck(state->cc, state->tag,
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+}
+
+static void test_too_many_plucks(void) {
+ grpc_event ev;
+ grpc_completion_queue *cc;
+ void *tags[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
+ grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
+ gpr_thd_id thread_ids[GPR_ARRAY_SIZE(tags)];
+ struct thread_state thread_states[GPR_ARRAY_SIZE(tags)];
+ gpr_thd_options thread_options = gpr_thd_options_default();
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ unsigned i, j;
+
+ LOG_TEST("test_too_many_plucks");
+
+ cc = grpc_completion_queue_create(NULL);
+ gpr_thd_options_set_joinable(&thread_options);
+
+ for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+ tags[i] = create_test_tag();
+ for (j = 0; j < i; j++) {
+ GPR_ASSERT(tags[i] != tags[j]);
+ }
+ thread_states[i].cc = cc;
+ thread_states[i].tag = tags[i];
+ gpr_thd_new(thread_ids + i, pluck_one, thread_states + i, &thread_options);
+ }
+
+ /* wait until all other threads are plucking */
+ gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1000));
+
+ ev = grpc_completion_queue_pluck(cc, create_test_tag(),
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+ GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT);
+
+ for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+ grpc_cq_begin_op(cc, tags[i]);
+ grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
+ do_nothing_end_completion, NULL, &completions[i]);
+ }
+
+ for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+ gpr_thd_join(thread_ids[i]);
+ }
+
+ shutdown_and_destroy(cc);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+#define TEST_THREAD_EVENTS 10000
+
+typedef struct test_thread_options {
+ gpr_event on_started;
+ gpr_event *phase1;
+ gpr_event on_phase1_done;
+ gpr_event *phase2;
+ gpr_event on_finished;
+ size_t events_triggered;
+ int id;
+ grpc_completion_queue *cc;
+} test_thread_options;
+
+gpr_timespec ten_seconds_time(void) {
+ return grpc_timeout_seconds_to_deadline(10);
+}
+
+static void free_completion(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_cq_completion *completion) {
+ gpr_free(completion);
+}
+
+static void producer_thread(void *arg) {
+ test_thread_options *opt = arg;
+ int i;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ gpr_log(GPR_INFO, "producer %d started", opt->id);
+ gpr_event_set(&opt->on_started, (void *)(intptr_t)1);
+ GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
+
+ gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
+ for (i = 0; i < TEST_THREAD_EVENTS; i++) {
+ grpc_cq_begin_op(opt->cc, (void *)(intptr_t)1);
+ }
+
+ gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
+ gpr_event_set(&opt->on_phase1_done, (void *)(intptr_t)1);
+ GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
+
+ gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
+ for (i = 0; i < TEST_THREAD_EVENTS; i++) {
+ grpc_cq_end_op(&exec_ctx, opt->cc, (void *)(intptr_t)1, GRPC_ERROR_NONE,
+ free_completion, NULL,
+ gpr_malloc(sizeof(grpc_cq_completion)));
+ opt->events_triggered++;
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+
+ gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
+ gpr_event_set(&opt->on_finished, (void *)(intptr_t)1);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void consumer_thread(void *arg) {
+ test_thread_options *opt = arg;
+ grpc_event ev;
+
+ gpr_log(GPR_INFO, "consumer %d started", opt->id);
+ gpr_event_set(&opt->on_started, (void *)(intptr_t)1);
+ GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
+
+ gpr_log(GPR_INFO, "consumer %d phase 1", opt->id);
+
+ gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id);
+ gpr_event_set(&opt->on_phase1_done, (void *)(intptr_t)1);
+ GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
+
+ gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
+ for (;;) {
+ ev = grpc_completion_queue_next(opt->cc, ten_seconds_time(), NULL);
+ switch (ev.type) {
+ case GRPC_OP_COMPLETE:
+ GPR_ASSERT(ev.success);
+ opt->events_triggered++;
+ break;
+ case GRPC_QUEUE_SHUTDOWN:
+ gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id);
+ gpr_event_set(&opt->on_finished, (void *)(intptr_t)1);
+ return;
+ case GRPC_QUEUE_TIMEOUT:
+ gpr_log(GPR_ERROR, "Invalid timeout received");
+ abort();
+ }
+ }
+}
+
+static void test_threading(size_t producers, size_t consumers) {
+ test_thread_options *options =
+ gpr_malloc((producers + consumers) * sizeof(test_thread_options));
+ gpr_event phase1 = GPR_EVENT_INIT;
+ gpr_event phase2 = GPR_EVENT_INIT;
+ grpc_completion_queue *cc = grpc_completion_queue_create(NULL);
+ size_t i;
+ size_t total_consumed = 0;
+ static int optid = 101;
+
+ gpr_log(GPR_INFO, "%s: %" PRIuPTR " producers, %" PRIuPTR " consumers",
+ "test_threading", producers, consumers);
+
+ /* start all threads: they will wait for phase1 */
+ for (i = 0; i < producers + consumers; i++) {
+ gpr_thd_id id;
+ gpr_event_init(&options[i].on_started);
+ gpr_event_init(&options[i].on_phase1_done);
+ gpr_event_init(&options[i].on_finished);
+ options[i].phase1 = &phase1;
+ options[i].phase2 = &phase2;
+ options[i].events_triggered = 0;
+ options[i].cc = cc;
+ options[i].id = optid++;
+ GPR_ASSERT(gpr_thd_new(&id,
+ i < producers ? producer_thread : consumer_thread,
+ options + i, NULL));
+ gpr_event_wait(&options[i].on_started, ten_seconds_time());
+ }
+
+ /* start phase1: producers will pre-declare all operations they will
+ complete */
+ gpr_log(GPR_INFO, "start phase 1");
+ gpr_event_set(&phase1, (void *)(intptr_t)1);
+
+ gpr_log(GPR_INFO, "wait phase 1");
+ for (i = 0; i < producers + consumers; i++) {
+ GPR_ASSERT(gpr_event_wait(&options[i].on_phase1_done, ten_seconds_time()));
+ }
+ gpr_log(GPR_INFO, "done phase 1");
+
+ /* start phase2: operations will complete, and consumers will consume them */
+ gpr_log(GPR_INFO, "start phase 2");
+ gpr_event_set(&phase2, (void *)(intptr_t)1);
+
+ /* in parallel, we shutdown the completion channel - all events should still
+ be consumed */
+ grpc_completion_queue_shutdown(cc);
+
+ /* join all threads */
+ gpr_log(GPR_INFO, "wait phase 2");
+ for (i = 0; i < producers + consumers; i++) {
+ GPR_ASSERT(gpr_event_wait(&options[i].on_finished, ten_seconds_time()));
+ }
+ gpr_log(GPR_INFO, "done phase 2");
+
+ /* destroy the completion channel */
+ grpc_completion_queue_destroy(cc);
+
+ /* verify that everything was produced and consumed */
+ for (i = 0; i < producers + consumers; i++) {
+ if (i < producers) {
+ GPR_ASSERT(options[i].events_triggered == TEST_THREAD_EVENTS);
+ } else {
+ total_consumed += options[i].events_triggered;
+ }
+ }
+ GPR_ASSERT(total_consumed == producers * TEST_THREAD_EVENTS);
+
+ gpr_free(options);
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+ test_too_many_plucks();
+ test_threading(1, 1);
+ test_threading(1, 10);
+ test_threading(10, 1);
+ test_threading(10, 10);
+ grpc_shutdown();
+ return 0;
+}
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index 4f7a25ab93..ff927385d4 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -215,7 +215,7 @@ int main(int argc, char **argv) {
/* Third round, bogus tcp server */
gpr_log(GPR_DEBUG, "Wave 3");
- args.pollset = gpr_malloc(grpc_pollset_size());
+ args.pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(args.pollset, &args.mu);
gpr_event_init(&args.ready);
gpr_thd_new(&server, bad_server_thread, &args, &options);
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index e0a2c94216..330da46849 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -52,6 +52,7 @@
#include <grpc/impl/codegen/status.h>
#include <grpc/impl/codegen/sync.h>
#include <grpc/impl/codegen/sync_generic.h>
+#include <grpc/load_reporting.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/status.h>
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
new file mode 100644
index 0000000000..08b2fd3332
--- /dev/null
+++ b/test/core/transport/BUILD
@@ -0,0 +1,79 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "bdp_estimator_test",
+ srcs = ["bdp_estimator_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "connectivity_state_test",
+ srcs = ["connectivity_state_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "metadata_test",
+ srcs = ["metadata_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "pid_controller_test",
+ srcs = ["pid_controller_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "status_conversion_test",
+ srcs = ["status_conversion_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "stream_owned_slice_test",
+ srcs = ["stream_owned_slice_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "timeout_encoding_test",
+ srcs = ["timeout_encoding_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/transport/chttp2/BUILD b/test/core/transport/chttp2/BUILD
index 94b4830138..b507e27efe 100644
--- a/test/core/transport/chttp2/BUILD
+++ b/test/core/transport/chttp2/BUILD
@@ -38,3 +38,58 @@ grpc_fuzzer(
corpus = "hpack_parser_corpus"
)
+cc_test(
+ name = "alpn_test",
+ srcs = ["alpn_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "bin_decoder_test",
+ srcs = ["bin_decoder_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "bin_encoder_test",
+ srcs = ["bin_encoder_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "hpack_encoder_test",
+ srcs = ["hpack_encoder_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "hpack_parser_test",
+ srcs = ["hpack_parser_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "hpack_table_test",
+ srcs = ["hpack_table_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "stream_map_test",
+ srcs = ["stream_map_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
+
+cc_test(
+ name = "varint_test",
+ srcs = ["varint_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/transport/connectivity_state_test.c b/test/core/transport/connectivity_state_test.c
index 3520ef0a80..8314a5f619 100644
--- a/test/core/transport/connectivity_state_test.c
+++ b/test/core/transport/connectivity_state_test.c
@@ -77,8 +77,9 @@ static void test_check(void) {
grpc_error *error;
gpr_log(GPR_DEBUG, "test_check");
grpc_connectivity_state_init(&tracker, GRPC_CHANNEL_IDLE, "xxx");
- GPR_ASSERT(grpc_connectivity_state_check(&tracker, &error) ==
+ GPR_ASSERT(grpc_connectivity_state_get(&tracker, &error) ==
GRPC_CHANNEL_IDLE);
+ GPR_ASSERT(grpc_connectivity_state_check(&tracker) == GRPC_CHANNEL_IDLE);
GPR_ASSERT(error == GRPC_ERROR_NONE);
grpc_connectivity_state_destroy(&exec_ctx, &tracker);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/internal_api_canaries/support.c b/test/core/transport/stream_owned_slice_test.c
index e992d2a66a..97ba1083f3 100644
--- a/test/core/internal_api_canaries/support.c
+++ b/test/core/transport/stream_owned_slice_test.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,28 +31,28 @@
*
*/
-/*******************************************************************************
- * NOTE: If this test fails to compile, then the api changes are likely to cause
- * merge failures downstream. Please pay special attention to reviewing
- * these changes, and solicit help as appropriate when merging downstream.
- *
- * This test is NOT expected to be run directly.
- ******************************************************************************/
+#include "src/core/lib/transport/transport.h"
-#include "src/core/lib/iomgr/load_file.h"
-#include "src/core/lib/support/env.h"
-#include "src/core/lib/support/tmpfile.h"
+#include "test/core/util/test_config.h"
-static void test_code(void) {
- /* env.h */
- gpr_set_env("abc", gpr_getenv("xyz"));
- /* load_file.h */
- grpc_load_file("abc", 1, NULL);
- /* tmpfile.h */
- fclose(gpr_tmpfile("foo", NULL));
-}
+#include <grpc/support/log.h>
+
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+
+ uint8_t buffer[] = "abc123";
+ grpc_stream_refcount r;
+ GRPC_STREAM_REF_INIT(&r, 1, do_nothing, NULL, "test");
+ GPR_ASSERT(r.refs.count == 1);
+ grpc_slice slice =
+ grpc_slice_from_stream_owned_buffer(&r, buffer, sizeof(buffer));
+ GPR_ASSERT(GRPC_SLICE_START_PTR(slice) == buffer);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == sizeof(buffer));
+ GPR_ASSERT(r.refs.count == 2);
+ grpc_slice_unref(slice);
+ GPR_ASSERT(r.refs.count == 1);
-int main(void) {
- if (false) test_code();
return 0;
}
diff --git a/test/core/tsi/BUILD b/test/core/tsi/BUILD
new file mode 100644
index 0000000000..e6cba344ee
--- /dev/null
+++ b/test/core/tsi/BUILD
@@ -0,0 +1,37 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "transport_security_test",
+ srcs = ["transport_security_test.c"],
+ deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+ copts = ['-std=c99']
+)
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 5c90f1db44..e6d0d247db 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -51,9 +51,8 @@ cc_library(
"mock_endpoint.c",
"parse_hexstring.c",
"passthru_endpoint.c",
- "port_posix.c",
+ "port.c",
"port_server_client.c",
- "port_windows.c",
"reconnect_server.c",
"slice_splitter.c",
"test_tcp_server.c",
diff --git a/test/core/util/memory_counters.c b/test/core/util/memory_counters.c
index bebe94e582..c27065f260 100644
--- a/test/core/util/memory_counters.c
+++ b/test/core/util/memory_counters.c
@@ -39,7 +39,6 @@
#include "test/core/util/memory_counters.h"
-static gpr_mu g_memory_mutex;
static struct grpc_memory_counters g_memory_counters;
static gpr_allocation_functions g_old_allocs;
@@ -47,15 +46,23 @@ static void *guard_malloc(size_t size);
static void *guard_realloc(void *vptr, size_t size);
static void guard_free(void *vptr);
+#ifdef GPR_LOW_LEVEL_COUNTERS
+/* hide these from the microbenchmark atomic stats */
+#define NO_BARRIER_FETCH_ADD(x, sz) \
+ __atomic_fetch_add((x), (sz), __ATOMIC_RELAXED)
+#define NO_BARRIER_LOAD(x) __atomic_load_n((x), __ATOMIC_RELAXED)
+#else
+#define NO_BARRIER_FETCH_ADD(x, sz) gpr_atm_no_barrier_fetch_add(x, sz)
+#define NO_BARRIER_LOAD(x) gpr_atm_no_barrier_load(x)
+#endif
+
static void *guard_malloc(size_t size) {
size_t *ptr;
if (!size) return NULL;
- gpr_mu_lock(&g_memory_mutex);
- g_memory_counters.total_size_absolute += size;
- g_memory_counters.total_size_relative += size;
- g_memory_counters.total_allocs_absolute++;
- g_memory_counters.total_allocs_relative++;
- gpr_mu_unlock(&g_memory_mutex);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_absolute, (gpr_atm)size);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_relative, (gpr_atm)1);
ptr = g_old_allocs.malloc_fn(size + sizeof(size));
*ptr++ = size;
return ptr;
@@ -71,12 +78,10 @@ static void *guard_realloc(void *vptr, size_t size) {
return NULL;
}
--ptr;
- gpr_mu_lock(&g_memory_mutex);
- g_memory_counters.total_size_absolute += size;
- g_memory_counters.total_size_relative -= *ptr;
- g_memory_counters.total_size_relative += size;
- g_memory_counters.total_allocs_absolute++;
- gpr_mu_unlock(&g_memory_mutex);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_absolute, (gpr_atm)size);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1);
ptr = g_old_allocs.realloc_fn(ptr, size + sizeof(size));
*ptr++ = size;
return ptr;
@@ -86,32 +91,33 @@ static void guard_free(void *vptr) {
size_t *ptr = vptr;
if (!vptr) return;
--ptr;
- gpr_mu_lock(&g_memory_mutex);
- g_memory_counters.total_size_relative -= *ptr;
- g_memory_counters.total_allocs_relative--;
- gpr_mu_unlock(&g_memory_mutex);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr);
+ NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_relative, -(gpr_atm)1);
g_old_allocs.free_fn(ptr);
}
-struct gpr_allocation_functions g_guard_allocs = {guard_malloc, guard_realloc,
- guard_free};
+struct gpr_allocation_functions g_guard_allocs = {guard_malloc, NULL,
+ guard_realloc, guard_free};
void grpc_memory_counters_init() {
memset(&g_memory_counters, 0, sizeof(g_memory_counters));
- gpr_mu_init(&g_memory_mutex);
g_old_allocs = gpr_get_allocation_functions();
gpr_set_allocation_functions(g_guard_allocs);
}
void grpc_memory_counters_destroy() {
gpr_set_allocation_functions(g_old_allocs);
- gpr_mu_destroy(&g_memory_mutex);
}
struct grpc_memory_counters grpc_memory_counters_snapshot() {
struct grpc_memory_counters counters;
- gpr_mu_lock(&g_memory_mutex);
- counters = g_memory_counters;
- gpr_mu_unlock(&g_memory_mutex);
+ counters.total_size_relative =
+ NO_BARRIER_LOAD(&g_memory_counters.total_size_relative);
+ counters.total_size_absolute =
+ NO_BARRIER_LOAD(&g_memory_counters.total_size_absolute);
+ counters.total_allocs_relative =
+ NO_BARRIER_LOAD(&g_memory_counters.total_allocs_relative);
+ counters.total_allocs_absolute =
+ NO_BARRIER_LOAD(&g_memory_counters.total_allocs_absolute);
return counters;
}
diff --git a/test/core/util/memory_counters.h b/test/core/util/memory_counters.h
index b9b2b3adda..51487c73ce 100644
--- a/test/core/util/memory_counters.h
+++ b/test/core/util/memory_counters.h
@@ -34,13 +34,13 @@
#ifndef GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
#define GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
-#include <stddef.h>
+#include <grpc/support/atm.h>
struct grpc_memory_counters {
- size_t total_size_relative;
- size_t total_size_absolute;
- size_t total_allocs_relative;
- size_t total_allocs_absolute;
+ gpr_atm total_size_relative;
+ gpr_atm total_size_absolute;
+ gpr_atm total_allocs_relative;
+ gpr_atm total_allocs_absolute;
};
void grpc_memory_counters_init();
diff --git a/test/core/util/mock_endpoint.c b/test/core/util/mock_endpoint.c
index d531ec6031..b8fed7e14b 100644
--- a/test/core/util/mock_endpoint.c
+++ b/test/core/util/mock_endpoint.c
@@ -31,6 +31,12 @@
*
*/
+/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+ using that endpoint. Because of various transitive includes in uv.h,
+ including windows.h on Windows, uv.h must be included before other system
+ headers. Therefore, sockaddr.h must always be included first */
+#include "src/core/lib/iomgr/sockaddr.h"
+
#include "test/core/util/mock_endpoint.h"
#include <inttypes.h>
diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c
index 1e82c737c6..5f27f9ae73 100644
--- a/test/core/util/passthru_endpoint.c
+++ b/test/core/util/passthru_endpoint.c
@@ -31,6 +31,12 @@
*
*/
+/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+ using that endpoint. Because of various transitive includes in uv.h,
+ including windows.h on Windows, uv.h must be included before other system
+ headers. Therefore, sockaddr.h must always be included first */
+#include "src/core/lib/iomgr/sockaddr.h"
+
#include "test/core/util/passthru_endpoint.h"
#include <inttypes.h>
diff --git a/test/core/util/port_uv.c b/test/core/util/port.c
index 0c9c0d87d6..da1ed4e052 100644
--- a/test/core/util/port_uv.c
+++ b/test/core/util/port.c
@@ -33,17 +33,24 @@
#include "src/core/lib/iomgr/port.h"
#include "test/core/util/test_config.h"
-#if defined(GRPC_UV) && defined(GRPC_TEST_PICK_PORT)
+#if defined(GRPC_TEST_PICK_PORT)
+#include "test/core/util/port.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "test/core/util/port_server_client.h"
-// Almost everything in this file has been copied from port_posix.c
-
static int *chosen_ports = NULL;
static size_t num_chosen_ports = 0;
@@ -51,7 +58,6 @@ static int free_chosen_port(int port) {
size_t i;
int found = 0;
size_t found_at = 0;
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
/* Find the port and erase it from the list, then tell the server it can be
freed. */
for (i = 0; i < num_chosen_ports; i++) {
@@ -64,24 +70,16 @@ static int free_chosen_port(int port) {
if (found) {
chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
num_chosen_ports--;
- if (env) {
- grpc_free_port_using_server(env, port);
- }
+ grpc_free_port_using_server(port);
}
- gpr_free(env);
return found;
}
static void free_chosen_ports(void) {
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env != NULL) {
- size_t i;
- for (i = 0; i < num_chosen_ports; i++) {
- grpc_free_port_using_server(env, chosen_ports[i]);
- }
- gpr_free(env);
+ size_t i;
+ for (i = 0; i < num_chosen_ports; i++) {
+ grpc_free_port_using_server(chosen_ports[i]);
}
-
gpr_free(chosen_ports);
}
@@ -95,23 +93,27 @@ static void chose_port(int port) {
}
int grpc_pick_unused_port(void) {
- // Currently only works with the port server
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- GPR_ASSERT(env);
- int port = grpc_pick_port_using_server(env);
- gpr_free(env);
+ int port = grpc_pick_port_using_server();
if (port != 0) {
chose_port(port);
}
+
return port;
}
int grpc_pick_unused_port_or_die(void) {
int port = grpc_pick_unused_port();
- GPR_ASSERT(port > 0);
+ if (port == 0) {
+ fprintf(stderr,
+ "gRPC tests require a helper port server to allocate ports used \n"
+ "during the test.\n\n"
+ "This server is not currently running.\n\n"
+ "To start it, run tools/run_tests/start_port_server.py\n\n");
+ exit(1);
+ }
return port;
}
void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
-#endif /* GRPC_UV && GRPC_TEST_PICK_PORT */
+#endif /* GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
deleted file mode 100644
index 4a42e4c702..0000000000
--- a/test/core/util/port_posix.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-#include "test/core/util/test_config.h"
-#if defined(GRPC_POSIX_SOCKET) && defined(GRPC_TEST_PICK_PORT)
-
-#include "test/core/util/port.h"
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/lib/http/httpcli.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port_server_client.h"
-
-#define NUM_RANDOM_PORTS_TO_PICK 100
-
-static int *chosen_ports = NULL;
-static size_t num_chosen_ports = 0;
-
-static int has_port_been_chosen(int port) {
- size_t i;
- for (i = 0; i < num_chosen_ports; i++) {
- if (chosen_ports[i] == port) {
- return 1;
- }
- }
- return 0;
-}
-
-static int free_chosen_port(int port) {
- size_t i;
- int found = 0;
- size_t found_at = 0;
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- /* Find the port and erase it from the list, then tell the server it can be
- freed. */
- for (i = 0; i < num_chosen_ports; i++) {
- if (chosen_ports[i] == port) {
- GPR_ASSERT(found == 0);
- found = 1;
- found_at = i;
- }
- }
- if (found) {
- chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
- num_chosen_ports--;
- if (env) {
- grpc_free_port_using_server(env, port);
- }
- }
- gpr_free(env);
- return found;
-}
-
-static void free_chosen_ports(void) {
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env != NULL) {
- size_t i;
- for (i = 0; i < num_chosen_ports; i++) {
- grpc_free_port_using_server(env, chosen_ports[i]);
- }
- gpr_free(env);
- }
-
- gpr_free(chosen_ports);
-}
-
-static void chose_port(int port) {
- if (chosen_ports == NULL) {
- atexit(free_chosen_ports);
- }
- num_chosen_ports++;
- chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
- chosen_ports[num_chosen_ports - 1] = port;
-}
-
-static bool is_port_available(int *port, bool is_tcp) {
- GPR_ASSERT(*port >= 0);
- GPR_ASSERT(*port <= 65535);
-
- /* For a port to be considered available, the kernel must support
- at least one of (IPv6, IPv4), and the port must be available
- on each supported family. */
- bool got_socket = false;
- for (int is_ipv6 = 1; is_ipv6 >= 0; is_ipv6--) {
- const int fd =
- socket(is_ipv6 ? AF_INET6 : AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM,
- is_tcp ? IPPROTO_TCP : 0);
- if (fd >= 0) {
- got_socket = true;
- } else {
- continue;
- }
-
- /* Reuseaddr lets us start up a server immediately after it exits */
- const int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
- gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
- close(fd);
- return false;
- }
-
- /* Try binding to port */
- grpc_resolved_address addr;
- if (is_ipv6) {
- grpc_sockaddr_make_wildcard6(*port, &addr); /* [::]:port */
- } else {
- grpc_sockaddr_make_wildcard4(*port, &addr); /* 0.0.0.0:port */
- }
- if (bind(fd, (struct sockaddr *)addr.addr, (socklen_t)addr.len) < 0) {
- gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
- close(fd);
- return false;
- }
-
- /* Get the bound port number */
- if (getsockname(fd, (struct sockaddr *)addr.addr, (socklen_t *)&addr.len) <
- 0) {
- gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
- close(fd);
- return false;
- }
- GPR_ASSERT(addr.len <= sizeof(addr.addr));
- const int actual_port = grpc_sockaddr_get_port(&addr);
- GPR_ASSERT(actual_port > 0);
- if (*port == 0) {
- *port = actual_port;
- } else {
- GPR_ASSERT(*port == actual_port);
- }
-
- close(fd);
- }
- if (!got_socket) {
- gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
- return false;
- }
- return true;
-}
-
-int grpc_pick_unused_port(void) {
- /* We repeatedly pick a port and then see whether or not it is
- available for use both as a TCP socket and a UDP socket. First, we
- pick a random large port number. For subsequent
- iterations, we bind to an anonymous port and let the OS pick the
- port number. The random port picking reduces the probability of
- races with other processes on kernels that want to reuse the same
- port numbers over and over. */
-
- /* In alternating iterations we trial UDP ports before TCP ports UDP
- ports -- it could be the case that this machine has been using up
- UDP ports and they are scarcer. */
-
- /* Type of port to first pick in next iteration */
- bool is_tcp = true;
- int trial = 0;
-
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env) {
- int port = grpc_pick_port_using_server(env);
- gpr_free(env);
- if (port != 0) {
- chose_port(port);
- }
- return port;
- }
-
- for (;;) {
- int port;
- trial++;
- if (trial == 1) {
- port = getpid() % (65536 - 30000) + 30000;
- } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) {
- port = rand() % (65536 - 30000) + 30000;
- } else {
- port = 0;
- }
-
- if (has_port_been_chosen(port)) {
- continue;
- }
-
- if (!is_port_available(&port, is_tcp)) {
- continue;
- }
-
- GPR_ASSERT(port > 0);
- /* Check that the port # is free for the other type of socket also */
- if (!is_port_available(&port, !is_tcp)) {
- /* In the next iteration trial to bind to the other type first
- because perhaps it is more rare. */
- is_tcp = !is_tcp;
- continue;
- }
-
- chose_port(port);
- return port;
- }
-
- /* The port iterator reached the end without finding a suitable port. */
- return 0;
-}
-
-int grpc_pick_unused_port_or_die(void) {
- int port = grpc_pick_unused_port();
- GPR_ASSERT(port > 0);
- return port;
-}
-
-void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
-
-#endif /* GRPC_POSIX_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index 6d722ffc88..38054dd1e7 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -74,7 +74,7 @@ static void freed_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(pr->mu);
}
-void grpc_free_port_using_server(char *server, int port) {
+void grpc_free_port_using_server(int port) {
grpc_httpcli_context context;
grpc_httpcli_request req;
grpc_httpcli_response rsp;
@@ -89,13 +89,13 @@ void grpc_free_port_using_server(char *server, int port) {
memset(&req, 0, sizeof(req));
memset(&rsp, 0, sizeof(rsp));
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &pr.mu);
pr.pops = grpc_polling_entity_create_from_pollset(pollset);
shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
grpc_schedule_on_exec_ctx);
- req.host = server;
+ req.host = GRPC_PORT_SERVER_ADDRESS;
gpr_asprintf(&path, "/drop/%d", port);
req.http.path = path;
@@ -121,7 +121,7 @@ void grpc_free_port_using_server(char *server, int port) {
}
gpr_mu_unlock(pr.mu);
- grpc_httpcli_context_destroy(&context);
+ grpc_httpcli_context_destroy(&exec_ctx, &context);
grpc_exec_ctx_finish(&exec_ctx);
grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&pr.pops),
shutdown_closure);
@@ -162,6 +162,15 @@ static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
if (failed) {
grpc_httpcli_request req;
memset(&req, 0, sizeof(req));
+ if (pr->retries >= 5) {
+ gpr_mu_lock(pr->mu);
+ pr->port = 0;
+ GRPC_LOG_IF_ERROR(
+ "pollset_kick",
+ grpc_pollset_kick(grpc_polling_entity_pollset(&pr->pops), NULL));
+ gpr_mu_unlock(pr->mu);
+ return;
+ }
GPR_ASSERT(pr->retries < 10);
gpr_sleep_until(gpr_time_add(
gpr_now(GPR_CLOCK_REALTIME),
@@ -198,7 +207,7 @@ static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(pr->mu);
}
-int grpc_pick_port_using_server(char *server) {
+int grpc_pick_port_using_server(void) {
grpc_httpcli_context context;
grpc_httpcli_request req;
portreq pr;
@@ -209,16 +218,16 @@ int grpc_pick_port_using_server(char *server) {
memset(&pr, 0, sizeof(pr));
memset(&req, 0, sizeof(req));
- grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(pollset, &pr.mu);
pr.pops = grpc_polling_entity_create_from_pollset(pollset);
shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
grpc_schedule_on_exec_ctx);
pr.port = -1;
- pr.server = server;
+ pr.server = GRPC_PORT_SERVER_ADDRESS;
pr.ctx = &context;
- req.host = server;
+ req.host = GRPC_PORT_SERVER_ADDRESS;
req.http.path = "/get";
grpc_httpcli_context_init(&context);
@@ -245,7 +254,7 @@ int grpc_pick_port_using_server(char *server) {
gpr_mu_unlock(pr.mu);
grpc_http_response_destroy(&pr.response);
- grpc_httpcli_context_destroy(&context);
+ grpc_httpcli_context_destroy(&exec_ctx, &context);
grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&pr.pops),
shutdown_closure);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/util/port_server_client.h b/test/core/util/port_server_client.h
index 437006495c..70471ecb8a 100644
--- a/test/core/util/port_server_client.h
+++ b/test/core/util/port_server_client.h
@@ -36,7 +36,10 @@
// C interface to port_server.py
-int grpc_pick_port_using_server(char *server);
-void grpc_free_port_using_server(char *server, int port);
+// must be synchronized with tools/run_tests/python_utils/start_port_server.py
+#define GRPC_PORT_SERVER_ADDRESS "localhost:32766"
+
+int grpc_pick_port_using_server(void);
+void grpc_free_port_using_server(int port);
#endif // GRPC_TEST_CORE_UTIL_PORT_SERVER_CLIENT_H
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
deleted file mode 100644
index 0c50a46644..0000000000
--- a/test/core/util/port_windows.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-#include "test/core/util/test_config.h"
-#if defined(GRPC_WINSOCK_SOCKET) && defined(GRPC_TEST_PICK_PORT)
-
-#include "src/core/lib/iomgr/sockaddr.h"
-
-#include "test/core/util/port.h"
-
-#include <errno.h>
-#include <process.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/http/httpcli.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/support/env.h"
-#include "test/core/util/port_server_client.h"
-
-#if GPR_GETPID_IN_UNISTD_H
-#include <sys/unistd.h>
-static int _getpid() { return getpid(); }
-#endif
-
-#define NUM_RANDOM_PORTS_TO_PICK 100
-
-static int *chosen_ports = NULL;
-static size_t num_chosen_ports = 0;
-
-static int has_port_been_chosen(int port) {
- size_t i;
- for (i = 0; i < num_chosen_ports; i++) {
- if (chosen_ports[i] == port) {
- return 1;
- }
- }
- return 0;
-}
-
-static int free_chosen_port(int port) {
- size_t i;
- int found = 0;
- size_t found_at = 0;
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env != NULL) {
- /* Find the port and erase it from the list, then tell the server it can be
- freed. */
- for (i = 0; i < num_chosen_ports; i++) {
- if (chosen_ports[i] == port) {
- GPR_ASSERT(found == 0);
- found = 1;
- found_at = i;
- }
- }
- if (found) {
- chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1];
- grpc_free_port_using_server(env, port);
- num_chosen_ports--;
- }
- }
- return found;
-}
-
-static void free_chosen_ports(void) {
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env != NULL) {
- size_t i;
- for (i = 0; i < num_chosen_ports; i++) {
- grpc_free_port_using_server(env, chosen_ports[i]);
- }
- gpr_free(env);
- }
-
- gpr_free(chosen_ports);
-}
-
-static void chose_port(int port) {
- if (chosen_ports == NULL) {
- atexit(free_chosen_ports);
- }
- num_chosen_ports++;
- chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
- chosen_ports[num_chosen_ports - 1] = port;
-}
-
-static int is_port_available(int *port, int is_tcp) {
- const int proto = is_tcp ? IPPROTO_TCP : 0;
- const SOCKET fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
- int one = 1;
- struct sockaddr_in addr;
- socklen_t alen = sizeof(addr);
- int actual_port;
-
- GPR_ASSERT(*port >= 0);
- GPR_ASSERT(*port <= 65535);
- if (INVALID_SOCKET == fd) {
- gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
- return 0;
- }
-
- /* Reuseaddr lets us start up a server immediately after it exits */
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one,
- sizeof(one)) < 0) {
- gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
- closesocket(fd);
- return 0;
- }
-
- /* Try binding to port */
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- addr.sin_port = htons((u_short)*port);
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
- closesocket(fd);
- return 0;
- }
-
- /* Get the bound port number */
- if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
- gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
- closesocket(fd);
- return 0;
- }
- GPR_ASSERT(alen <= (socklen_t)sizeof(addr));
- actual_port = ntohs(addr.sin_port);
- GPR_ASSERT(actual_port > 0);
- if (*port == 0) {
- *port = actual_port;
- } else {
- GPR_ASSERT(*port == actual_port);
- }
-
- closesocket(fd);
- return 1;
-}
-
-int grpc_pick_unused_port(void) {
- /* We repeatedly pick a port and then see whether or not it is
- available for use both as a TCP socket and a UDP socket. First, we
- pick a random large port number. For subsequent
- iterations, we bind to an anonymous port and let the OS pick the
- port number. The random port picking reduces the probability of
- races with other processes on kernels that want to reuse the same
- port numbers over and over. */
-
- /* In alternating iterations we trial UDP ports before TCP ports UDP
- ports -- it could be the case that this machine has been using up
- UDP ports and they are scarcer. */
-
- /* Type of port to first pick in next iteration */
- int is_tcp = 1;
- int trial = 0;
-
- char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
- if (env) {
- int port = grpc_pick_port_using_server(env);
- gpr_free(env);
- if (port != 0) {
- return port;
- }
- }
-
- for (;;) {
- int port;
- trial++;
- if (trial == 1) {
- port = _getpid() % (65536 - 30000) + 30000;
- } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) {
- port = rand() % (65536 - 30000) + 30000;
- } else {
- port = 0;
- }
-
- if (has_port_been_chosen(port)) {
- continue;
- }
-
- if (!is_port_available(&port, is_tcp)) {
- continue;
- }
-
- GPR_ASSERT(port > 0);
- /* Check that the port # is free for the other type of socket also */
- if (!is_port_available(&port, !is_tcp)) {
- /* In the next iteration trial to bind to the other type first
- because perhaps it is more rare. */
- is_tcp = !is_tcp;
- continue;
- }
-
- /* TODO(ctiller): consider caching this port in some structure, to avoid
- handing it out again */
-
- chose_port(port);
- return port;
- }
-
- /* The port iterator reached the end without finding a suitable port. */
- return 0;
-}
-
-int grpc_pick_unused_port_or_die(void) {
- int port = grpc_pick_unused_port();
- GPR_ASSERT(port > 0);
- return port;
-}
-
-void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); }
-
-#endif /* GRPC_WINSOCK_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
index 94aab27253..0180d6f08d 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -215,6 +215,16 @@ static void install_crash_handler() {
#include <stdio.h>
#include <string.h>
+#define SIGNAL_NAMES_LENGTH 32
+
+static const char *const signal_names[] = {
+ NULL, "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
+ "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV",
+ "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD",
+ "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG",
+ "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO",
+ "SIGPWR", "SIGSYS"};
+
static char g_alt_stack[GPR_MAX(MINSIGSTKSZ, 65536)];
#define MAX_FRAMES 32
@@ -240,7 +250,11 @@ static void crash_handler(int signum, siginfo_t *info, void *data) {
int addrlen;
output_string("\n\n\n*******************************\nCaught signal ");
- output_num(signum);
+ if (signum > 0 && signum < SIGNAL_NAMES_LENGTH) {
+ output_string(signal_names[signum]);
+ } else {
+ output_num(signum);
+ }
output_string("\n");
addrlen = backtrace(addrlist, GPR_ARRAY_SIZE(addrlist));
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index 2338b81ab1..496e579bc3 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -60,7 +60,7 @@ void test_tcp_server_init(test_tcp_server *server,
grpc_closure_init(&server->shutdown_complete, on_server_destroyed, server,
grpc_schedule_on_exec_ctx);
server->shutdown = 0;
- server->pollset = gpr_malloc(grpc_pollset_size());
+ server->pollset = gpr_zalloc(grpc_pollset_size());
grpc_pollset_init(server->pollset, &server->mu);
server->on_connect = on_connect;
server->cb_data = user_data;
diff --git a/test/core/util/trickle_endpoint.c b/test/core/util/trickle_endpoint.c
new file mode 100644
index 0000000000..0848147158
--- /dev/null
+++ b/test/core/util/trickle_endpoint.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include "test/core/util/passthru_endpoint.h"
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/slice/slice_internal.h"
+
+typedef struct {
+ grpc_endpoint base;
+ double bytes_per_second;
+ grpc_endpoint *wrapped;
+ gpr_timespec last_write;
+
+ gpr_mu mu;
+ grpc_slice_buffer write_buffer;
+ grpc_slice_buffer writing_buffer;
+ grpc_error *error;
+ bool writing;
+} trickle_endpoint;
+
+static void te_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_slice_buffer *slices, grpc_closure *cb) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ grpc_endpoint_read(exec_ctx, te->wrapped, slices, cb);
+}
+
+static void te_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_slice_buffer *slices, grpc_closure *cb) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ for (size_t i = 0; i < slices->count; i++) {
+ grpc_slice_ref_internal(slices->slices[i]);
+ }
+ gpr_mu_lock(&te->mu);
+ if (te->write_buffer.length == 0) {
+ te->last_write = gpr_now(GPR_CLOCK_MONOTONIC);
+ }
+ grpc_slice_buffer_addn(&te->write_buffer, slices->slices, slices->count);
+ grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_REF(te->error));
+ gpr_mu_unlock(&te->mu);
+}
+
+static grpc_workqueue *te_get_workqueue(grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ return grpc_endpoint_get_workqueue(te->wrapped);
+}
+
+static void te_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_pollset *pollset) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ grpc_endpoint_add_to_pollset(exec_ctx, te->wrapped, pollset);
+}
+
+static void te_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_pollset_set *pollset_set) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ grpc_endpoint_add_to_pollset_set(exec_ctx, te->wrapped, pollset_set);
+}
+
+static void te_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+ grpc_error *why) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ gpr_mu_lock(&te->mu);
+ if (te->error == GRPC_ERROR_NONE) {
+ te->error = GRPC_ERROR_REF(why);
+ }
+ gpr_mu_unlock(&te->mu);
+ grpc_endpoint_shutdown(exec_ctx, te->wrapped, why);
+}
+
+static void te_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ grpc_endpoint_destroy(exec_ctx, te->wrapped);
+ gpr_mu_destroy(&te->mu);
+ grpc_slice_buffer_destroy_internal(exec_ctx, &te->write_buffer);
+ grpc_slice_buffer_destroy_internal(exec_ctx, &te->writing_buffer);
+ GRPC_ERROR_UNREF(te->error);
+ gpr_free(te);
+}
+
+static grpc_resource_user *te_get_resource_user(grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ return grpc_endpoint_get_resource_user(te->wrapped);
+}
+
+static char *te_get_peer(grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ return grpc_endpoint_get_peer(te->wrapped);
+}
+
+static int te_get_fd(grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ return grpc_endpoint_get_fd(te->wrapped);
+}
+
+static void te_finish_write(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ trickle_endpoint *te = arg;
+ gpr_mu_lock(&te->mu);
+ te->writing = false;
+ grpc_slice_buffer_reset_and_unref(&te->writing_buffer);
+ gpr_mu_unlock(&te->mu);
+}
+
+static const grpc_endpoint_vtable vtable = {te_read,
+ te_write,
+ te_get_workqueue,
+ te_add_to_pollset,
+ te_add_to_pollset_set,
+ te_shutdown,
+ te_destroy,
+ te_get_resource_user,
+ te_get_peer,
+ te_get_fd};
+
+grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap,
+ double bytes_per_second) {
+ trickle_endpoint *te = gpr_malloc(sizeof(*te));
+ te->base.vtable = &vtable;
+ te->wrapped = wrap;
+ te->bytes_per_second = bytes_per_second;
+ gpr_mu_init(&te->mu);
+ grpc_slice_buffer_init(&te->write_buffer);
+ grpc_slice_buffer_init(&te->writing_buffer);
+ te->error = GRPC_ERROR_NONE;
+ te->writing = false;
+ return &te->base;
+}
+
+static double ts2dbl(gpr_timespec s) {
+ return (double)s.tv_sec + 1e-9 * (double)s.tv_nsec;
+}
+
+size_t grpc_trickle_endpoint_trickle(grpc_exec_ctx *exec_ctx,
+ grpc_endpoint *ep) {
+ trickle_endpoint *te = (trickle_endpoint *)ep;
+ gpr_mu_lock(&te->mu);
+ if (!te->writing && te->write_buffer.length > 0) {
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ double elapsed = ts2dbl(gpr_time_sub(now, te->last_write));
+ size_t bytes = (size_t)(te->bytes_per_second * elapsed);
+ // gpr_log(GPR_DEBUG, "%lf elapsed --> %" PRIdPTR " bytes", elapsed, bytes);
+ if (bytes > 0) {
+ grpc_slice_buffer_move_first(&te->write_buffer,
+ GPR_MIN(bytes, te->write_buffer.length),
+ &te->writing_buffer);
+ te->writing = true;
+ te->last_write = now;
+ grpc_endpoint_write(
+ exec_ctx, te->wrapped, &te->writing_buffer,
+ grpc_closure_create(te_finish_write, te, grpc_schedule_on_exec_ctx));
+ }
+ }
+ size_t backlog = te->write_buffer.length;
+ gpr_mu_unlock(&te->mu);
+ return backlog;
+}
diff --git a/test/core/util/trickle_endpoint.h b/test/core/util/trickle_endpoint.h
new file mode 100644
index 0000000000..7e8d9d91e3
--- /dev/null
+++ b/test/core/util/trickle_endpoint.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TRICKLE_ENDPOINT_H
+#define TRICKLE_ENDPOINT_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+
+grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap,
+ double bytes_per_second);
+
+/* Allow up to \a bytes through the endpoint. Returns the new backlog. */
+size_t grpc_trickle_endpoint_trickle(grpc_exec_ctx *exec_ctx,
+ grpc_endpoint *endpoint);
+
+#endif
diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD
new file mode 100644
index 0000000000..14d5733da2
--- /dev/null
+++ b/test/cpp/codegen/BUILD
@@ -0,0 +1,77 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "codegen_test_full",
+ srcs = ["codegen_test_full.cc"],
+ deps = [
+ "//:grpc++",
+ "//external:gtest",
+ "//test/core/util:gpr_test_util",
+ ],
+)
+
+cc_test(
+ name = "codegen_test_minimal",
+ srcs = ["codegen_test_minimal.cc"],
+ deps = [
+ "//:grpc++",
+ "//external:gtest",
+ "//test/core/util:gpr_test_util",
+ ],
+)
+
+cc_test(
+ name = "proto_utils_test",
+ srcs = ["proto_utils_test.cc"],
+ deps = [
+ "//:grpc++",
+ "//external:gtest",
+ "//test/core/util:gpr_test_util",
+ ],
+)
+
+cc_test(
+ name = "golden_file_test",
+ srcs = ["golden_file_test.cc"],
+ args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.h"],
+ data = [
+ ":compiler_test_golden",
+ "//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen",
+ ],
+ deps = [
+ "//:grpc++",
+ "//external:gflags",
+ "//external:gtest",
+ "//src/proto/grpc/testing:compiler_test_proto",
+ "//test/core/util:gpr_test_util",
+ ],
+)
diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden
index 0b82f2a59f..fd26a17ac1 100644
--- a/test/cpp/codegen/compiler_test_golden
+++ b/test/cpp/codegen/compiler_test_golden
@@ -1,4 +1,4 @@
-// Generated by the gRPC protobuf plugin.
+// Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost.
// source: src/proto/grpc/testing/compiler_test.proto
// Original file comments:
diff --git a/test/cpp/codegen/golden_file_test.cc b/test/cpp/codegen/golden_file_test.cc
index ec08d08de6..158a4d933c 100644
--- a/test/cpp/codegen/golden_file_test.cc
+++ b/test/cpp/codegen/golden_file_test.cc
@@ -34,15 +34,18 @@
#include <fstream>
#include <sstream>
+#include <gflags/gflags.h>
#include <gtest/gtest.h>
-// These paths rely on the fact that we run our tests under grpc/
-const char kGeneratedFilePath[] =
- "gens/src/proto/grpc/testing/compiler_test.grpc.pb.h";
+DEFINE_string(generated_file_path, "",
+ "path to the generated compiler_test.grpc.pb.h file");
+
const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden";
TEST(GoldenFileTest, TestGeneratedFile) {
- std::ifstream generated(kGeneratedFilePath);
+ ASSERT_FALSE(FLAGS_generated_file_path.empty());
+
+ std::ifstream generated(FLAGS_generated_file_path);
std::ifstream golden(kGoldenFilePath);
ASSERT_TRUE(generated.good());
@@ -60,5 +63,6 @@ TEST(GoldenFileTest, TestGeneratedFile) {
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
+ ::google::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
}
diff --git a/test/cpp/common/BUILD b/test/cpp/common/BUILD
new file mode 100644
index 0000000000..0e2db00f0a
--- /dev/null
+++ b/test/cpp/common/BUILD
@@ -0,0 +1,36 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_test(
+ name = "alarm_cpp_test",
+ srcs = ["alarm_cpp_test.cc"],
+ deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util"],
+)
diff --git a/test/cpp/common/channel_filter_test.cc b/test/cpp/common/channel_filter_test.cc
index 32246a4b76..d78b05e5d8 100644
--- a/test/cpp/common/channel_filter_test.cc
+++ b/test/cpp/common/channel_filter_test.cc
@@ -55,7 +55,7 @@ class MyCallData : public CallData {
MyCallData() {}
grpc_error* Init(grpc_exec_ctx* exec_ctx, ChannelData* channel_data,
- grpc_call_element_args* args) override {
+ const grpc_call_element_args* args) override {
(void)args->path; // Make sure field is available.
return GRPC_ERROR_NONE;
}
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
new file mode 100644
index 0000000000..0bf7948fcf
--- /dev/null
+++ b/test/cpp/end2end/BUILD
@@ -0,0 +1,323 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_library(
+ name = "test_service_impl",
+ srcs = ["test_service_impl.cc"],
+ hdrs = ["test_service_impl.h"],
+ deps = [
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "async_end2end_test",
+ srcs = ["async_end2end_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "client_crash_test",
+ srcs = ["client_crash_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "client_crash_test_server",
+ srcs = ["client_crash_test_server.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gflags",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "end2end_test",
+ srcs = ["end2end_test.cc"],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "filter_end2end_test",
+ srcs = ["filter_end2end_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "generic_end2end_test",
+ srcs = ["generic_end2end_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "hybrid_end2end_test",
+ srcs = ["hybrid_end2end_test.cc"],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "mock_test",
+ srcs = ["mock_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "round_robin_end2end_test",
+ srcs = ["round_robin_end2end_test.cc"],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "proto_server_reflection_test",
+ srcs = ["proto_server_reflection_test.cc"],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//:grpc++_reflection",
+ "//external:gflags",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:grpc++_proto_reflection_desc_db",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "server_builder_plugin_test",
+ srcs = ["server_builder_plugin_test.cc"],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "server_crash_test",
+ srcs = ["server_crash_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "server_crash_test_client",
+ srcs = ["server_crash_test_client.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gflags",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "shutdown_test",
+ srcs = ["shutdown_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "streaming_throughput_test",
+ srcs = ["streaming_throughput_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+cc_test(
+ name = "thread_stress_test",
+ srcs = ["thread_stress_test.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//external:gtest",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 47e5c5bd77..df78557c43 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -901,8 +901,7 @@ TEST_P(End2endTest, RpcMaxMessageSize) {
EchoRequest request;
EchoResponse response;
request.set_message(string(kMaxMessageSize_ * 2, 'a'));
- // cancelled is not guaranteed to appear before the end of the service handler
- request.mutable_param()->set_skip_cancelled_check(true);
+ request.mutable_param()->set_server_die(true);
ClientContext context;
Status s = stub_->Echo(&context, request, &response);
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
new file mode 100644
index 0000000000..3d51007857
--- /dev/null
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -0,0 +1,323 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/ext/health_check_service_server_builder_option.h>
+#include <grpc++/health_check_service_interface.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/health/v1/health.grpc.pb.h"
+#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_service_impl.h"
+
+using grpc::health::v1::Health;
+using grpc::health::v1::HealthCheckRequest;
+using grpc::health::v1::HealthCheckResponse;
+
+namespace grpc {
+namespace testing {
+namespace {
+
+// A sample sync implementation of the health checking service. This does the
+// same thing as the default one.
+class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service {
+ public:
+ Status Check(ServerContext* context, const HealthCheckRequest* request,
+ HealthCheckResponse* response) override {
+ std::lock_guard<std::mutex> lock(mu_);
+ auto iter = status_map_.find(request->service());
+ if (iter == status_map_.end()) {
+ return Status(StatusCode::NOT_FOUND, "");
+ }
+ response->set_status(iter->second);
+ return Status::OK;
+ }
+
+ void SetStatus(const grpc::string& service_name,
+ HealthCheckResponse::ServingStatus status) {
+ std::lock_guard<std::mutex> lock(mu_);
+ status_map_[service_name] = status;
+ }
+
+ void SetAll(HealthCheckResponse::ServingStatus status) {
+ std::lock_guard<std::mutex> lock(mu_);
+ for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) {
+ iter->second = status;
+ }
+ }
+
+ private:
+ std::mutex mu_;
+ std::map<const grpc::string, HealthCheckResponse::ServingStatus> status_map_;
+};
+
+// A custom implementation of the health checking service interface. This is
+// used to test that it prevents the server from creating a default service and
+// also serves as an example of how to override the default service.
+class CustomHealthCheckService : public HealthCheckServiceInterface {
+ public:
+ explicit CustomHealthCheckService(HealthCheckServiceImpl* impl)
+ : impl_(impl) {
+ impl_->SetStatus("", HealthCheckResponse::SERVING);
+ }
+ void SetServingStatus(const grpc::string& service_name,
+ bool serving) override {
+ impl_->SetStatus(service_name, serving ? HealthCheckResponse::SERVING
+ : HealthCheckResponse::NOT_SERVING);
+ }
+
+ void SetServingStatus(bool serving) override {
+ impl_->SetAll(serving ? HealthCheckResponse::SERVING
+ : HealthCheckResponse::NOT_SERVING);
+ }
+
+ private:
+ HealthCheckServiceImpl* impl_; // not owned
+};
+
+void LoopCompletionQueue(ServerCompletionQueue* cq) {
+ void* tag;
+ bool ok;
+ while (cq->Next(&tag, &ok)) {
+ abort(); // Nothing should come out of the cq.
+ }
+}
+
+class HealthServiceEnd2endTest : public ::testing::Test {
+ protected:
+ HealthServiceEnd2endTest() {}
+
+ void SetUpServer(bool register_sync_test_service, bool add_async_cq,
+ bool explicit_health_service,
+ std::unique_ptr<HealthCheckServiceInterface> service) {
+ int port = grpc_pick_unused_port_or_die();
+ server_address_ << "localhost:" << port;
+
+ bool register_sync_health_service_impl =
+ explicit_health_service && service != nullptr;
+
+ // Setup server
+ ServerBuilder builder;
+ if (explicit_health_service) {
+ std::unique_ptr<ServerBuilderOption> option(
+ new HealthCheckServiceServerBuilderOption(std::move(service)));
+ builder.SetOption(std::move(option));
+ }
+ builder.AddListeningPort(server_address_.str(),
+ grpc::InsecureServerCredentials());
+ if (register_sync_test_service) {
+ // Register a sync service.
+ builder.RegisterService(&echo_test_service_);
+ }
+ if (register_sync_health_service_impl) {
+ builder.RegisterService(&health_check_service_impl_);
+ }
+ if (add_async_cq) {
+ cq_ = builder.AddCompletionQueue();
+ }
+ server_ = builder.BuildAndStart();
+ }
+
+ void TearDown() override {
+ if (server_) {
+ server_->Shutdown();
+ if (cq_ != nullptr) {
+ cq_->Shutdown();
+ }
+ if (cq_thread_.joinable()) {
+ cq_thread_.join();
+ }
+ }
+ }
+
+ void ResetStubs() {
+ std::shared_ptr<Channel> channel =
+ CreateChannel(server_address_.str(), InsecureChannelCredentials());
+ hc_stub_ = grpc::health::v1::Health::NewStub(channel);
+ }
+
+ // When the expected_status is NOT OK, we do not care about the response.
+ void SendHealthCheckRpc(const grpc::string& service_name,
+ const Status& expected_status) {
+ EXPECT_FALSE(expected_status.ok());
+ SendHealthCheckRpc(service_name, expected_status,
+ HealthCheckResponse::UNKNOWN);
+ }
+
+ void SendHealthCheckRpc(
+ const grpc::string& service_name, const Status& expected_status,
+ HealthCheckResponse::ServingStatus expected_serving_status) {
+ HealthCheckRequest request;
+ request.set_service(service_name);
+ HealthCheckResponse response;
+ ClientContext context;
+ Status s = hc_stub_->Check(&context, request, &response);
+ EXPECT_EQ(expected_status.error_code(), s.error_code());
+ if (s.ok()) {
+ EXPECT_EQ(expected_serving_status, response.status());
+ }
+ }
+
+ void VerifyHealthCheckService() {
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ EXPECT_TRUE(service != nullptr);
+ const grpc::string kHealthyService("healthy_service");
+ const grpc::string kUnhealthyService("unhealthy_service");
+ const grpc::string kNotRegisteredService("not_registered");
+ service->SetServingStatus(kHealthyService, true);
+ service->SetServingStatus(kUnhealthyService, false);
+
+ ResetStubs();
+
+ SendHealthCheckRpc("", Status::OK, HealthCheckResponse::SERVING);
+ SendHealthCheckRpc(kHealthyService, Status::OK,
+ HealthCheckResponse::SERVING);
+ SendHealthCheckRpc(kUnhealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kNotRegisteredService,
+ Status(StatusCode::NOT_FOUND, ""));
+
+ service->SetServingStatus(false);
+ SendHealthCheckRpc("", Status::OK, HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kHealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kUnhealthyService, Status::OK,
+ HealthCheckResponse::NOT_SERVING);
+ SendHealthCheckRpc(kNotRegisteredService,
+ Status(StatusCode::NOT_FOUND, ""));
+ }
+
+ TestServiceImpl echo_test_service_;
+ HealthCheckServiceImpl health_check_service_impl_;
+ std::unique_ptr<Health::Stub> hc_stub_;
+ std::unique_ptr<ServerCompletionQueue> cq_;
+ std::unique_ptr<Server> server_;
+ std::ostringstream server_address_;
+ std::thread cq_thread_;
+};
+
+TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceDisabled) {
+ EnableDefaultHealthCheckService(false);
+ EXPECT_FALSE(DefaultHealthCheckServiceEnabled());
+ SetUpServer(true, false, false, nullptr);
+ HealthCheckServiceInterface* default_service =
+ server_->GetHealthCheckService();
+ EXPECT_TRUE(default_service == nullptr);
+
+ ResetStubs();
+
+ SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
+}
+
+TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ SetUpServer(true, false, false, nullptr);
+ VerifyHealthCheckService();
+
+ // The default service has a size limit of the service name.
+ const grpc::string kTooLongServiceName(201, 'x');
+ SendHealthCheckRpc(kTooLongServiceName,
+ Status(StatusCode::INVALID_ARGUMENT, ""));
+}
+
+// The server has no sync service.
+TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceAsyncOnly) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ SetUpServer(false, true, false, nullptr);
+ cq_thread_ = std::thread(LoopCompletionQueue, cq_.get());
+
+ HealthCheckServiceInterface* default_service =
+ server_->GetHealthCheckService();
+ EXPECT_TRUE(default_service == nullptr);
+
+ ResetStubs();
+
+ SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
+}
+
+// Provide an empty service to disable the default service.
+TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ std::unique_ptr<HealthCheckServiceInterface> empty_service;
+ SetUpServer(true, false, true, std::move(empty_service));
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ EXPECT_TRUE(service == nullptr);
+
+ ResetStubs();
+
+ SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
+}
+
+// Provide an explicit override of health checking service interface.
+TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) {
+ EnableDefaultHealthCheckService(true);
+ EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
+ std::unique_ptr<HealthCheckServiceInterface> override_service(
+ new CustomHealthCheckService(&health_check_service_impl_));
+ HealthCheckServiceInterface* underlying_service = override_service.get();
+ SetUpServer(false, false, true, std::move(override_service));
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ EXPECT_TRUE(service == underlying_service);
+
+ ResetStubs();
+
+ VerifyHealthCheckService();
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index 001047778d..59d36e9cb5 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -88,6 +88,10 @@ void CheckServerAuthContext(
Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) {
+ if (request->has_param() && request->param().server_die()) {
+ gpr_log(GPR_ERROR, "The request should not reach application handler.");
+ GPR_ASSERT(0);
+ }
int server_try_cancel = GetIntValueFromMetadata(
kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
if (server_try_cancel > DO_NOT_CANCEL) {
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 8a00b61cef..5688ab7971 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -51,7 +51,7 @@ DEFINE_bool(use_tls, false, "Whether to use tls.");
DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
DEFINE_bool(use_test_ca, false, "False to use SSL roots for google");
DEFINE_int32(server_port, 0, "Server port.");
-DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
+DEFINE_string(server_host, "localhost", "Server host to connect to");
DEFINE_string(server_host_override, "foo.test.google.fr",
"Override the server host which is sent in HTTP header");
DEFINE_string(
diff --git a/test/cpp/interop/http2_client.cc b/test/cpp/interop/http2_client.cc
index 38aee43b26..01c07823cf 100644
--- a/test/cpp/interop/http2_client.cc
+++ b/test/cpp/interop/http2_client.cc
@@ -65,7 +65,9 @@ Http2Client::ServiceStub::ServiceStub(std::shared_ptr<Channel> channel)
TestService::Stub* Http2Client::ServiceStub::Get() { return stub_.get(); }
Http2Client::Http2Client(std::shared_ptr<Channel> channel)
- : serviceStub_(channel), channel_(channel) {}
+ : serviceStub_(channel),
+ channel_(channel),
+ defaultRequest_(BuildDefaultRequest()) {}
bool Http2Client::AssertStatusCode(const Status& s, StatusCode expected_code) {
if (s.error_code() == expected_code) {
@@ -77,18 +79,24 @@ bool Http2Client::AssertStatusCode(const Status& s, StatusCode expected_code) {
abort();
}
-bool Http2Client::DoRstAfterHeader() {
- gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after header");
-
+Status Http2Client::SendUnaryCall(SimpleResponse* response) {
ClientContext context;
+ return serviceStub_.Get()->UnaryCall(&context, defaultRequest_, response);
+}
+
+SimpleRequest Http2Client::BuildDefaultRequest() {
SimpleRequest request;
- SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+ return request;
+}
+
+bool Http2Client::DoRstAfterHeader() {
+ gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after header");
- Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+ SimpleResponse response;
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL);
GPR_ASSERT(!response.has_payload()); // no data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream after header");
@@ -98,15 +106,8 @@ bool Http2Client::DoRstAfterHeader() {
bool Http2Client::DoRstAfterData() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after data");
- ClientContext context;
- SimpleRequest request;
SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
- Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL);
GPR_ASSERT(response.has_payload()); // data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream after data");
@@ -116,15 +117,8 @@ bool Http2Client::DoRstAfterData() {
bool Http2Client::DoRstDuringData() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream during data");
- ClientContext context;
- SimpleRequest request;
SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
- Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL);
GPR_ASSERT(!response.has_payload()); // no data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream during data");
@@ -133,56 +127,37 @@ bool Http2Client::DoRstDuringData() {
bool Http2Client::DoGoaway() {
gpr_log(GPR_DEBUG, "Sending two RPCs and expecting goaway");
+ SimpleResponse response;
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK);
+ GPR_ASSERT(response.payload().body() ==
+ grpc::string(kLargeResponseSize, '\0'));
- int numCalls = 2;
- for (int i = 0; i < numCalls; i++) {
- ClientContext context;
- SimpleRequest request;
- SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
- Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::OK);
- GPR_ASSERT(response.payload().body() ==
- grpc::string(kLargeResponseSize, '\0'));
- }
+ // Sleep for one second to give time for client to receive goaway frame.
+ gpr_timespec sleep_time = gpr_time_add(
+ gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(1, GPR_TIMESPAN));
+ gpr_sleep_until(sleep_time);
+ response.Clear();
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK);
+ GPR_ASSERT(response.payload().body() ==
+ grpc::string(kLargeResponseSize, '\0'));
gpr_log(GPR_DEBUG, "Done testing goaway");
return true;
}
bool Http2Client::DoPing() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting ping");
-
- ClientContext context;
- SimpleRequest request;
SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
- Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::OK);
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
-
gpr_log(GPR_DEBUG, "Done testing ping");
return true;
}
void Http2Client::MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel) {
- ClientContext context;
- SimpleRequest request;
SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
- Status s =
- TestService::NewStub(channel)->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::OK);
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
}
@@ -192,15 +167,8 @@ bool Http2Client::DoMaxStreams() {
// Make an initial call on the channel to ensure the server's max streams
// setting is received
- ClientContext context;
- SimpleRequest request;
SimpleResponse response;
- request.set_response_size(kLargeResponseSize);
- grpc::string payload(kLargeRequestSize, '\0');
- request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
- Status s =
- TestService::NewStub(channel_)->UnaryCall(&context, request, &response);
- AssertStatusCode(s, grpc::StatusCode::OK);
+ AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
@@ -223,7 +191,7 @@ bool Http2Client::DoMaxStreams() {
} // namespace grpc
DEFINE_int32(server_port, 0, "Server port.");
-DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
+DEFINE_string(server_host, "localhost", "Server host to connect to");
DEFINE_string(test_case, "rst_after_header",
"Configure different test cases. Valid options are:\n\n"
"goaway\n"
@@ -240,7 +208,11 @@ int main(int argc, char** argv) {
char host_port[host_port_buf_size];
snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
FLAGS_server_port);
- grpc::testing::Http2Client client(grpc::CreateTestChannel(host_port, false));
+ std::shared_ptr<grpc::Channel> channel =
+ grpc::CreateTestChannel(host_port, false);
+ GPR_ASSERT(channel->WaitForConnected(gpr_time_add(
+ gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(300, GPR_TIMESPAN))));
+ grpc::testing::Http2Client client(channel);
gpr_log(GPR_INFO, "Testing case: %s", FLAGS_test_case.c_str());
int ret = 0;
if (FLAGS_test_case == "rst_after_header") {
diff --git a/test/cpp/interop/http2_client.h b/test/cpp/interop/http2_client.h
index 6a315f5abb..12df5d26bc 100644
--- a/test/cpp/interop/http2_client.h
+++ b/test/cpp/interop/http2_client.h
@@ -70,8 +70,11 @@ class Http2Client {
void MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel);
bool AssertStatusCode(const Status& s, StatusCode expected_code);
+ Status SendUnaryCall(SimpleResponse* response);
+ SimpleRequest BuildDefaultRequest();
ServiceStub serviceStub_;
std::shared_ptr<Channel> channel_;
+ SimpleRequest defaultRequest_;
};
} // namespace testing
diff --git a/test/cpp/interop/reconnect_interop_client.cc b/test/cpp/interop/reconnect_interop_client.cc
index 797e52c744..1c2f606637 100644
--- a/test/cpp/interop/reconnect_interop_client.cc
+++ b/test/cpp/interop/reconnect_interop_client.cc
@@ -48,7 +48,7 @@
DEFINE_int32(server_control_port, 0, "Server port for control rpcs.");
DEFINE_int32(server_retry_port, 0, "Server port for testing reconnection.");
-DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
+DEFINE_string(server_host, "localhost", "Server host to connect to");
DEFINE_int32(max_reconnect_backoff_ms, 0,
"Maximum backoff time, or 0 for default.");
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
new file mode 100644
index 0000000000..014e2b96b5
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -0,0 +1,463 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* This benchmark exists to ensure that the benchmark integration is
+ * working */
+
+#include <string.h>
+#include <sstream>
+
+#include <grpc++/channel.h>
+#include <grpc++/support/channel_arguments.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+extern "C" {
+#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/deadline_filter.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/channel/message_size_filter.h"
+#include "src/core/lib/transport/transport_impl.h"
+}
+
+#include "src/cpp/client/create_channel_internal.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+auto &force_library_initialization = Library::get();
+
+void BM_Zalloc(benchmark::State &state) {
+ // speed of light for call creation is zalloc, so benchmark a few interesting
+ // sizes
+ size_t sz = state.range(0);
+ while (state.KeepRunning()) {
+ gpr_free(gpr_zalloc(sz));
+ }
+}
+BENCHMARK(BM_Zalloc)
+ ->Arg(64)
+ ->Arg(128)
+ ->Arg(256)
+ ->Arg(512)
+ ->Arg(1024)
+ ->Arg(1536)
+ ->Arg(2048)
+ ->Arg(3072)
+ ->Arg(4096)
+ ->Arg(5120)
+ ->Arg(6144)
+ ->Arg(7168);
+
+class BaseChannelFixture {
+ public:
+ BaseChannelFixture(grpc_channel *channel) : channel_(channel) {}
+ ~BaseChannelFixture() { grpc_channel_destroy(channel_); }
+
+ grpc_channel *channel() const { return channel_; }
+
+ private:
+ grpc_channel *const channel_;
+};
+
+class InsecureChannel : public BaseChannelFixture {
+ public:
+ InsecureChannel()
+ : BaseChannelFixture(
+ grpc_insecure_channel_create("localhost:1234", NULL, NULL)) {}
+};
+
+class LameChannel : public BaseChannelFixture {
+ public:
+ LameChannel()
+ : BaseChannelFixture(grpc_lame_client_channel_create(
+ "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah")) {}
+};
+
+template <class Fixture>
+static void BM_CallCreateDestroy(benchmark::State &state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+ gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ void *method_hdl =
+ grpc_channel_register_call(fixture.channel(), "/foo/bar", NULL, NULL);
+ while (state.KeepRunning()) {
+ grpc_call_destroy(grpc_channel_create_registered_call(
+ fixture.channel(), NULL, GRPC_PROPAGATE_DEFAULTS, cq, method_hdl,
+ deadline, NULL));
+ }
+ grpc_completion_queue_destroy(cq);
+ track_counters.Finish(state);
+}
+
+BENCHMARK_TEMPLATE(BM_CallCreateDestroy, InsecureChannel);
+BENCHMARK_TEMPLATE(BM_CallCreateDestroy, LameChannel);
+
+static void *tag(int i) {
+ return reinterpret_cast<void *>(static_cast<intptr_t>(i));
+}
+
+static void BM_LameChannelCallCreateCpp(benchmark::State &state) {
+ TrackCounters track_counters;
+ auto stub =
+ grpc::testing::EchoTestService::NewStub(grpc::CreateChannelInternal(
+ "", grpc_lame_client_channel_create(
+ "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah")));
+ grpc::CompletionQueue cq;
+ grpc::testing::EchoRequest send_request;
+ grpc::testing::EchoResponse recv_response;
+ grpc::Status recv_status;
+ while (state.KeepRunning()) {
+ grpc::ClientContext cli_ctx;
+ auto reader = stub->AsyncEcho(&cli_ctx, send_request, &cq);
+ reader->Finish(&recv_response, &recv_status, tag(0));
+ void *t;
+ bool ok;
+ GPR_ASSERT(cq.Next(&t, &ok));
+ GPR_ASSERT(ok);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_LameChannelCallCreateCpp);
+
+static void FilterDestroy(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ gpr_free(arg);
+}
+
+static void DoNothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+
+class FakeClientChannelFactory : public grpc_client_channel_factory {
+ public:
+ FakeClientChannelFactory() { vtable = &vtable_; }
+
+ private:
+ static void NoRef(grpc_client_channel_factory *factory) {}
+ static void NoUnref(grpc_exec_ctx *exec_ctx,
+ grpc_client_channel_factory *factory) {}
+ static grpc_subchannel *CreateSubchannel(grpc_exec_ctx *exec_ctx,
+ grpc_client_channel_factory *factory,
+ const grpc_subchannel_args *args) {
+ return nullptr;
+ }
+ static grpc_channel *CreateClientChannel(grpc_exec_ctx *exec_ctx,
+ grpc_client_channel_factory *factory,
+ const char *target,
+ grpc_client_channel_type type,
+ const grpc_channel_args *args) {
+ return nullptr;
+ }
+
+ static const grpc_client_channel_factory_vtable vtable_;
+};
+
+const grpc_client_channel_factory_vtable FakeClientChannelFactory::vtable_ = {
+ NoRef, NoUnref, CreateSubchannel, CreateClientChannel};
+
+static grpc_arg StringArg(const char *key, const char *value) {
+ grpc_arg a;
+ a.type = GRPC_ARG_STRING;
+ a.key = const_cast<char *>(key);
+ a.value.string = const_cast<char *>(value);
+ return a;
+}
+
+enum FixtureFlags : uint32_t {
+ CHECKS_NOT_LAST = 1,
+ REQUIRES_TRANSPORT = 2,
+};
+
+template <const grpc_channel_filter *kFilter, uint32_t kFlags>
+struct Fixture {
+ const grpc_channel_filter *filter = kFilter;
+ const uint32_t flags = kFlags;
+};
+
+namespace dummy_filter {
+
+static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_transport_stream_op *op) {}
+
+static void StartTransportOp(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ grpc_transport_op *op) {}
+
+static grpc_error *InitCallElem(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ const grpc_call_element_args *args) {
+ return GRPC_ERROR_NONE;
+}
+
+static void SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_polling_entity *pollent) {}
+
+static void DestroyCallElem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ const grpc_call_final_info *final_info,
+ void *and_free_memory) {}
+
+grpc_error *InitChannelElem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ grpc_channel_element_args *args) {
+ return GRPC_ERROR_NONE;
+}
+
+void DestroyChannelElem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) {}
+
+char *GetPeer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+ return gpr_strdup("peer");
+}
+
+void GetChannelInfo(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {}
+
+static const grpc_channel_filter dummy_filter = {StartTransportStreamOp,
+ StartTransportOp,
+ 0,
+ InitCallElem,
+ SetPollsetOrPollsetSet,
+ DestroyCallElem,
+ 0,
+ InitChannelElem,
+ DestroyChannelElem,
+ GetPeer,
+ GetChannelInfo,
+ "dummy_filter"};
+
+} // namespace dummy_filter
+
+namespace dummy_transport {
+
+/* Memory required for a single stream element - this is allocated by upper
+ layers and initialized by the transport */
+size_t sizeof_stream; /* = sizeof(transport stream) */
+
+/* name of this transport implementation */
+const char *name;
+
+/* implementation of grpc_transport_init_stream */
+int InitStream(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, grpc_stream_refcount *refcount,
+ const void *server_data) {
+ return 0;
+}
+
+/* implementation of grpc_transport_set_pollset */
+void SetPollset(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, grpc_pollset *pollset) {}
+
+/* implementation of grpc_transport_set_pollset */
+void SetPollsetSet(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, grpc_pollset_set *pollset_set) {}
+
+/* implementation of grpc_transport_perform_stream_op */
+void PerformStreamOp(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, grpc_transport_stream_op *op) {
+ grpc_closure_sched(exec_ctx, op->on_complete, GRPC_ERROR_NONE);
+}
+
+/* implementation of grpc_transport_perform_op */
+void PerformOp(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_transport_op *op) {}
+
+/* implementation of grpc_transport_destroy_stream */
+void DestroyStream(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, void *and_free_memory) {}
+
+/* implementation of grpc_transport_destroy */
+void Destroy(grpc_exec_ctx *exec_ctx, grpc_transport *self) {}
+
+/* implementation of grpc_transport_get_peer */
+char *GetPeer(grpc_exec_ctx *exec_ctx, grpc_transport *self) {
+ return gpr_strdup("transport_peer");
+}
+
+/* implementation of grpc_transport_get_endpoint */
+grpc_endpoint *GetEndpoint(grpc_exec_ctx *exec_ctx, grpc_transport *self) {
+ return nullptr;
+}
+
+static const grpc_transport_vtable dummy_transport_vtable = {
+ 0, "dummy_http2", InitStream,
+ SetPollset, SetPollsetSet, PerformStreamOp,
+ PerformOp, DestroyStream, Destroy,
+ GetPeer, GetEndpoint};
+
+static grpc_transport dummy_transport = {&dummy_transport_vtable};
+
+} // namespace dummy_transport
+
+class NoOp {
+ public:
+ class Op {
+ public:
+ Op(grpc_exec_ctx *exec_ctx, NoOp *p, grpc_call_stack *s) {}
+ void Finish(grpc_exec_ctx *exec_ctx) {}
+ };
+};
+
+class SendEmptyMetadata {
+ public:
+ SendEmptyMetadata() {
+ memset(&op_, 0, sizeof(op_));
+ op_.on_complete = grpc_closure_init(&closure_, DoNothing, nullptr,
+ grpc_schedule_on_exec_ctx);
+ }
+
+ class Op {
+ public:
+ Op(grpc_exec_ctx *exec_ctx, SendEmptyMetadata *p, grpc_call_stack *s) {
+ grpc_metadata_batch_init(&batch_);
+ p->op_.send_initial_metadata = &batch_;
+ }
+ void Finish(grpc_exec_ctx *exec_ctx) {
+ grpc_metadata_batch_destroy(exec_ctx, &batch_);
+ }
+
+ private:
+ grpc_metadata_batch batch_;
+ };
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ const gpr_timespec start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
+ const grpc_slice method_ = grpc_slice_from_static_string("/foo/bar");
+ grpc_transport_stream_op op_;
+ grpc_closure closure_;
+};
+
+// Test a filter in isolation. Fixture specifies the filter under test (use the
+// Fixture<> template to specify this), and TestOp defines some unit of work to
+// perform on said filter.
+template <class Fixture, class TestOp>
+static void BM_IsolatedFilter(benchmark::State &state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ std::ostringstream label;
+
+ std::vector<grpc_arg> args;
+ FakeClientChannelFactory fake_client_channel_factory;
+ args.push_back(grpc_client_channel_factory_create_channel_arg(
+ &fake_client_channel_factory));
+ args.push_back(StringArg(GRPC_ARG_SERVER_URI, "localhost"));
+
+ grpc_channel_args channel_args = {args.size(), &args[0]};
+
+ std::vector<const grpc_channel_filter *> filters;
+ if (fixture.filter != nullptr) {
+ filters.push_back(fixture.filter);
+ }
+ if (fixture.flags & CHECKS_NOT_LAST) {
+ filters.push_back(&dummy_filter::dummy_filter);
+ label << " #has_dummy_filter";
+ }
+
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ size_t channel_size = grpc_channel_stack_size(&filters[0], filters.size());
+ grpc_channel_stack *channel_stack =
+ static_cast<grpc_channel_stack *>(gpr_zalloc(channel_size));
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "call_stack_init",
+ grpc_channel_stack_init(&exec_ctx, 1, FilterDestroy, channel_stack,
+ &filters[0], filters.size(), &channel_args,
+ fixture.flags & REQUIRES_TRANSPORT
+ ? &dummy_transport::dummy_transport
+ : nullptr,
+ "CHANNEL", channel_stack)));
+ grpc_exec_ctx_flush(&exec_ctx);
+ grpc_call_stack *call_stack = static_cast<grpc_call_stack *>(
+ gpr_zalloc(channel_stack->call_stack_size));
+ gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ gpr_timespec start_time = gpr_now(GPR_CLOCK_MONOTONIC);
+ grpc_slice method = grpc_slice_from_static_string("/foo/bar");
+ grpc_call_final_info final_info;
+ TestOp test_op_data;
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(grpc_call_stack_init(&exec_ctx, channel_stack, 1,
+ DoNothing, NULL, NULL, NULL, method,
+ start_time, deadline, call_stack));
+ typename TestOp::Op op(&exec_ctx, &test_op_data, call_stack);
+ grpc_call_stack_destroy(&exec_ctx, call_stack, &final_info, NULL);
+ op.Finish(&exec_ctx);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_channel_stack_destroy(&exec_ctx, channel_stack);
+ grpc_exec_ctx_finish(&exec_ctx);
+ gpr_free(channel_stack);
+ gpr_free(call_stack);
+
+ state.SetLabel(label.str());
+ track_counters.Finish(state);
+}
+
+typedef Fixture<nullptr, 0> NoFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, NoFilter, NoOp);
+typedef Fixture<&dummy_filter::dummy_filter, 0> DummyFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, DummyFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, DummyFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_client_channel_filter, 0> ClientChannelFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientChannelFilter, NoOp);
+typedef Fixture<&grpc_compress_filter, CHECKS_NOT_LAST> CompressFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_client_deadline_filter, CHECKS_NOT_LAST>
+ ClientDeadlineFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientDeadlineFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientDeadlineFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_server_deadline_filter, CHECKS_NOT_LAST>
+ ServerDeadlineFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, ServerDeadlineFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, ServerDeadlineFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_http_client_filter, CHECKS_NOT_LAST | REQUIRES_TRANSPORT>
+ HttpClientFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpClientFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpClientFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_http_server_filter, CHECKS_NOT_LAST> HttpServerFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpServerFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, HttpServerFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_message_size_filter, CHECKS_NOT_LAST> MessageSizeFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, MessageSizeFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, MessageSizeFilter, SendEmptyMetadata);
+typedef Fixture<&grpc_load_reporting_filter, CHECKS_NOT_LAST>
+ LoadReportingFilter;
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, NoOp);
+BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, SendEmptyMetadata);
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
new file mode 100644
index 0000000000..563db758f7
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -0,0 +1,449 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Microbenchmarks around CHTTP2 HPACK operations */
+
+#include <grpc/support/log.h>
+#include <string.h>
+#include <sstream>
+extern "C" {
+#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/transport/static_metadata.h"
+}
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+auto &force_library_initialization = Library::get();
+
+////////////////////////////////////////////////////////////////////////////////
+// HPACK encoder
+//
+
+static void BM_HpackEncoderInitDestroy(benchmark::State &state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_chttp2_hpack_compressor c;
+ while (state.KeepRunning()) {
+ grpc_chttp2_hpack_compressor_init(&c);
+ grpc_chttp2_hpack_compressor_destroy(&exec_ctx, &c);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_HpackEncoderInitDestroy);
+
+template <class Fixture>
+static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ grpc_metadata_batch b;
+ grpc_metadata_batch_init(&b);
+ std::vector<grpc_mdelem> elems = Fixture::GetElems(&exec_ctx);
+ std::vector<grpc_linked_mdelem> storage(elems.size());
+ for (size_t i = 0; i < elems.size(); i++) {
+ GPR_ASSERT(GRPC_LOG_IF_ERROR(
+ "addmd",
+ grpc_metadata_batch_add_tail(&exec_ctx, &b, &storage[i], elems[i])));
+ }
+
+ grpc_chttp2_hpack_compressor c;
+ grpc_chttp2_hpack_compressor_init(&c);
+ grpc_transport_one_way_stats stats;
+ memset(&stats, 0, sizeof(stats));
+ grpc_slice_buffer outbuf;
+ grpc_slice_buffer_init(&outbuf);
+ while (state.KeepRunning()) {
+ grpc_chttp2_encode_header(&exec_ctx, &c, (uint32_t)state.iterations(), &b,
+ state.range(0), state.range(1), &stats, &outbuf);
+ grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, &outbuf);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_metadata_batch_destroy(&exec_ctx, &b);
+ grpc_chttp2_hpack_compressor_destroy(&exec_ctx, &c);
+ grpc_slice_buffer_destroy_internal(&exec_ctx, &outbuf);
+ grpc_exec_ctx_finish(&exec_ctx);
+
+ std::ostringstream label;
+ label << "framing_bytes/iter:" << (static_cast<double>(stats.framing_bytes) /
+ static_cast<double>(state.iterations()))
+ << " header_bytes/iter:" << (static_cast<double>(stats.header_bytes) /
+ static_cast<double>(state.iterations()));
+ state.SetLabel(label.str());
+ track_counters.Finish(state);
+}
+
+namespace hpack_encoder_fixtures {
+
+class EmptyBatch {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {};
+ }
+};
+
+class SingleStaticElem {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE};
+ }
+};
+
+class SingleInternedElem {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {grpc_mdelem_from_slices(
+ exec_ctx, grpc_slice_intern(grpc_slice_from_static_string("abc")),
+ grpc_slice_intern(grpc_slice_from_static_string("def")))};
+ }
+};
+
+class SingleInternedKeyElem {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {grpc_mdelem_from_slices(
+ exec_ctx, grpc_slice_intern(grpc_slice_from_static_string("abc")),
+ grpc_slice_from_static_string("def"))};
+ }
+};
+
+class SingleNonInternedElem {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {grpc_mdelem_from_slices(exec_ctx,
+ grpc_slice_from_static_string("abc"),
+ grpc_slice_from_static_string("def"))};
+ }
+};
+
+class RepresentativeClientInitialMetadata {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {
+ GRPC_MDELEM_SCHEME_HTTP, GRPC_MDELEM_METHOD_POST,
+ grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_PATH,
+ grpc_slice_intern(grpc_slice_from_static_string("/foo/bar"))),
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_slice_intern(grpc_slice_from_static_string(
+ "foo.test.google.fr:1234"))),
+ GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
+ GRPC_MDELEM_TE_TRAILERS,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
+ grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_USER_AGENT,
+ grpc_slice_intern(grpc_slice_from_static_string(
+ "grpc-c/3.0.0-dev (linux; chttp2; green)")))};
+ }
+};
+
+class RepresentativeServerInitialMetadata {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {GRPC_MDELEM_STATUS_200,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
+ GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP};
+ }
+};
+
+class RepresentativeServerTrailingMetadata {
+ public:
+ static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
+ return {GRPC_MDELEM_GRPC_STATUS_0};
+ }
+};
+
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({0, 16384});
+// test with eof (shouldn't affect anything)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, EmptyBatch)->Args({1, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleStaticElem)
+ ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedKeyElem)
+ ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedElem)
+ ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
+ ->Args({0, 16384});
+// test with a tiny frame size, to highlight continuation costs
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
+ ->Args({0, 1});
+
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+ RepresentativeClientInitialMetadata)
+ ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+ RepresentativeServerInitialMetadata)
+ ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+ RepresentativeServerTrailingMetadata)
+ ->Args({1, 16384});
+
+} // namespace hpack_encoder_fixtures
+
+////////////////////////////////////////////////////////////////////////////////
+// HPACK parser
+//
+
+static void BM_HpackParserInitDestroy(benchmark::State &state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_chttp2_hpack_parser p;
+ while (state.KeepRunning()) {
+ grpc_chttp2_hpack_parser_init(&exec_ctx, &p);
+ grpc_chttp2_hpack_parser_destroy(&exec_ctx, &p);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_HpackParserInitDestroy);
+
+static void UnrefHeader(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_mdelem md) {
+ GRPC_MDELEM_UNREF(exec_ctx, md);
+}
+
+template <class Fixture>
+static void BM_HpackParserParseHeader(benchmark::State &state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ std::vector<grpc_slice> init_slices = Fixture::GetInitSlices();
+ std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
+ grpc_chttp2_hpack_parser p;
+ grpc_chttp2_hpack_parser_init(&exec_ctx, &p);
+ p.on_header = UnrefHeader;
+ p.on_header_user_data = nullptr;
+ for (auto slice : init_slices) {
+ grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice);
+ }
+ while (state.KeepRunning()) {
+ for (auto slice : benchmark_slices) {
+ grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice);
+ }
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_chttp2_hpack_parser_destroy(&exec_ctx, &p);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+
+namespace hpack_parser_fixtures {
+
+static grpc_slice MakeSlice(std::initializer_list<uint8_t> bytes) {
+ grpc_slice s = grpc_slice_malloc(bytes.size());
+ uint8_t *p = GRPC_SLICE_START_PTR(s);
+ for (auto b : bytes) {
+ *p++ = b;
+ }
+ return s;
+}
+
+class EmptyBatch {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({})};
+ }
+};
+
+class IndexedSingleStaticElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice(
+ {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0xbe})};
+ }
+};
+
+class AddIndexedSingleStaticElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice(
+ {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
+ }
+};
+
+class KeyIndexedSingleStaticElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice(
+ {0x40, 0x07, ':', 's', 't', 'a', 't', 'u', 's', 0x03, '2', '0', '0'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x7e, 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class IndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0xbe})};
+ }
+};
+
+class AddIndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class KeyIndexedSingleInternedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {MakeSlice({0x40, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x7e, 0x03, 'g', 'h', 'i'})};
+ }
+};
+
+class NonIndexedElem {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() { return {}; }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ return {MakeSlice({0x00, 0x03, 'a', 'b', 'c', 0x03, 'd', 'e', 'f'})};
+ }
+};
+
+class RepresentativeClientInitialMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // < test/core/bad_client/tests/simple_request.headers
+ // ```
+ "@\x05:path\x08/foo/bar"
+ "@\x07:scheme\x04http"
+ "@\x07:method\x04POST"
+ "@\x0a:authority\x09localhost"
+ "@\x0c"
+ "content-type\x10"
+ "application/grpc"
+ "@\x14grpc-accept-encoding\x15identity,deflate,gzip"
+ "@\x02te\x08trailers"
+ "@\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex < test/core/bad_client/tests/simple_request.headers
+ // ```
+ return {MakeSlice({0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe})};
+ }
+};
+
+class RepresentativeServerInitialMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // <
+ // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
+ // ```
+ "@\x07:status\x03"
+ "200"
+ "@\x0c"
+ "content-type\x10"
+ "application/grpc"
+ "@\x14grpc-accept-encoding\x15identity,deflate,gzip")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex <
+ // test/cpp/microbenchmarks/representative_server_initial_metadata.headers
+ // ```
+ return {MakeSlice({0xc0, 0xbf, 0xbe})};
+ }
+};
+
+class RepresentativeServerTrailingMetadata {
+ public:
+ static std::vector<grpc_slice> GetInitSlices() {
+ return {grpc_slice_from_static_string(
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression inc --no_framing
+ // <
+ // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
+ // ```
+ "@\x0bgrpc-status\x01"
+ "0"
+ "@\x0cgrpc-message\x00")};
+ }
+ static std::vector<grpc_slice> GetBenchmarkSlices() {
+ // generated with:
+ // ```
+ // tools/codegen/core/gen_header_frame.py --compression pre --no_framing
+ // --hex <
+ // test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
+ // ```
+ return {MakeSlice({0xbf, 0xbe})};
+ }
+};
+
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleStaticElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeClientInitialMetadata);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerInitialMetadata);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerTrailingMetadata);
+
+} // namespace hpack_parser_fixtures
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_closure.cc b/test/cpp/microbenchmarks/bm_closure.cc
new file mode 100644
index 0000000000..28a385b6c1
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_closure.cc
@@ -0,0 +1,444 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test various closure related operations */
+
+#include <grpc/grpc.h>
+
+extern "C" {
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/support/spinlock.h"
+}
+
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+auto& force_library_initialization = Library::get();
+
+static void BM_NoOpExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_NoOpExecCtx);
+
+static void BM_WellFlushed(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_WellFlushed);
+
+static void DoNothing(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {}
+
+static void BM_ClosureInitAgainstExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_closure c;
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(
+ grpc_closure_init(&c, DoNothing, NULL, grpc_schedule_on_exec_ctx));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureInitAgainstExecCtx);
+
+static void BM_ClosureInitAgainstCombiner(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ grpc_closure c;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(grpc_closure_init(
+ &c, DoNothing, NULL, grpc_combiner_scheduler(combiner, false)));
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureInitAgainstCombiner);
+
+static void BM_ClosureRunOnExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_closure c;
+ grpc_closure_init(&c, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_run(&exec_ctx, &c, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureRunOnExecCtx);
+
+static void BM_ClosureCreateAndRun(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_run(&exec_ctx, grpc_closure_create(DoNothing, NULL,
+ grpc_schedule_on_exec_ctx),
+ GRPC_ERROR_NONE);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureCreateAndRun);
+
+static void BM_ClosureInitAndRun(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_closure c;
+ while (state.KeepRunning()) {
+ grpc_closure_run(&exec_ctx, grpc_closure_init(&c, DoNothing, NULL,
+ grpc_schedule_on_exec_ctx),
+ GRPC_ERROR_NONE);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureInitAndRun);
+
+static void BM_ClosureSchedOnExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_closure c;
+ grpc_closure_init(&c, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSchedOnExecCtx);
+
+static void BM_ClosureSched2OnExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure_init(&c1, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_closure_init(&c2, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched2OnExecCtx);
+
+static void BM_ClosureSched3OnExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure c3;
+ grpc_closure_init(&c1, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_closure_init(&c2, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_closure_init(&c3, DoNothing, NULL, grpc_schedule_on_exec_ctx);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c3, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched3OnExecCtx);
+
+static void BM_AcquireMutex(benchmark::State& state) {
+ TrackCounters track_counters;
+ // for comparison with the combiner stuff below
+ gpr_mu mu;
+ gpr_mu_init(&mu);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ gpr_mu_lock(&mu);
+ DoNothing(&exec_ctx, NULL, GRPC_ERROR_NONE);
+ gpr_mu_unlock(&mu);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_AcquireMutex);
+
+static void BM_TryAcquireMutex(benchmark::State& state) {
+ TrackCounters track_counters;
+ // for comparison with the combiner stuff below
+ gpr_mu mu;
+ gpr_mu_init(&mu);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ if (gpr_mu_trylock(&mu)) {
+ DoNothing(&exec_ctx, NULL, GRPC_ERROR_NONE);
+ gpr_mu_unlock(&mu);
+ } else {
+ abort();
+ }
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_TryAcquireMutex);
+
+static void BM_AcquireSpinlock(benchmark::State& state) {
+ TrackCounters track_counters;
+ // for comparison with the combiner stuff below
+ gpr_spinlock mu = GPR_SPINLOCK_INITIALIZER;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ gpr_spinlock_lock(&mu);
+ DoNothing(&exec_ctx, NULL, GRPC_ERROR_NONE);
+ gpr_spinlock_unlock(&mu);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_AcquireSpinlock);
+
+static void BM_TryAcquireSpinlock(benchmark::State& state) {
+ TrackCounters track_counters;
+ // for comparison with the combiner stuff below
+ gpr_spinlock mu = GPR_SPINLOCK_INITIALIZER;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ if (gpr_spinlock_trylock(&mu)) {
+ DoNothing(&exec_ctx, NULL, GRPC_ERROR_NONE);
+ gpr_spinlock_unlock(&mu);
+ } else {
+ abort();
+ }
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_TryAcquireSpinlock);
+
+static void BM_ClosureSchedOnCombiner(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ grpc_closure c;
+ grpc_closure_init(&c, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSchedOnCombiner);
+
+static void BM_ClosureSched2OnCombiner(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure_init(&c1, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_closure_init(&c2, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched2OnCombiner);
+
+static void BM_ClosureSched3OnCombiner(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure c3;
+ grpc_closure_init(&c1, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_closure_init(&c2, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_closure_init(&c3, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner, false));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c3, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched3OnCombiner);
+
+static void BM_ClosureSched2OnTwoCombiners(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner1 = grpc_combiner_create(NULL);
+ grpc_combiner* combiner2 = grpc_combiner_create(NULL);
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure_init(&c1, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner1, false));
+ grpc_closure_init(&c2, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner2, false));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner1, "finished");
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner2, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched2OnTwoCombiners);
+
+static void BM_ClosureSched4OnTwoCombiners(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_combiner* combiner1 = grpc_combiner_create(NULL);
+ grpc_combiner* combiner2 = grpc_combiner_create(NULL);
+ grpc_closure c1;
+ grpc_closure c2;
+ grpc_closure c3;
+ grpc_closure c4;
+ grpc_closure_init(&c1, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner1, false));
+ grpc_closure_init(&c2, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner2, false));
+ grpc_closure_init(&c3, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner1, false));
+ grpc_closure_init(&c4, DoNothing, NULL,
+ grpc_combiner_scheduler(combiner2, false));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_closure_sched(&exec_ctx, &c1, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c2, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c3, GRPC_ERROR_NONE);
+ grpc_closure_sched(&exec_ctx, &c4, GRPC_ERROR_NONE);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner1, "finished");
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner2, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureSched4OnTwoCombiners);
+
+// Helper that continuously reschedules the same closure against something until
+// the benchmark is complete
+class Rescheduler {
+ public:
+ Rescheduler(benchmark::State& state, grpc_closure_scheduler* scheduler)
+ : state_(state) {
+ grpc_closure_init(&closure_, Step, this, scheduler);
+ }
+
+ void ScheduleFirst(grpc_exec_ctx* exec_ctx) {
+ grpc_closure_sched(exec_ctx, &closure_, GRPC_ERROR_NONE);
+ }
+
+ void ScheduleFirstAgainstDifferentScheduler(
+ grpc_exec_ctx* exec_ctx, grpc_closure_scheduler* scheduler) {
+ grpc_closure_sched(exec_ctx, grpc_closure_create(Step, this, scheduler),
+ GRPC_ERROR_NONE);
+ }
+
+ private:
+ benchmark::State& state_;
+ grpc_closure closure_;
+
+ static void Step(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
+ Rescheduler* self = static_cast<Rescheduler*>(arg);
+ if (self->state_.KeepRunning()) {
+ grpc_closure_sched(exec_ctx, &self->closure_, GRPC_ERROR_NONE);
+ }
+ }
+};
+
+static void BM_ClosureReschedOnExecCtx(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ Rescheduler r(state, grpc_schedule_on_exec_ctx);
+ r.ScheduleFirst(&exec_ctx);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureReschedOnExecCtx);
+
+static void BM_ClosureReschedOnCombiner(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ Rescheduler r(state, grpc_combiner_scheduler(combiner, false));
+ r.ScheduleFirst(&exec_ctx);
+ grpc_exec_ctx_flush(&exec_ctx);
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureReschedOnCombiner);
+
+static void BM_ClosureReschedOnCombinerFinally(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_combiner* combiner = grpc_combiner_create(NULL);
+ Rescheduler r(state, grpc_combiner_finally_scheduler(combiner, false));
+ r.ScheduleFirstAgainstDifferentScheduler(
+ &exec_ctx, grpc_combiner_scheduler(combiner, false));
+ grpc_exec_ctx_flush(&exec_ctx);
+ GRPC_COMBINER_UNREF(&exec_ctx, combiner, "finished");
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ClosureReschedOnCombinerFinally);
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc
new file mode 100644
index 0000000000..91e6a85101
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_cq.cc
@@ -0,0 +1,150 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* This benchmark exists to ensure that the benchmark integration is
+ * working */
+
+#include <grpc++/completion_queue.h>
+#include <grpc++/impl/grpc_library.h>
+#include <grpc/grpc.h>
+
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+extern "C" {
+#include "src/core/lib/surface/completion_queue.h"
+}
+
+namespace grpc {
+namespace testing {
+
+auto& force_library_initialization = Library::get();
+
+static void BM_CreateDestroyCpp(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ CompletionQueue cq;
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_CreateDestroyCpp);
+
+static void BM_CreateDestroyCore(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ grpc_completion_queue_destroy(grpc_completion_queue_create(NULL));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_CreateDestroyCore);
+
+static void DoneWithCompletionOnStack(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_cq_completion* completion) {}
+
+class DummyTag final : public CompletionQueueTag {
+ public:
+ bool FinalizeResult(void** tag, bool* status) override { return true; }
+};
+
+static void BM_Pass1Cpp(benchmark::State& state) {
+ TrackCounters track_counters;
+ CompletionQueue cq;
+ grpc_completion_queue* c_cq = cq.cq();
+ while (state.KeepRunning()) {
+ grpc_cq_completion completion;
+ DummyTag dummy_tag;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_cq_begin_op(c_cq, &dummy_tag);
+ grpc_cq_end_op(&exec_ctx, c_cq, &dummy_tag, GRPC_ERROR_NONE,
+ DoneWithCompletionOnStack, NULL, &completion);
+ grpc_exec_ctx_finish(&exec_ctx);
+ void* tag;
+ bool ok;
+ cq.Next(&tag, &ok);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_Pass1Cpp);
+
+static void BM_Pass1Core(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+ gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ while (state.KeepRunning()) {
+ grpc_cq_completion completion;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_cq_begin_op(cq, NULL);
+ grpc_cq_end_op(&exec_ctx, cq, NULL, GRPC_ERROR_NONE,
+ DoneWithCompletionOnStack, NULL, &completion);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_completion_queue_next(cq, deadline, NULL);
+ }
+ grpc_completion_queue_destroy(cq);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_Pass1Core);
+
+static void BM_Pluck1Core(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+ gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ while (state.KeepRunning()) {
+ grpc_cq_completion completion;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_cq_begin_op(cq, NULL);
+ grpc_cq_end_op(&exec_ctx, cq, NULL, GRPC_ERROR_NONE,
+ DoneWithCompletionOnStack, NULL, &completion);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_completion_queue_pluck(cq, NULL, deadline, NULL);
+ }
+ grpc_completion_queue_destroy(cq);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_Pluck1Core);
+
+static void BM_EmptyCore(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+ gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+ while (state.KeepRunning()) {
+ grpc_completion_queue_next(cq, deadline, NULL);
+ }
+ grpc_completion_queue_destroy(cq);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_EmptyCore);
+
+} // namespace testing
+} // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc
new file mode 100644
index 0000000000..c4f6aa19d5
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_error.cc
@@ -0,0 +1,312 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test various operations on grpc_error */
+
+#include <memory>
+
+extern "C" {
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/transport/error_utils.h"
+}
+
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+auto& force_library_initialization = Library::get();
+
+class ErrorDeleter {
+ public:
+ void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); }
+};
+typedef std::unique_ptr<grpc_error, ErrorDeleter> ErrorPtr;
+
+static void BM_ErrorCreate(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_CREATE("Error"));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorCreate);
+
+static void BM_ErrorCreateAndSetStatus(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_ABORTED));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorCreateAndSetStatus);
+
+static void BM_ErrorCreateAndSetIntAndStr(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
+ GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)0),
+ GRPC_ERROR_STR_RAW_BYTES, "raw bytes"));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorCreateAndSetIntAndStr);
+
+static void BM_ErrorCreateAndSetIntLoop(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_error* error = GRPC_ERROR_CREATE("Error");
+ int n = 0;
+ while (state.KeepRunning()) {
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, n++);
+ }
+ GRPC_ERROR_UNREF(error);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorCreateAndSetIntLoop);
+
+static void BM_ErrorCreateAndSetStrLoop(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_error* error = GRPC_ERROR_CREATE("Error");
+ const char* str = "hello";
+ while (state.KeepRunning()) {
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, str);
+ }
+ GRPC_ERROR_UNREF(error);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorCreateAndSetStrLoop);
+
+static void BM_ErrorRefUnref(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_error* error = GRPC_ERROR_CREATE("Error");
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorRefUnref);
+
+static void BM_ErrorUnrefNone(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_NONE);
+ }
+}
+BENCHMARK(BM_ErrorUnrefNone);
+
+static void BM_ErrorGetIntFromNoError(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(GRPC_ERROR_NONE, GRPC_ERROR_INT_GRPC_STATUS, &value);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorGetIntFromNoError);
+
+static void BM_ErrorGetMissingInt(benchmark::State& state) {
+ TrackCounters track_counters;
+ ErrorPtr error(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Error"), GRPC_ERROR_INT_INDEX, 1));
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorGetMissingInt);
+
+static void BM_ErrorGetPresentInt(benchmark::State& state) {
+ TrackCounters track_counters;
+ ErrorPtr error(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Error"), GRPC_ERROR_INT_OFFSET, 1));
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_ErrorGetPresentInt);
+
+// Fixtures for tests: generate different kinds of errors
+class ErrorNone {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return GRPC_ERROR_NONE; }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+};
+
+class ErrorCancelled {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+};
+
+class SimpleError {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{GRPC_ERROR_CREATE("Error")};
+};
+
+class ErrorWithGrpcStatus {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED)};
+};
+
+class ErrorWithHttpError {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ GRPC_HTTP2_COMPRESSION_ERROR)};
+};
+
+class ErrorWithNestedGrpcStatus {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr nested_error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED)};
+ grpc_error* nested_errors_[1] = {nested_error_.get()};
+ ErrorPtr error_{GRPC_ERROR_CREATE_REFERENCING("Error", nested_errors_, 1)};
+};
+
+template <class Fixture>
+static void BM_ErrorStringOnNewError(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ Fixture fixture;
+ grpc_error_string(fixture.error());
+ }
+ track_counters.Finish(state);
+}
+
+template <class Fixture>
+static void BM_ErrorStringRepeatedly(benchmark::State& state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_error_string(fixture.error());
+ }
+ track_counters.Finish(state);
+}
+
+template <class Fixture>
+static void BM_ErrorGetStatus(benchmark::State& state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_status_code status;
+ const char* msg;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), &status, &msg,
+ NULL);
+ }
+ track_counters.Finish(state);
+}
+
+template <class Fixture>
+static void BM_ErrorGetStatusCode(benchmark::State& state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_status_code status;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), &status, NULL,
+ NULL);
+ }
+ track_counters.Finish(state);
+}
+
+template <class Fixture>
+static void BM_ErrorHttpError(benchmark::State& state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_http2_error_code error;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), NULL, NULL,
+ &error);
+ }
+ track_counters.Finish(state);
+}
+
+template <class Fixture>
+static void BM_HasClearGrpcStatus(benchmark::State& state) {
+ TrackCounters track_counters;
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_error_has_clear_grpc_status(fixture.error());
+ }
+ track_counters.Finish(state);
+}
+
+#define BENCHMARK_SUITE(fixture) \
+ BENCHMARK_TEMPLATE(BM_ErrorStringOnNewError, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorStringRepeatedly, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorGetStatus, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorGetStatusCode, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorHttpError, fixture); \
+ BENCHMARK_TEMPLATE(BM_HasClearGrpcStatus, fixture)
+
+BENCHMARK_SUITE(ErrorNone);
+BENCHMARK_SUITE(ErrorCancelled);
+BENCHMARK_SUITE(SimpleError);
+BENCHMARK_SUITE(ErrorWithGrpcStatus);
+BENCHMARK_SUITE(ErrorWithHttpError);
+BENCHMARK_SUITE(ErrorWithNestedGrpcStatus);
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_fullstack.cc b/test/cpp/microbenchmarks/bm_fullstack.cc
deleted file mode 100644
index 9d883e68d7..0000000000
--- a/test/cpp/microbenchmarks/bm_fullstack.cc
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Benchmark gRPC end2end in various configurations */
-
-#include <sstream>
-
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc/support/log.h>
-
-extern "C" {
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/iomgr/endpoint.h"
-#include "src/core/lib/iomgr/endpoint_pair.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/tcp_posix.h"
-#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/surface/completion_queue.h"
-#include "src/core/lib/surface/server.h"
-#include "test/core/util/memory_counters.h"
-#include "test/core/util/passthru_endpoint.h"
-#include "test/core/util/port.h"
-}
-#include "src/core/lib/profiling/timers.h"
-#include "src/cpp/client/create_channel_internal.h"
-#include "src/proto/grpc/testing/echo.grpc.pb.h"
-#include "third_party/benchmark/include/benchmark/benchmark.h"
-
-namespace grpc {
-namespace testing {
-
-static class InitializeStuff {
- public:
- InitializeStuff() {
- grpc_memory_counters_init();
- init_lib_.init();
- rq_ = grpc_resource_quota_create("bm");
- }
-
- ~InitializeStuff() { init_lib_.shutdown(); }
-
- grpc_resource_quota* rq() { return rq_; }
-
- private:
- internal::GrpcLibrary init_lib_;
- grpc_resource_quota* rq_;
-} initialize_stuff;
-
-/*******************************************************************************
- * FIXTURES
- */
-
-static void ApplyCommonServerBuilderConfig(ServerBuilder* b) {
- b->SetMaxReceiveMessageSize(INT_MAX);
- b->SetMaxSendMessageSize(INT_MAX);
-}
-
-static void ApplyCommonChannelArguments(ChannelArguments* c) {
- c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
- c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
-}
-
-#ifdef GPR_MU_COUNTERS
-extern "C" gpr_atm grpc_mu_locks;
-#endif
-
-class BaseFixture {
- public:
- void Finish(benchmark::State& s) {
- std::ostringstream out;
- this->AddToLabel(out, s);
-#ifdef GPR_MU_COUNTERS
- out << " locks/iter:" << ((double)(gpr_atm_no_barrier_load(&grpc_mu_locks) -
- mu_locks_at_start_) /
- (double)s.iterations());
-#endif
- grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
- out << " allocs/iter:"
- << ((double)(counters_at_end.total_allocs_absolute -
- counters_at_start_.total_allocs_absolute) /
- (double)s.iterations());
- auto label = out.str();
- if (label.length() && label[0] == ' ') {
- label = label.substr(1);
- }
- s.SetLabel(label);
- }
-
- virtual void AddToLabel(std::ostream& out, benchmark::State& s) = 0;
-
- private:
-#ifdef GPR_MU_COUNTERS
- const size_t mu_locks_at_start_ = gpr_atm_no_barrier_load(&grpc_mu_locks);
-#endif
- grpc_memory_counters counters_at_start_ = grpc_memory_counters_snapshot();
-};
-
-class FullstackFixture : public BaseFixture {
- public:
- FullstackFixture(Service* service, const grpc::string& address) {
- ServerBuilder b;
- b.AddListeningPort(address, InsecureServerCredentials());
- cq_ = b.AddCompletionQueue(true);
- b.RegisterService(service);
- ApplyCommonServerBuilderConfig(&b);
- server_ = b.BuildAndStart();
- ChannelArguments args;
- ApplyCommonChannelArguments(&args);
- channel_ = CreateCustomChannel(address, InsecureChannelCredentials(), args);
- }
-
- virtual ~FullstackFixture() {
- server_->Shutdown();
- cq_->Shutdown();
- void* tag;
- bool ok;
- while (cq_->Next(&tag, &ok)) {
- }
- }
-
- ServerCompletionQueue* cq() { return cq_.get(); }
- std::shared_ptr<Channel> channel() { return channel_; }
-
- private:
- std::unique_ptr<Server> server_;
- std::unique_ptr<ServerCompletionQueue> cq_;
- std::shared_ptr<Channel> channel_;
-};
-
-class TCP : public FullstackFixture {
- public:
- TCP(Service* service) : FullstackFixture(service, MakeAddress()) {}
-
- void AddToLabel(std::ostream& out, benchmark::State& state) {}
-
- private:
- static grpc::string MakeAddress() {
- int port = grpc_pick_unused_port_or_die();
- std::stringstream addr;
- addr << "localhost:" << port;
- return addr.str();
- }
-};
-
-class UDS : public FullstackFixture {
- public:
- UDS(Service* service) : FullstackFixture(service, MakeAddress()) {}
-
- void AddToLabel(std::ostream& out, benchmark::State& state) override {}
-
- private:
- static grpc::string MakeAddress() {
- int port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
- // real port
- std::stringstream addr;
- addr << "unix:/tmp/bm_fullstack." << port;
- return addr.str();
- }
-};
-
-class EndpointPairFixture : public BaseFixture {
- public:
- EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints) {
- ServerBuilder b;
- cq_ = b.AddCompletionQueue(true);
- b.RegisterService(service);
- ApplyCommonServerBuilderConfig(&b);
- server_ = b.BuildAndStart();
-
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- /* add server endpoint to server_ */
- {
- const grpc_channel_args* server_args =
- grpc_server_get_channel_args(server_->c_server());
- grpc_transport* transport = grpc_create_chttp2_transport(
- &exec_ctx, server_args, endpoints.server, 0 /* is_client */);
-
- grpc_pollset** pollsets;
- size_t num_pollsets = 0;
- grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets);
-
- for (size_t i = 0; i < num_pollsets; i++) {
- grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]);
- }
-
- grpc_server_setup_transport(&exec_ctx, server_->c_server(), transport,
- NULL, server_args);
- grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
- }
-
- /* create channel */
- {
- ChannelArguments args;
- args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
- ApplyCommonChannelArguments(&args);
-
- grpc_channel_args c_args = args.c_channel_args();
- grpc_transport* transport =
- grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1);
- GPR_ASSERT(transport);
- grpc_channel* channel = grpc_channel_create(
- &exec_ctx, "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
- grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
-
- channel_ = CreateChannelInternal("", channel);
- }
-
- grpc_exec_ctx_finish(&exec_ctx);
- }
-
- virtual ~EndpointPairFixture() {
- server_->Shutdown();
- cq_->Shutdown();
- void* tag;
- bool ok;
- while (cq_->Next(&tag, &ok)) {
- }
- }
-
- ServerCompletionQueue* cq() { return cq_.get(); }
- std::shared_ptr<Channel> channel() { return channel_; }
-
- private:
- std::unique_ptr<Server> server_;
- std::unique_ptr<ServerCompletionQueue> cq_;
- std::shared_ptr<Channel> channel_;
-};
-
-class SockPair : public EndpointPairFixture {
- public:
- SockPair(Service* service)
- : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
- "test", initialize_stuff.rq(), 8192)) {
- }
-
- void AddToLabel(std::ostream& out, benchmark::State& state) {}
-};
-
-class InProcessCHTTP2 : public EndpointPairFixture {
- public:
- InProcessCHTTP2(Service* service)
- : EndpointPairFixture(service, MakeEndpoints()) {}
-
- void AddToLabel(std::ostream& out, benchmark::State& state) {
- out << " writes/iter:"
- << ((double)stats_.num_writes / (double)state.iterations());
- }
-
- private:
- grpc_passthru_endpoint_stats stats_;
-
- grpc_endpoint_pair MakeEndpoints() {
- grpc_endpoint_pair p;
- grpc_passthru_endpoint_create(&p.client, &p.server, initialize_stuff.rq(),
- &stats_);
- return p;
- }
-};
-
-/*******************************************************************************
- * CONTEXT MUTATORS
- */
-
-static const int kPregenerateKeyCount = 100000;
-
-template <class F>
-auto MakeVector(size_t length, F f) -> std::vector<decltype(f())> {
- std::vector<decltype(f())> out;
- out.reserve(length);
- for (size_t i = 0; i < length; i++) {
- out.push_back(f());
- }
- return out;
-}
-
-class NoOpMutator {
- public:
- template <class ContextType>
- NoOpMutator(ContextType* context) {}
-};
-
-template <int length>
-class RandomBinaryMetadata {
- public:
- static const grpc::string& Key() { return kKey; }
-
- static const grpc::string& Value() {
- return kValues[rand() % kValues.size()];
- }
-
- private:
- static const grpc::string kKey;
- static const std::vector<grpc::string> kValues;
-
- static grpc::string GenerateOneString() {
- grpc::string s;
- s.reserve(length + 1);
- for (int i = 0; i < length; i++) {
- s += (char)rand();
- }
- return s;
- }
-};
-
-template <int length>
-const grpc::string RandomBinaryMetadata<length>::kKey = "foo-bin";
-
-template <int length>
-const std::vector<grpc::string> RandomBinaryMetadata<length>::kValues =
- MakeVector(kPregenerateKeyCount, GenerateOneString);
-
-template <int length>
-class RandomAsciiMetadata {
- public:
- static const grpc::string& Key() { return kKey; }
-
- static const grpc::string& Value() {
- return kValues[rand() % kValues.size()];
- }
-
- private:
- static const grpc::string kKey;
- static const std::vector<grpc::string> kValues;
-
- static grpc::string GenerateOneString() {
- grpc::string s;
- s.reserve(length + 1);
- for (int i = 0; i < length; i++) {
- s += (char)(rand() % 26 + 'a');
- }
- return s;
- }
-};
-
-template <int length>
-const grpc::string RandomAsciiMetadata<length>::kKey = "foo";
-
-template <int length>
-const std::vector<grpc::string> RandomAsciiMetadata<length>::kValues =
- MakeVector(kPregenerateKeyCount, GenerateOneString);
-
-template <class Generator, int kNumKeys>
-class Client_AddMetadata : public NoOpMutator {
- public:
- Client_AddMetadata(ClientContext* context) : NoOpMutator(context) {
- for (int i = 0; i < kNumKeys; i++) {
- context->AddMetadata(Generator::Key(), Generator::Value());
- }
- }
-};
-
-template <class Generator, int kNumKeys>
-class Server_AddInitialMetadata : public NoOpMutator {
- public:
- Server_AddInitialMetadata(ServerContext* context) : NoOpMutator(context) {
- for (int i = 0; i < kNumKeys; i++) {
- context->AddInitialMetadata(Generator::Key(), Generator::Value());
- }
- }
-};
-
-/*******************************************************************************
- * BENCHMARKING KERNELS
- */
-
-static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
-
-template <class Fixture, class ClientContextMutator, class ServerContextMutator>
-static void BM_UnaryPingPong(benchmark::State& state) {
- EchoTestService::AsyncService service;
- std::unique_ptr<Fixture> fixture(new Fixture(&service));
- EchoRequest send_request;
- EchoResponse send_response;
- EchoResponse recv_response;
- if (state.range(0) > 0) {
- send_request.set_message(std::string(state.range(0), 'a'));
- }
- if (state.range(1) > 0) {
- send_response.set_message(std::string(state.range(1), 'a'));
- }
- Status recv_status;
- struct ServerEnv {
- ServerContext ctx;
- EchoRequest recv_request;
- grpc::ServerAsyncResponseWriter<EchoResponse> response_writer;
- ServerEnv() : response_writer(&ctx) {}
- };
- uint8_t server_env_buffer[2 * sizeof(ServerEnv)];
- ServerEnv* server_env[2] = {
- reinterpret_cast<ServerEnv*>(server_env_buffer),
- reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))};
- new (server_env[0]) ServerEnv;
- new (server_env[1]) ServerEnv;
- service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request,
- &server_env[0]->response_writer, fixture->cq(),
- fixture->cq(), tag(0));
- service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request,
- &server_env[1]->response_writer, fixture->cq(),
- fixture->cq(), tag(1));
- std::unique_ptr<EchoTestService::Stub> stub(
- EchoTestService::NewStub(fixture->channel()));
- while (state.KeepRunning()) {
- GPR_TIMER_SCOPE("BenchmarkCycle", 0);
- recv_response.Clear();
- ClientContext cli_ctx;
- ClientContextMutator cli_ctx_mut(&cli_ctx);
- std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
- stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
- void* t;
- bool ok;
- 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];
- 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);
- int tagnum = (int)reinterpret_cast<intptr_t>(t);
- GPR_ASSERT(i & (1 << tagnum));
- i -= 1 << tagnum;
- }
- GPR_ASSERT(recv_status.ok());
-
- senv->~ServerEnv();
- senv = new (senv) ServerEnv();
- service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer,
- fixture->cq(), fixture->cq(), tag(slot));
- }
- fixture->Finish(state);
- fixture.reset();
- server_env[0]->~ServerEnv();
- server_env[1]->~ServerEnv();
- state.SetBytesProcessed(state.range(0) * state.iterations() +
- state.range(1) * state.iterations());
-}
-
-// Repeatedly makes Streaming Bidi calls (exchanging a configurable number of
-// messages in each call) in a loop on a single channel
-//
-// First parmeter (i.e state.range(0)): Message size (in bytes) to use
-// Second parameter (i.e state.range(1)): Number of ping pong messages.
-// Note: One ping-pong means two messages (one from client to server and
-// the other from server to client):
-template <class Fixture, class ClientContextMutator, class ServerContextMutator>
-static void BM_StreamingPingPong(benchmark::State& state) {
- const int msg_size = state.range(0);
- const int max_ping_pongs = state.range(1);
-
- EchoTestService::AsyncService service;
- std::unique_ptr<Fixture> fixture(new Fixture(&service));
- {
- EchoResponse send_response;
- EchoResponse recv_response;
- EchoRequest send_request;
- EchoRequest recv_request;
-
- if (msg_size > 0) {
- send_request.set_message(std::string(msg_size, 'a'));
- send_response.set_message(std::string(msg_size, 'b'));
- }
-
- std::unique_ptr<EchoTestService::Stub> stub(
- EchoTestService::NewStub(fixture->channel()));
-
- while (state.KeepRunning()) {
- ServerContext svr_ctx;
- ServerContextMutator svr_ctx_mut(&svr_ctx);
- ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
- service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
- fixture->cq(), tag(0));
-
- ClientContext cli_ctx;
- ClientContextMutator cli_ctx_mut(&cli_ctx);
- auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
-
- // Establish async stream between client side and server side
- void* t;
- bool ok;
- int need_tags = (1 << 0) | (1 << 1);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
-
- // Send 'max_ping_pongs' number of ping pong messages
- int ping_pong_cnt = 0;
- while (ping_pong_cnt < max_ping_pongs) {
- request_rw->Write(send_request, tag(0)); // Start client send
- response_rw.Read(&recv_request, tag(1)); // Start server recv
- request_rw->Read(&recv_response, tag(2)); // Start client recv
-
- need_tags = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
-
- // If server recv is complete, start the server send operation
- if (i == 1) {
- response_rw.Write(send_response, tag(3));
- }
-
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
-
- ping_pong_cnt++;
- }
-
- request_rw->WritesDone(tag(0));
- response_rw.Finish(Status::OK, tag(1));
-
- Status recv_status;
- request_rw->Finish(&recv_status, tag(2));
-
- need_tags = (1 << 0) | (1 << 1) | (1 << 2);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
-
- GPR_ASSERT(recv_status.ok());
- }
- }
-
- fixture->Finish(state);
- fixture.reset();
- state.SetBytesProcessed(msg_size * state.iterations() * max_ping_pongs * 2);
-}
-
-// Repeatedly sends ping pong messages in a single streaming Bidi call in a loop
-// First parmeter (i.e state.range(0)): Message size (in bytes) to use
-template <class Fixture, class ClientContextMutator, class ServerContextMutator>
-static void BM_StreamingPingPongMsgs(benchmark::State& state) {
- const int msg_size = state.range(0);
-
- EchoTestService::AsyncService service;
- std::unique_ptr<Fixture> fixture(new Fixture(&service));
- {
- EchoResponse send_response;
- EchoResponse recv_response;
- EchoRequest send_request;
- EchoRequest recv_request;
-
- if (msg_size > 0) {
- send_request.set_message(std::string(msg_size, 'a'));
- send_response.set_message(std::string(msg_size, 'b'));
- }
-
- std::unique_ptr<EchoTestService::Stub> stub(
- EchoTestService::NewStub(fixture->channel()));
-
- ServerContext svr_ctx;
- ServerContextMutator svr_ctx_mut(&svr_ctx);
- ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
- service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
- fixture->cq(), tag(0));
-
- ClientContext cli_ctx;
- ClientContextMutator cli_ctx_mut(&cli_ctx);
- auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
-
- // Establish async stream between client side and server side
- void* t;
- bool ok;
- int need_tags = (1 << 0) | (1 << 1);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
-
- while (state.KeepRunning()) {
- request_rw->Write(send_request, tag(0)); // Start client send
- response_rw.Read(&recv_request, tag(1)); // Start server recv
- request_rw->Read(&recv_response, tag(2)); // Start client recv
-
- need_tags = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
-
- // If server recv is complete, start the server send operation
- if (i == 1) {
- response_rw.Write(send_response, tag(3));
- }
-
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
- }
-
- request_rw->WritesDone(tag(0));
- response_rw.Finish(Status::OK, tag(1));
- Status recv_status;
- request_rw->Finish(&recv_status, tag(2));
-
- need_tags = (1 << 0) | (1 << 1) | (1 << 2);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
-
- GPR_ASSERT(recv_status.ok());
- }
-
- fixture->Finish(state);
- fixture.reset();
- state.SetBytesProcessed(msg_size * state.iterations() * 2);
-}
-
-template <class Fixture>
-static void BM_PumpStreamClientToServer(benchmark::State& state) {
- EchoTestService::AsyncService service;
- std::unique_ptr<Fixture> fixture(new Fixture(&service));
- {
- EchoRequest send_request;
- EchoRequest recv_request;
- if (state.range(0) > 0) {
- send_request.set_message(std::string(state.range(0), 'a'));
- }
- Status recv_status;
- ServerContext svr_ctx;
- ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
- service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
- fixture->cq(), tag(0));
- std::unique_ptr<EchoTestService::Stub> stub(
- EchoTestService::NewStub(fixture->channel()));
- ClientContext cli_ctx;
- auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
- int need_tags = (1 << 0) | (1 << 1);
- void* t;
- bool ok;
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
- response_rw.Read(&recv_request, tag(0));
- while (state.KeepRunning()) {
- GPR_TIMER_SCOPE("BenchmarkCycle", 0);
- request_rw->Write(send_request, tag(1));
- while (true) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- if (t == tag(0)) {
- response_rw.Read(&recv_request, tag(0));
- } else if (t == tag(1)) {
- break;
- } else {
- GPR_ASSERT(false);
- }
- }
- }
- request_rw->WritesDone(tag(1));
- need_tags = (1 << 0) | (1 << 1);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
- }
- fixture->Finish(state);
- fixture.reset();
- state.SetBytesProcessed(state.range(0) * state.iterations());
-}
-
-template <class Fixture>
-static void BM_PumpStreamServerToClient(benchmark::State& state) {
- EchoTestService::AsyncService service;
- std::unique_ptr<Fixture> fixture(new Fixture(&service));
- {
- EchoResponse send_response;
- EchoResponse recv_response;
- if (state.range(0) > 0) {
- send_response.set_message(std::string(state.range(0), 'a'));
- }
- Status recv_status;
- ServerContext svr_ctx;
- ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
- service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
- fixture->cq(), tag(0));
- std::unique_ptr<EchoTestService::Stub> stub(
- EchoTestService::NewStub(fixture->channel()));
- ClientContext cli_ctx;
- auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
- int need_tags = (1 << 0) | (1 << 1);
- void* t;
- bool ok;
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- GPR_ASSERT(ok);
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
- request_rw->Read(&recv_response, tag(0));
- while (state.KeepRunning()) {
- GPR_TIMER_SCOPE("BenchmarkCycle", 0);
- response_rw.Write(send_response, tag(1));
- while (true) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- if (t == tag(0)) {
- request_rw->Read(&recv_response, tag(0));
- } else if (t == tag(1)) {
- break;
- } else {
- GPR_ASSERT(false);
- }
- }
- }
- response_rw.Finish(Status::OK, tag(1));
- need_tags = (1 << 0) | (1 << 1);
- while (need_tags) {
- GPR_ASSERT(fixture->cq()->Next(&t, &ok));
- int i = (int)(intptr_t)t;
- GPR_ASSERT(need_tags & (1 << i));
- need_tags &= ~(1 << i);
- }
- }
- fixture->Finish(state);
- fixture.reset();
- state.SetBytesProcessed(state.range(0) * state.iterations());
-}
-
-/*******************************************************************************
- * CONFIGURATIONS
- */
-
-static void SweepSizesArgs(benchmark::internal::Benchmark* b) {
- b->Args({0, 0});
- for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
- b->Args({i, 0});
- b->Args({0, i});
- b->Args({i, i});
- }
-}
-
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator)
- ->Apply(SweepSizesArgs);
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator)
- ->Apply(SweepSizesArgs);
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
- NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
- NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
- Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
- ->Args({0, 0});
-BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
- Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
- ->Args({0, 0});
-
-BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, TCP)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, SockPair)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcessCHTTP2)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, TCP)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, UDS)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, SockPair)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
- ->Range(0, 128 * 1024 * 1024);
-
-// Generate Args for StreamingPingPong benchmarks. Currently generates args for
-// only "small streams" (i.e streams with 0, 1 or 2 messages)
-static void StreamingPingPongArgs(benchmark::internal::Benchmark* b) {
- int msg_size = 0;
-
- b->Args({0, 0}); // spl case: 0 ping-pong msgs (msg_size doesn't matter here)
-
- for (msg_size = 0; msg_size <= 128 * 1024 * 1024;
- msg_size == 0 ? msg_size++ : msg_size *= 8) {
- b->Args({msg_size, 1});
- b->Args({msg_size, 2});
- }
-}
-
-BENCHMARK_TEMPLATE(BM_StreamingPingPong, InProcessCHTTP2, NoOpMutator,
- NoOpMutator)
- ->Apply(StreamingPingPongArgs);
-BENCHMARK_TEMPLATE(BM_StreamingPingPong, TCP, NoOpMutator, NoOpMutator)
- ->Apply(StreamingPingPongArgs);
-
-BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, InProcessCHTTP2, NoOpMutator,
- NoOpMutator)
- ->Range(0, 128 * 1024 * 1024);
-BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, TCP, NoOpMutator, NoOpMutator)
- ->Range(0, 128 * 1024 * 1024);
-
-} // namespace testing
-} // namespace grpc
-
-BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
new file mode 100644
index 0000000000..dc0e7d769a
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
@@ -0,0 +1,197 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Benchmark gRPC end2end in various configurations */
+
+#include <sstream>
+
+#include "src/core/lib/profiling/timers.h"
+#include "src/cpp/client/create_channel_internal.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+namespace grpc {
+namespace testing {
+
+// force library initialization
+auto& force_library_initialization = Library::get();
+
+/*******************************************************************************
+ * BENCHMARKING KERNELS
+ */
+
+static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
+
+template <class Fixture>
+static void BM_PumpStreamClientToServer(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<Fixture> fixture(new Fixture(&service));
+ {
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ if (state.range(0) > 0) {
+ send_request.set_message(std::string(state.range(0), 'a'));
+ }
+ Status recv_status;
+ ServerContext svr_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
+ service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
+ fixture->cq(), tag(0));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ ClientContext cli_ctx;
+ auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
+ int need_tags = (1 << 0) | (1 << 1);
+ void* t;
+ bool ok;
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ GPR_ASSERT(ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ response_rw.Read(&recv_request, tag(0));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ request_rw->Write(send_request, tag(1));
+ while (true) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ if (t == tag(0)) {
+ response_rw.Read(&recv_request, tag(0));
+ } else if (t == tag(1)) {
+ break;
+ } else {
+ GPR_ASSERT(false);
+ }
+ }
+ }
+ request_rw->WritesDone(tag(1));
+ need_tags = (1 << 0) | (1 << 1);
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ state.SetBytesProcessed(state.range(0) * state.iterations());
+}
+
+template <class Fixture>
+static void BM_PumpStreamServerToClient(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<Fixture> fixture(new Fixture(&service));
+ {
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ if (state.range(0) > 0) {
+ send_response.set_message(std::string(state.range(0), 'a'));
+ }
+ Status recv_status;
+ ServerContext svr_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
+ service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
+ fixture->cq(), tag(0));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ ClientContext cli_ctx;
+ auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
+ int need_tags = (1 << 0) | (1 << 1);
+ void* t;
+ bool ok;
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ GPR_ASSERT(ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ request_rw->Read(&recv_response, tag(0));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ response_rw.Write(send_response, tag(1));
+ while (true) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ if (t == tag(0)) {
+ request_rw->Read(&recv_response, tag(0));
+ } else if (t == tag(1)) {
+ break;
+ } else {
+ GPR_ASSERT(false);
+ }
+ }
+ }
+ response_rw.Finish(Status::OK, tag(1));
+ need_tags = (1 << 0) | (1 << 1);
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ state.SetBytesProcessed(state.range(0) * state.iterations());
+}
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, TCP)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, SockPair)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcessCHTTP2)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, TCP)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, UDS)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, SockPair)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
+ ->Range(0, 128 * 1024 * 1024);
+
+} // namespace testing
+} // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
new file mode 100644
index 0000000000..dc0e7d769a
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
@@ -0,0 +1,197 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Benchmark gRPC end2end in various configurations */
+
+#include <sstream>
+
+#include "src/core/lib/profiling/timers.h"
+#include "src/cpp/client/create_channel_internal.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+namespace grpc {
+namespace testing {
+
+// force library initialization
+auto& force_library_initialization = Library::get();
+
+/*******************************************************************************
+ * BENCHMARKING KERNELS
+ */
+
+static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
+
+template <class Fixture>
+static void BM_PumpStreamClientToServer(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<Fixture> fixture(new Fixture(&service));
+ {
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ if (state.range(0) > 0) {
+ send_request.set_message(std::string(state.range(0), 'a'));
+ }
+ Status recv_status;
+ ServerContext svr_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
+ service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
+ fixture->cq(), tag(0));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ ClientContext cli_ctx;
+ auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
+ int need_tags = (1 << 0) | (1 << 1);
+ void* t;
+ bool ok;
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ GPR_ASSERT(ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ response_rw.Read(&recv_request, tag(0));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ request_rw->Write(send_request, tag(1));
+ while (true) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ if (t == tag(0)) {
+ response_rw.Read(&recv_request, tag(0));
+ } else if (t == tag(1)) {
+ break;
+ } else {
+ GPR_ASSERT(false);
+ }
+ }
+ }
+ request_rw->WritesDone(tag(1));
+ need_tags = (1 << 0) | (1 << 1);
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ state.SetBytesProcessed(state.range(0) * state.iterations());
+}
+
+template <class Fixture>
+static void BM_PumpStreamServerToClient(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<Fixture> fixture(new Fixture(&service));
+ {
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ if (state.range(0) > 0) {
+ send_response.set_message(std::string(state.range(0), 'a'));
+ }
+ Status recv_status;
+ ServerContext svr_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
+ service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
+ fixture->cq(), tag(0));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ ClientContext cli_ctx;
+ auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
+ int need_tags = (1 << 0) | (1 << 1);
+ void* t;
+ bool ok;
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ GPR_ASSERT(ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ request_rw->Read(&recv_response, tag(0));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ response_rw.Write(send_response, tag(1));
+ while (true) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ if (t == tag(0)) {
+ request_rw->Read(&recv_response, tag(0));
+ } else if (t == tag(1)) {
+ break;
+ } else {
+ GPR_ASSERT(false);
+ }
+ }
+ }
+ response_rw.Finish(Status::OK, tag(1));
+ need_tags = (1 << 0) | (1 << 1);
+ while (need_tags) {
+ GPR_ASSERT(fixture->cq()->Next(&t, &ok));
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ state.SetBytesProcessed(state.range(0) * state.iterations());
+}
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, TCP)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, SockPair)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcessCHTTP2)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, TCP)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, UDS)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, SockPair)
+ ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
+ ->Range(0, 128 * 1024 * 1024);
+
+} // namespace testing
+} // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
new file mode 100644
index 0000000000..5011f06368
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -0,0 +1,219 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Benchmark gRPC end2end in various configurations */
+
+#include "src/core/lib/profiling/timers.h"
+#include "src/cpp/client/create_channel_internal.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+extern "C" {
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "test/core/util/trickle_endpoint.h"
+}
+
+namespace grpc {
+namespace testing {
+
+static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
+
+class TrickledCHTTP2 : public EndpointPairFixture {
+ public:
+ TrickledCHTTP2(Service* service, size_t megabits_per_second)
+ : EndpointPairFixture(service, MakeEndpoints(megabits_per_second)) {}
+
+ void AddToLabel(std::ostream& out, benchmark::State& state) {
+ out << " writes/iter:"
+ << ((double)stats_.num_writes / (double)state.iterations())
+ << " cli_transport_stalls/iter:"
+ << ((double)
+ client_stats_.streams_stalled_due_to_transport_flow_control /
+ (double)state.iterations())
+ << " cli_stream_stalls/iter:"
+ << ((double)client_stats_.streams_stalled_due_to_stream_flow_control /
+ (double)state.iterations())
+ << " svr_transport_stalls/iter:"
+ << ((double)
+ server_stats_.streams_stalled_due_to_transport_flow_control /
+ (double)state.iterations())
+ << " svr_stream_stalls/iter:"
+ << ((double)server_stats_.streams_stalled_due_to_stream_flow_control /
+ (double)state.iterations());
+ }
+
+ void Step() {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ size_t client_backlog =
+ grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.client);
+ size_t server_backlog =
+ grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.server);
+ grpc_exec_ctx_finish(&exec_ctx);
+
+ UpdateStats((grpc_chttp2_transport*)client_transport_, &client_stats_,
+ client_backlog);
+ UpdateStats((grpc_chttp2_transport*)server_transport_, &server_stats_,
+ server_backlog);
+ }
+
+ private:
+ grpc_passthru_endpoint_stats stats_;
+ struct Stats {
+ int streams_stalled_due_to_stream_flow_control = 0;
+ int streams_stalled_due_to_transport_flow_control = 0;
+ };
+ Stats client_stats_;
+ Stats server_stats_;
+
+ grpc_endpoint_pair MakeEndpoints(size_t kilobits) {
+ grpc_endpoint_pair p;
+ grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(),
+ &stats_);
+ double bytes_per_second = 125.0 * kilobits;
+ p.client = grpc_trickle_endpoint_create(p.client, bytes_per_second);
+ p.server = grpc_trickle_endpoint_create(p.server, bytes_per_second);
+ return p;
+ }
+
+ void UpdateStats(grpc_chttp2_transport* t, Stats* s, size_t backlog) {
+ if (backlog == 0) {
+ if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != NULL) {
+ s->streams_stalled_due_to_stream_flow_control++;
+ }
+ if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != NULL) {
+ s->streams_stalled_due_to_transport_flow_control++;
+ }
+ }
+ }
+};
+
+// force library initialization
+auto& force_library_initialization = Library::get();
+
+static void TrickleCQNext(TrickledCHTTP2* fixture, void** t, bool* ok) {
+ while (true) {
+ switch (fixture->cq()->AsyncNext(
+ t, ok, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_micros(100, GPR_TIMESPAN)))) {
+ case CompletionQueue::TIMEOUT:
+ fixture->Step();
+ break;
+ case CompletionQueue::SHUTDOWN:
+ GPR_ASSERT(false);
+ break;
+ case CompletionQueue::GOT_EVENT:
+ return;
+ }
+ }
+}
+
+static void BM_PumpStreamServerToClient_Trickle(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<TrickledCHTTP2> fixture(
+ new TrickledCHTTP2(&service, state.range(1)));
+ {
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ if (state.range(0) > 0) {
+ send_response.set_message(std::string(state.range(0), 'a'));
+ }
+ Status recv_status;
+ ServerContext svr_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
+ service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
+ fixture->cq(), tag(0));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ ClientContext cli_ctx;
+ auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
+ int need_tags = (1 << 0) | (1 << 1);
+ void* t;
+ bool ok;
+ while (need_tags) {
+ TrickleCQNext(fixture.get(), &t, &ok);
+ GPR_ASSERT(ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ request_rw->Read(&recv_response, tag(0));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ response_rw.Write(send_response, tag(1));
+ while (true) {
+ TrickleCQNext(fixture.get(), &t, &ok);
+ if (t == tag(0)) {
+ request_rw->Read(&recv_response, tag(0));
+ } else if (t == tag(1)) {
+ break;
+ } else {
+ GPR_ASSERT(false);
+ }
+ }
+ }
+ response_rw.Finish(Status::OK, tag(1));
+ need_tags = (1 << 0) | (1 << 1);
+ while (need_tags) {
+ TrickleCQNext(fixture.get(), &t, &ok);
+ int i = (int)(intptr_t)t;
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
+ }
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ state.SetBytesProcessed(state.range(0) * state.iterations());
+}
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+static void TrickleArgs(benchmark::internal::Benchmark* b) {
+ for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
+ for (int j = 1; j <= 128 * 1024 * 1024; j *= 8) {
+ double expected_time =
+ static_cast<double>(14 + i) / (125.0 * static_cast<double>(j));
+ if (expected_time > 0.01) continue;
+ b->Args({i, j});
+ }
+ }
+}
+
+BENCHMARK(BM_PumpStreamServerToClient_Trickle)->Apply(TrickleArgs);
+}
+}
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
new file mode 100644
index 0000000000..e51d272b10
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
@@ -0,0 +1,205 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Benchmark gRPC end2end in various configurations */
+
+#include <sstream>
+
+#include "src/core/lib/profiling/timers.h"
+#include "src/cpp/client/create_channel_internal.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
+#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+namespace grpc {
+namespace testing {
+
+// force library initialization
+auto& force_library_initialization = Library::get();
+
+/*******************************************************************************
+ * BENCHMARKING KERNELS
+ */
+
+static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }
+
+template <class Fixture, class ClientContextMutator, class ServerContextMutator>
+static void BM_UnaryPingPong(benchmark::State& state) {
+ EchoTestService::AsyncService service;
+ std::unique_ptr<Fixture> fixture(new Fixture(&service));
+ EchoRequest send_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ if (state.range(0) > 0) {
+ send_request.set_message(std::string(state.range(0), 'a'));
+ }
+ if (state.range(1) > 0) {
+ send_response.set_message(std::string(state.range(1), 'a'));
+ }
+ Status recv_status;
+ struct ServerEnv {
+ ServerContext ctx;
+ EchoRequest recv_request;
+ grpc::ServerAsyncResponseWriter<EchoResponse> response_writer;
+ ServerEnv() : response_writer(&ctx) {}
+ };
+ uint8_t server_env_buffer[2 * sizeof(ServerEnv)];
+ ServerEnv* server_env[2] = {
+ reinterpret_cast<ServerEnv*>(server_env_buffer),
+ reinterpret_cast<ServerEnv*>(server_env_buffer + sizeof(ServerEnv))};
+ new (server_env[0]) ServerEnv;
+ new (server_env[1]) ServerEnv;
+ service.RequestEcho(&server_env[0]->ctx, &server_env[0]->recv_request,
+ &server_env[0]->response_writer, fixture->cq(),
+ fixture->cq(), tag(0));
+ service.RequestEcho(&server_env[1]->ctx, &server_env[1]->recv_request,
+ &server_env[1]->response_writer, fixture->cq(),
+ fixture->cq(), tag(1));
+ std::unique_ptr<EchoTestService::Stub> stub(
+ EchoTestService::NewStub(fixture->channel()));
+ while (state.KeepRunning()) {
+ GPR_TIMER_SCOPE("BenchmarkCycle", 0);
+ recv_response.Clear();
+ ClientContext cli_ctx;
+ ClientContextMutator cli_ctx_mut(&cli_ctx);
+ std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+ stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
+ void* t;
+ bool ok;
+ 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];
+ 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);
+ int tagnum = (int)reinterpret_cast<intptr_t>(t);
+ GPR_ASSERT(i & (1 << tagnum));
+ i -= 1 << tagnum;
+ }
+ GPR_ASSERT(recv_status.ok());
+
+ senv->~ServerEnv();
+ senv = new (senv) ServerEnv();
+ service.RequestEcho(&senv->ctx, &senv->recv_request, &senv->response_writer,
+ fixture->cq(), fixture->cq(), tag(slot));
+ }
+ fixture->Finish(state);
+ fixture.reset();
+ server_env[0]->~ServerEnv();
+ server_env[1]->~ServerEnv();
+ state.SetBytesProcessed(state.range(0) * state.iterations() +
+ state.range(1) * state.iterations());
+}
+
+/*******************************************************************************
+ * CONFIGURATIONS
+ */
+
+static void SweepSizesArgs(benchmark::internal::Benchmark* b) {
+ b->Args({0, 0});
+ for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
+ b->Args({i, 0});
+ b->Args({0, i});
+ b->Args({i, i});
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator)
+ ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator)
+ ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
+ NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
+ NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
+ Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
+ ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
+ Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
+ ->Args({0, 0});
+
+} // namespace testing
+} // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_metadata.cc b/test/cpp/microbenchmarks/bm_metadata.cc
new file mode 100644
index 0000000000..34874b57f5
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_metadata.cc
@@ -0,0 +1,332 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test out various metadata handling primitives */
+
+#include <grpc/grpc.h>
+
+extern "C" {
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/transport.h"
+}
+
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+auto& force_library_initialization = Library::get();
+
+static void BM_SliceFromStatic(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(grpc_slice_from_static_string("abc"));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceFromStatic);
+
+static void BM_SliceFromCopied(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ grpc_slice_unref(grpc_slice_from_copied_string("abc"));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceFromCopied);
+
+static void BM_SliceFromStreamOwnedBuffer(benchmark::State& state) {
+ grpc_stream_refcount r;
+ GRPC_STREAM_REF_INIT(&r, 1, NULL, NULL, "test");
+ char buffer[64];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ grpc_slice_unref_internal(&exec_ctx, grpc_slice_from_stream_owned_buffer(
+ &r, buffer, sizeof(buffer)));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+BENCHMARK(BM_SliceFromStreamOwnedBuffer);
+
+static void BM_SliceIntern(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice slice = grpc_slice_from_static_string("abc");
+ while (state.KeepRunning()) {
+ grpc_slice_unref(grpc_slice_intern(slice));
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceIntern);
+
+static void BM_SliceReIntern(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice slice = grpc_slice_intern(grpc_slice_from_static_string("abc"));
+ while (state.KeepRunning()) {
+ grpc_slice_unref(grpc_slice_intern(slice));
+ }
+ grpc_slice_unref(slice);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceReIntern);
+
+static void BM_SliceInternStaticMetadata(benchmark::State& state) {
+ TrackCounters track_counters;
+ while (state.KeepRunning()) {
+ grpc_slice_intern(GRPC_MDSTR_GZIP);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceInternStaticMetadata);
+
+static void BM_SliceInternEqualToStaticMetadata(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice slice = grpc_slice_from_static_string("gzip");
+ while (state.KeepRunning()) {
+ grpc_slice_intern(slice);
+ }
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SliceInternEqualToStaticMetadata);
+
+static void BM_MetadataFromNonInternedSlices(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_from_static_string("key");
+ gpr_slice v = grpc_slice_from_static_string("value");
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromNonInternedSlices);
+
+static void BM_MetadataFromInternedSlices(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_intern(grpc_slice_from_static_string("value"));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ grpc_slice_unref(v);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromInternedSlices);
+
+static void BM_MetadataFromInternedSlicesAlreadyInIndex(
+ benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_intern(grpc_slice_from_static_string("value"));
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_mdelem seed = grpc_mdelem_create(&exec_ctx, k, v, NULL);
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ GRPC_MDELEM_UNREF(&exec_ctx, seed);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ grpc_slice_unref(v);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromInternedSlicesAlreadyInIndex);
+
+static void BM_MetadataFromInternedKey(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_from_static_string("value");
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromInternedKey);
+
+static void BM_MetadataFromNonInternedSlicesWithBackingStore(
+ benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_from_static_string("key");
+ gpr_slice v = grpc_slice_from_static_string("value");
+ char backing_store[sizeof(grpc_mdelem_data)];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(
+ &exec_ctx,
+ grpc_mdelem_create(&exec_ctx, k, v,
+ reinterpret_cast<grpc_mdelem_data*>(backing_store)));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromNonInternedSlicesWithBackingStore);
+
+static void BM_MetadataFromInternedSlicesWithBackingStore(
+ benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_intern(grpc_slice_from_static_string("value"));
+ char backing_store[sizeof(grpc_mdelem_data)];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(
+ &exec_ctx,
+ grpc_mdelem_create(&exec_ctx, k, v,
+ reinterpret_cast<grpc_mdelem_data*>(backing_store)));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ grpc_slice_unref(v);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromInternedSlicesWithBackingStore);
+
+static void BM_MetadataFromInternedKeyWithBackingStore(
+ benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_from_static_string("value");
+ char backing_store[sizeof(grpc_mdelem_data)];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(
+ &exec_ctx,
+ grpc_mdelem_create(&exec_ctx, k, v,
+ reinterpret_cast<grpc_mdelem_data*>(backing_store)));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromInternedKeyWithBackingStore);
+
+static void BM_MetadataFromStaticMetadataStrings(benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = GRPC_MDSTR_STATUS;
+ gpr_slice v = GRPC_MDSTR_200;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromStaticMetadataStrings);
+
+static void BM_MetadataFromStaticMetadataStringsNotIndexed(
+ benchmark::State& state) {
+ TrackCounters track_counters;
+ gpr_slice k = GRPC_MDSTR_STATUS;
+ gpr_slice v = GRPC_MDSTR_GZIP;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_create(&exec_ctx, k, v, NULL));
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_slice_unref(k);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataFromStaticMetadataStringsNotIndexed);
+
+static void BM_MetadataRefUnrefExternal(benchmark::State& state) {
+ TrackCounters track_counters;
+ char backing_store[sizeof(grpc_mdelem_data)];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_mdelem el =
+ grpc_mdelem_create(&exec_ctx, grpc_slice_from_static_string("a"),
+ grpc_slice_from_static_string("b"),
+ reinterpret_cast<grpc_mdelem_data*>(backing_store));
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, GRPC_MDELEM_REF(el));
+ }
+ GRPC_MDELEM_UNREF(&exec_ctx, el);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataRefUnrefExternal);
+
+static void BM_MetadataRefUnrefInterned(benchmark::State& state) {
+ TrackCounters track_counters;
+ char backing_store[sizeof(grpc_mdelem_data)];
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ gpr_slice k = grpc_slice_intern(grpc_slice_from_static_string("key"));
+ gpr_slice v = grpc_slice_intern(grpc_slice_from_static_string("value"));
+ grpc_mdelem el = grpc_mdelem_create(
+ &exec_ctx, k, v, reinterpret_cast<grpc_mdelem_data*>(backing_store));
+ grpc_slice_unref(k);
+ grpc_slice_unref(v);
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, GRPC_MDELEM_REF(el));
+ }
+ GRPC_MDELEM_UNREF(&exec_ctx, el);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataRefUnrefInterned);
+
+static void BM_MetadataRefUnrefAllocated(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_mdelem el =
+ grpc_mdelem_create(&exec_ctx, grpc_slice_from_static_string("a"),
+ grpc_slice_from_static_string("b"), NULL);
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, GRPC_MDELEM_REF(el));
+ }
+ GRPC_MDELEM_UNREF(&exec_ctx, el);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataRefUnrefAllocated);
+
+static void BM_MetadataRefUnrefStatic(benchmark::State& state) {
+ TrackCounters track_counters;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_mdelem el =
+ grpc_mdelem_create(&exec_ctx, GRPC_MDSTR_STATUS, GRPC_MDSTR_200, NULL);
+ while (state.KeepRunning()) {
+ GRPC_MDELEM_UNREF(&exec_ctx, GRPC_MDELEM_REF(el));
+ }
+ GRPC_MDELEM_UNREF(&exec_ctx, el);
+ grpc_exec_ctx_finish(&exec_ctx);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_MetadataRefUnrefStatic);
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_pollset.cc b/test/cpp/microbenchmarks/bm_pollset.cc
new file mode 100644
index 0000000000..0f3d3cef66
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_pollset.cc
@@ -0,0 +1,254 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test out pollset latencies */
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+extern "C" {
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/port.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+}
+
+#include "test/cpp/microbenchmarks/helpers.h"
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+#include <string.h>
+
+#ifdef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#endif
+
+auto& force_library_initialization = Library::get();
+
+static void shutdown_ps(grpc_exec_ctx* exec_ctx, void* ps, grpc_error* error) {
+ grpc_pollset_destroy(static_cast<grpc_pollset*>(ps));
+}
+
+static void BM_CreateDestroyPollset(benchmark::State& state) {
+ TrackCounters track_counters;
+ size_t ps_sz = grpc_pollset_size();
+ grpc_pollset* ps = static_cast<grpc_pollset*>(gpr_malloc(ps_sz));
+ gpr_mu* mu;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_closure shutdown_ps_closure;
+ grpc_closure_init(&shutdown_ps_closure, shutdown_ps, ps,
+ grpc_schedule_on_exec_ctx);
+ while (state.KeepRunning()) {
+ memset(ps, 0, ps_sz);
+ grpc_pollset_init(ps, &mu);
+ gpr_mu_lock(mu);
+ grpc_pollset_shutdown(&exec_ctx, ps, &shutdown_ps_closure);
+ gpr_mu_unlock(mu);
+ grpc_exec_ctx_flush(&exec_ctx);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ gpr_free(ps);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_CreateDestroyPollset);
+
+#ifdef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
+static void BM_PollEmptyPollset_SpeedOfLight(benchmark::State& state) {
+ // equivalent to BM_PollEmptyPollset, but just use the OS primitives to guage
+ // what the speed of light would be if we abstracted perfectly
+ TrackCounters track_counters;
+ int epfd = epoll_create1(0);
+ GPR_ASSERT(epfd != -1);
+ size_t nev = state.range(0);
+ size_t nfd = state.range(1);
+ epoll_event* ev = new epoll_event[nev];
+ std::vector<int> fds;
+ for (size_t i = 0; i < nfd; i++) {
+ fds.push_back(eventfd(0, 0));
+ epoll_event ev;
+ ev.events = EPOLLIN;
+ epoll_ctl(epfd, EPOLL_CTL_ADD, fds.back(), &ev);
+ }
+ while (state.KeepRunning()) {
+ epoll_wait(epfd, ev, nev, 0);
+ }
+ for (auto fd : fds) {
+ close(fd);
+ }
+ close(epfd);
+ delete[] ev;
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_PollEmptyPollset_SpeedOfLight)
+ ->Args({1, 0})
+ ->Args({1, 1})
+ ->Args({1, 10})
+ ->Args({1, 100})
+ ->Args({1, 1000})
+ ->Args({1, 10000})
+ ->Args({1, 100000})
+ ->Args({10, 1})
+ ->Args({100, 1})
+ ->Args({1000, 1});
+#endif
+
+static void BM_PollEmptyPollset(benchmark::State& state) {
+ TrackCounters track_counters;
+ size_t ps_sz = grpc_pollset_size();
+ grpc_pollset* ps = static_cast<grpc_pollset*>(gpr_zalloc(ps_sz));
+ gpr_mu* mu;
+ grpc_pollset_init(ps, &mu);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ gpr_timespec now = gpr_time_0(GPR_CLOCK_MONOTONIC);
+ gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+ gpr_mu_lock(mu);
+ while (state.KeepRunning()) {
+ grpc_pollset_worker* worker;
+ GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, &worker, now, deadline));
+ }
+ grpc_closure shutdown_ps_closure;
+ grpc_closure_init(&shutdown_ps_closure, shutdown_ps, ps,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(&exec_ctx, ps, &shutdown_ps_closure);
+ gpr_mu_unlock(mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+ gpr_free(ps);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_PollEmptyPollset);
+
+class Closure : public grpc_closure {
+ public:
+ virtual ~Closure() {}
+};
+
+template <class F>
+Closure* MakeClosure(F f, grpc_closure_scheduler* scheduler) {
+ struct C : public Closure {
+ C(F f, grpc_closure_scheduler* scheduler) : f_(f) {
+ grpc_closure_init(this, C::cbfn, this, scheduler);
+ }
+ static void cbfn(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
+ C* p = static_cast<C*>(arg);
+ p->f_();
+ }
+ F f_;
+ };
+ return new C(f, scheduler);
+}
+
+#ifdef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
+static void BM_SingleThreadPollOneFd_SpeedOfLight(benchmark::State& state) {
+ // equivalent to BM_PollEmptyPollset, but just use the OS primitives to guage
+ // what the speed of light would be if we abstracted perfectly
+ TrackCounters track_counters;
+ int epfd = epoll_create1(0);
+ GPR_ASSERT(epfd != -1);
+ epoll_event ev[100];
+ int fd = eventfd(0, EFD_NONBLOCK);
+ ev[0].events = EPOLLIN;
+ epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev[0]);
+ while (state.KeepRunning()) {
+ int err;
+ do {
+ err = eventfd_write(fd, 1);
+ } while (err < 0 && errno == EINTR);
+ GPR_ASSERT(err == 0);
+ do {
+ err = epoll_wait(epfd, ev, GPR_ARRAY_SIZE(ev), 0);
+ } while (err < 0 && errno == EINTR);
+ GPR_ASSERT(err == 1);
+ eventfd_t value;
+ do {
+ err = eventfd_read(fd, &value);
+ } while (err < 0 && errno == EINTR);
+ GPR_ASSERT(err == 0);
+ }
+ close(fd);
+ close(epfd);
+ track_counters.Finish(state);
+}
+BENCHMARK(BM_SingleThreadPollOneFd_SpeedOfLight);
+#endif
+
+static void BM_SingleThreadPollOneFd(benchmark::State& state) {
+ TrackCounters track_counters;
+ size_t ps_sz = grpc_pollset_size();
+ grpc_pollset* ps = static_cast<grpc_pollset*>(gpr_zalloc(ps_sz));
+ gpr_mu* mu;
+ grpc_pollset_init(ps, &mu);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ gpr_timespec now = gpr_time_0(GPR_CLOCK_MONOTONIC);
+ gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ grpc_wakeup_fd wakeup_fd;
+ GRPC_ERROR_UNREF(grpc_wakeup_fd_init(&wakeup_fd));
+ grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read");
+ grpc_pollset_add_fd(&exec_ctx, ps, wakeup);
+ bool done = false;
+ Closure* continue_closure = MakeClosure(
+ [&]() {
+ GRPC_ERROR_UNREF(grpc_wakeup_fd_consume_wakeup(&wakeup_fd));
+ if (!state.KeepRunning()) {
+ done = true;
+ return;
+ }
+ GRPC_ERROR_UNREF(grpc_wakeup_fd_wakeup(&wakeup_fd));
+ grpc_fd_notify_on_read(&exec_ctx, wakeup, continue_closure);
+ },
+ grpc_schedule_on_exec_ctx);
+ GRPC_ERROR_UNREF(grpc_wakeup_fd_wakeup(&wakeup_fd));
+ grpc_fd_notify_on_read(&exec_ctx, wakeup, continue_closure);
+ gpr_mu_lock(mu);
+ while (!done) {
+ grpc_pollset_worker* worker;
+ GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, &worker, now, deadline));
+ }
+ grpc_fd_orphan(&exec_ctx, wakeup, NULL, NULL, "done");
+ wakeup_fd.read_fd = 0;
+ grpc_closure shutdown_ps_closure;
+ grpc_closure_init(&shutdown_ps_closure, shutdown_ps, ps,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(&exec_ctx, ps, &shutdown_ps_closure);
+ gpr_mu_unlock(mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_wakeup_fd_destroy(&wakeup_fd);
+ gpr_free(ps);
+ track_counters.Finish(state);
+ delete continue_closure;
+}
+BENCHMARK(BM_SingleThreadPollOneFd);
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/fullstack_context_mutators.h b/test/cpp/microbenchmarks/fullstack_context_mutators.h
new file mode 100644
index 0000000000..676f9aa1cc
--- /dev/null
+++ b/test/cpp/microbenchmarks/fullstack_context_mutators.h
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_CONTEXT_MUTATORS_H
+#define TEST_CPP_MICROBENCHMARKS_FULLSTACK_CONTEXT_MUTATORS_H
+
+#include <grpc++/channel.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/security/credentials.h>
+#include <grpc++/security/server_credentials.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/support/log.h>
+
+#include "test/cpp/microbenchmarks/helpers.h"
+
+namespace grpc {
+namespace testing {
+
+/*******************************************************************************
+ * CONTEXT MUTATORS
+ */
+
+static const int kPregenerateKeyCount = 100000;
+
+template <class F>
+auto MakeVector(size_t length, F f) -> std::vector<decltype(f())> {
+ std::vector<decltype(f())> out;
+ out.reserve(length);
+ for (size_t i = 0; i < length; i++) {
+ out.push_back(f());
+ }
+ return out;
+}
+
+class NoOpMutator {
+ public:
+ template <class ContextType>
+ NoOpMutator(ContextType* context) {}
+};
+
+template <int length>
+class RandomBinaryMetadata {
+ public:
+ static const grpc::string& Key() { return kKey; }
+
+ static const grpc::string& Value() {
+ return kValues[rand() % kValues.size()];
+ }
+
+ private:
+ static const grpc::string kKey;
+ static const std::vector<grpc::string> kValues;
+
+ static grpc::string GenerateOneString() {
+ grpc::string s;
+ s.reserve(length + 1);
+ for (int i = 0; i < length; i++) {
+ s += (char)rand();
+ }
+ return s;
+ }
+};
+
+template <int length>
+class RandomAsciiMetadata {
+ public:
+ static const grpc::string& Key() { return kKey; }
+
+ static const grpc::string& Value() {
+ return kValues[rand() % kValues.size()];
+ }
+
+ private:
+ static const grpc::string kKey;
+ static const std::vector<grpc::string> kValues;
+
+ static grpc::string GenerateOneString() {
+ grpc::string s;
+ s.reserve(length + 1);
+ for (int i = 0; i < length; i++) {
+ s += (char)(rand() % 26 + 'a');
+ }
+ return s;
+ }
+};
+
+template <class Generator, int kNumKeys>
+class Client_AddMetadata : public NoOpMutator {
+ public:
+ Client_AddMetadata(ClientContext* context) : NoOpMutator(context) {
+ for (int i = 0; i < kNumKeys; i++) {
+ context->AddMetadata(Generator::Key(), Generator::Value());
+ }
+ }
+};
+
+template <class Generator, int kNumKeys>
+class Server_AddInitialMetadata : public NoOpMutator {
+ public:
+ Server_AddInitialMetadata(ServerContext* context) : NoOpMutator(context) {
+ for (int i = 0; i < kNumKeys; i++) {
+ context->AddInitialMetadata(Generator::Key(), Generator::Value());
+ }
+ }
+};
+
+// static initialization
+
+template <int length>
+const grpc::string RandomBinaryMetadata<length>::kKey = "foo-bin";
+
+template <int length>
+const std::vector<grpc::string> RandomBinaryMetadata<length>::kValues =
+ MakeVector(kPregenerateKeyCount, GenerateOneString);
+
+template <int length>
+const grpc::string RandomAsciiMetadata<length>::kKey = "foo";
+
+template <int length>
+const std::vector<grpc::string> RandomAsciiMetadata<length>::kValues =
+ MakeVector(kPregenerateKeyCount, GenerateOneString);
+
+} // namespace testing
+} // namespace grpc
+
+#endif
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
new file mode 100644
index 0000000000..dc29701059
--- /dev/null
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -0,0 +1,244 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
+#define TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
+
+#include <grpc++/channel.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/security/credentials.h>
+#include <grpc++/security/server_credentials.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc/support/log.h>
+
+extern "C" {
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/util/passthru_endpoint.h"
+#include "test/core/util/port.h"
+}
+
+#include "test/cpp/microbenchmarks/helpers.h"
+
+namespace grpc {
+namespace testing {
+
+static void ApplyCommonServerBuilderConfig(ServerBuilder* b) {
+ b->SetMaxReceiveMessageSize(INT_MAX);
+ b->SetMaxSendMessageSize(INT_MAX);
+}
+
+static void ApplyCommonChannelArguments(ChannelArguments* c) {
+ c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
+ c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
+}
+
+class BaseFixture : public TrackCounters {};
+
+class FullstackFixture : public BaseFixture {
+ public:
+ FullstackFixture(Service* service, const grpc::string& address) {
+ ServerBuilder b;
+ b.AddListeningPort(address, InsecureServerCredentials());
+ cq_ = b.AddCompletionQueue(true);
+ b.RegisterService(service);
+ ApplyCommonServerBuilderConfig(&b);
+ server_ = b.BuildAndStart();
+ ChannelArguments args;
+ ApplyCommonChannelArguments(&args);
+ channel_ = CreateCustomChannel(address, InsecureChannelCredentials(), args);
+ }
+
+ virtual ~FullstackFixture() {
+ server_->Shutdown();
+ cq_->Shutdown();
+ void* tag;
+ bool ok;
+ while (cq_->Next(&tag, &ok)) {
+ }
+ }
+
+ ServerCompletionQueue* cq() { return cq_.get(); }
+ std::shared_ptr<Channel> channel() { return channel_; }
+
+ private:
+ std::unique_ptr<Server> server_;
+ std::unique_ptr<ServerCompletionQueue> cq_;
+ std::shared_ptr<Channel> channel_;
+};
+
+class TCP : public FullstackFixture {
+ public:
+ TCP(Service* service) : FullstackFixture(service, MakeAddress()) {}
+
+ private:
+ static grpc::string MakeAddress() {
+ int port = grpc_pick_unused_port_or_die();
+ std::stringstream addr;
+ addr << "localhost:" << port;
+ return addr.str();
+ }
+};
+
+class UDS : public FullstackFixture {
+ public:
+ UDS(Service* service) : FullstackFixture(service, MakeAddress()) {}
+
+ private:
+ static grpc::string MakeAddress() {
+ int port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
+ // real port
+ std::stringstream addr;
+ addr << "unix:/tmp/bm_fullstack." << port;
+ return addr.str();
+ }
+};
+
+class EndpointPairFixture : public BaseFixture {
+ public:
+ EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints)
+ : endpoint_pair_(endpoints) {
+ ServerBuilder b;
+ cq_ = b.AddCompletionQueue(true);
+ b.RegisterService(service);
+ ApplyCommonServerBuilderConfig(&b);
+ server_ = b.BuildAndStart();
+
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ /* add server endpoint to server_
+ * */
+ {
+ const grpc_channel_args* server_args =
+ grpc_server_get_channel_args(server_->c_server());
+ server_transport_ = grpc_create_chttp2_transport(
+ &exec_ctx, server_args, endpoints.server, 0 /* is_client */);
+
+ grpc_pollset** pollsets;
+ size_t num_pollsets = 0;
+ grpc_server_get_pollsets(server_->c_server(), &pollsets, &num_pollsets);
+
+ for (size_t i = 0; i < num_pollsets; i++) {
+ grpc_endpoint_add_to_pollset(&exec_ctx, endpoints.server, pollsets[i]);
+ }
+
+ grpc_server_setup_transport(&exec_ctx, server_->c_server(),
+ server_transport_, NULL, server_args);
+ grpc_chttp2_transport_start_reading(&exec_ctx, server_transport_, NULL);
+ }
+
+ /* create channel */
+ {
+ ChannelArguments args;
+ args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
+ ApplyCommonChannelArguments(&args);
+
+ grpc_channel_args c_args = args.c_channel_args();
+ client_transport_ =
+ grpc_create_chttp2_transport(&exec_ctx, &c_args, endpoints.client, 1);
+ GPR_ASSERT(client_transport_);
+ grpc_channel* channel =
+ grpc_channel_create(&exec_ctx, "target", &c_args,
+ GRPC_CLIENT_DIRECT_CHANNEL, client_transport_);
+ grpc_chttp2_transport_start_reading(&exec_ctx, client_transport_, NULL);
+
+ channel_ = CreateChannelInternal("", channel);
+ }
+
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+
+ virtual ~EndpointPairFixture() {
+ server_->Shutdown();
+ cq_->Shutdown();
+ void* tag;
+ bool ok;
+ while (cq_->Next(&tag, &ok)) {
+ }
+ }
+
+ ServerCompletionQueue* cq() { return cq_.get(); }
+ std::shared_ptr<Channel> channel() { return channel_; }
+
+ protected:
+ grpc_endpoint_pair endpoint_pair_;
+ grpc_transport* client_transport_;
+ grpc_transport* server_transport_;
+
+ private:
+ std::unique_ptr<Server> server_;
+ std::unique_ptr<ServerCompletionQueue> cq_;
+ std::shared_ptr<Channel> channel_;
+};
+
+class SockPair : public EndpointPairFixture {
+ public:
+ SockPair(Service* service)
+ : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
+ "test", Library::get().rq(), 8192)) {}
+};
+
+class InProcessCHTTP2 : public EndpointPairFixture {
+ public:
+ InProcessCHTTP2(Service* service)
+ : EndpointPairFixture(service, MakeEndpoints()) {}
+
+ void AddToLabel(std::ostream& out, benchmark::State& state) {
+ EndpointPairFixture::AddToLabel(out, state);
+ out << " writes/iter:"
+ << ((double)stats_.num_writes / (double)state.iterations());
+ }
+
+ private:
+ grpc_passthru_endpoint_stats stats_;
+
+ grpc_endpoint_pair MakeEndpoints() {
+ grpc_endpoint_pair p;
+ grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(),
+ &stats_);
+ return p;
+ }
+};
+
+} // namespace testing
+} // namespace grpc
+
+#endif
diff --git a/test/cpp/qps/qps_test_with_poll.cc b/test/cpp/microbenchmarks/helpers.cc
index c64e6c9d49..d277c5984c 100644
--- a/test/cpp/qps/qps_test_with_poll.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,55 +31,35 @@
*
*/
-#include <set>
+#include "test/cpp/microbenchmarks/helpers.h"
-#include <grpc/support/log.h>
-
-#include "test/cpp/qps/driver.h"
-#include "test/cpp/qps/report.h"
-#include "test/cpp/util/benchmark_config.h"
-
-extern "C" {
-#include "src/core/lib/iomgr/pollset_posix.h"
-}
-
-namespace grpc {
-namespace testing {
-
-static const int WARMUP = 5;
-static const int BENCHMARK = 5;
-
-static void RunQPS() {
- gpr_log(GPR_INFO, "Running QPS test");
-
- ClientConfig client_config;
- client_config.set_client_type(ASYNC_CLIENT);
- client_config.set_outstanding_rpcs_per_channel(1000);
- client_config.set_client_channels(8);
- client_config.set_async_client_threads(8);
- client_config.set_rpc_type(UNARY);
- client_config.mutable_load_params()->mutable_closed_loop();
-
- ServerConfig server_config;
- server_config.set_server_type(ASYNC_SERVER);
- server_config.set_async_server_threads(4);
-
- const auto result =
- RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
-
- GetReporter()->ReportQPSPerCore(*result);
- GetReporter()->ReportLatency(*result);
+void TrackCounters::Finish(benchmark::State &state) {
+ std::ostringstream out;
+ AddToLabel(out, state);
+ auto label = out.str();
+ if (label.length() && label[0] == ' ') {
+ label = label.substr(1);
+ }
+ state.SetLabel(label);
}
-} // namespace testing
-} // namespace grpc
-
-int main(int argc, char** argv) {
- grpc::testing::InitBenchmark(&argc, &argv, true);
-
- grpc_platform_become_multipoller = grpc_poll_become_multipoller;
-
- grpc::testing::RunQPS();
-
- return 0;
+void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) {
+#ifdef GPR_LOW_LEVEL_COUNTERS
+ grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
+ out << " locks/iter:" << ((double)(gpr_atm_no_barrier_load(&gpr_mu_locks) -
+ mu_locks_at_start_) /
+ (double)state.iterations())
+ << " atm_cas/iter:"
+ << ((double)(gpr_atm_no_barrier_load(&gpr_counter_atm_cas) -
+ atm_cas_at_start_) /
+ (double)state.iterations())
+ << " atm_add/iter:"
+ << ((double)(gpr_atm_no_barrier_load(&gpr_counter_atm_add) -
+ atm_add_at_start_) /
+ (double)state.iterations())
+ << " allocs/iter:"
+ << ((double)(counters_at_end.total_allocs_absolute -
+ counters_at_start_.total_allocs_absolute) /
+ (double)state.iterations());
+#endif
}
diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h
new file mode 100644
index 0000000000..f44b7cf83a
--- /dev/null
+++ b/test/cpp/microbenchmarks/helpers.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TEST_CPP_MICROBENCHMARKS_COUNTERS_H
+#define TEST_CPP_MICROBENCHMARKS_COUNTERS_H
+
+#include <sstream>
+
+extern "C" {
+#include <grpc/support/port_platform.h>
+#include "test/core/util/memory_counters.h"
+}
+
+#include <grpc++/impl/grpc_library.h>
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+class Library {
+ public:
+ static Library& get() {
+ static Library lib;
+ return lib;
+ }
+
+ grpc_resource_quota* rq() { return rq_; }
+
+ private:
+ Library() {
+#ifdef GPR_LOW_LEVEL_COUNTERS
+ grpc_memory_counters_init();
+#endif
+ init_lib_.init();
+ rq_ = grpc_resource_quota_create("bm");
+ }
+
+ ~Library() { init_lib_.shutdown(); }
+
+ grpc::internal::GrpcLibrary init_lib_;
+ grpc_resource_quota* rq_;
+};
+
+#ifdef GPR_LOW_LEVEL_COUNTERS
+extern "C" gpr_atm gpr_mu_locks;
+extern "C" gpr_atm gpr_counter_atm_cas;
+extern "C" gpr_atm gpr_counter_atm_add;
+#endif
+
+class TrackCounters {
+ public:
+ virtual void Finish(benchmark::State& state);
+ virtual void AddToLabel(std::ostream& out, benchmark::State& state);
+
+ private:
+#ifdef GPR_LOW_LEVEL_COUNTERS
+ const size_t mu_locks_at_start_ = gpr_atm_no_barrier_load(&gpr_mu_locks);
+ const size_t atm_cas_at_start_ =
+ gpr_atm_no_barrier_load(&gpr_counter_atm_cas);
+ const size_t atm_add_at_start_ =
+ gpr_atm_no_barrier_load(&gpr_counter_atm_add);
+ grpc_memory_counters counters_at_start_ = grpc_memory_counters_snapshot();
+#endif
+};
+
+#endif
diff --git a/test/cpp/microbenchmarks/representative_server_initial_metadata.headers b/test/cpp/microbenchmarks/representative_server_initial_metadata.headers
new file mode 100644
index 0000000000..d3e6933366
--- /dev/null
+++ b/test/cpp/microbenchmarks/representative_server_initial_metadata.headers
@@ -0,0 +1,4 @@
+:status: 200
+content-type: application/grpc
+grpc-accept-encoding: identity,deflate,gzip
+
diff --git a/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers b/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
new file mode 100644
index 0000000000..544d089853
--- /dev/null
+++ b/test/cpp/microbenchmarks/representative_server_trailing_metadata.headers
@@ -0,0 +1,3 @@
+grpc-status: 0
+grpc-message:
+
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 4032039ea1..396d308e2a 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -112,7 +112,9 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
next_state_ = State::RESP_DONE;
return true;
case State::RESP_DONE:
- entry->set_value((UsageTimer::Now() - start_) * 1e9);
+ if (status_.ok()) {
+ entry->set_value((UsageTimer::Now() - start_) * 1e9);
+ }
callback_(status_, &response_, entry);
next_state_ = State::INVALID;
return false;
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 498416c64a..a944c45496 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -129,7 +129,9 @@ class SynchronousUnaryClient final : public SynchronousClient {
grpc::ClientContext context;
grpc::Status s =
stub->UnaryCall(&context, request_, &responses_[thread_idx]);
- entry->set_value((UsageTimer::Now() - start) * 1e9);
+ if (s.ok()) {
+ entry->set_value((UsageTimer::Now() - start) * 1e9);
+ }
entry->set_status(s.error_code());
return true;
}
@@ -154,7 +156,7 @@ class SynchronousStreamingClient final : public SynchronousClient {
(*stream)->WritesDone();
Status s = (*stream)->Finish();
if (!s.ok()) {
- gpr_log(GPR_ERROR, "Stream %zu received an error %s", i,
+ gpr_log(GPR_ERROR, "Stream %" PRIuPTR " received an error %s", i,
s.error_message().c_str());
}
}
@@ -170,8 +172,17 @@ class SynchronousStreamingClient final : public SynchronousClient {
if (stream_[thread_idx]->Write(request_) &&
stream_[thread_idx]->Read(&responses_[thread_idx])) {
entry->set_value((UsageTimer::Now() - start) * 1e9);
+ // don't set the status since there isn't one yet
return true;
}
+ stream_[thread_idx]->WritesDone();
+ Status s = stream_[thread_idx]->Finish();
+ // don't set the value since the stream is failed and shouldn't be timed
+ entry->set_status(s.error_code());
+ if (!s.ok()) {
+ gpr_log(GPR_ERROR, "Stream %" PRIuPTR " received an error %s", thread_idx,
+ s.error_message().c_str());
+ }
auto* stub = channels_[thread_idx % channels_.size()].get_stub();
context_[thread_idx].~ClientContext();
new (&context_[thread_idx]) ClientContext();
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index 8076a4a6b9..f79284d225 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -74,7 +74,9 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service {
return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
}
}
- stream->Write(response);
+ if (!stream->Write(response)) {
+ return Status(StatusCode::INTERNAL, "Server couldn't respond");
+ }
}
return Status::OK;
}
diff --git a/test/cpp/server/server_builder_test.cc b/test/cpp/server/server_builder_test.cc
new file mode 100644
index 0000000000..1d9eda17b4
--- /dev/null
+++ b/test/cpp/server/server_builder_test.cc
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/impl/codegen/config.h>
+#include <gtest/gtest.h>
+
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+
+namespace grpc {
+namespace {
+
+testing::EchoTestService::Service g_service;
+
+grpc::string MakePort() {
+ std::ostringstream s;
+ int p = grpc_pick_unused_port_or_die();
+ s << "localhost:" << p;
+ return s.str();
+}
+
+grpc::string g_port = MakePort();
+
+TEST(ServerBuilderTest, NoOp) { ServerBuilder b; }
+
+TEST(ServerBuilderTest, CreateServerNoPorts) {
+ ServerBuilder().RegisterService(&g_service).BuildAndStart()->Shutdown();
+}
+
+TEST(ServerBuilderTest, CreateServerOnePort) {
+ ServerBuilder()
+ .RegisterService(&g_service)
+ .AddListeningPort(g_port, InsecureServerCredentials())
+ .BuildAndStart()
+ ->Shutdown();
+}
+
+TEST(ServerBuilderTest, CreateServerRepeatedPort) {
+ ServerBuilder()
+ .RegisterService(&g_service)
+ .AddListeningPort(g_port, InsecureServerCredentials())
+ .AddListeningPort(g_port, InsecureServerCredentials())
+ .BuildAndStart()
+ ->Shutdown();
+}
+
+TEST(ServerBuilderTest, CreateServerRepeatedPortWithDisallowedReusePort) {
+ EXPECT_EQ(ServerBuilder()
+ .RegisterService(&g_service)
+ .AddListeningPort(g_port, InsecureServerCredentials())
+ .AddListeningPort(g_port, InsecureServerCredentials())
+ .AddChannelArgument(GRPC_ARG_ALLOW_REUSEPORT, 0)
+ .BuildAndStart(),
+ nullptr);
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
new file mode 100644
index 0000000000..dc90a4e172
--- /dev/null
+++ b/test/cpp/util/BUILD
@@ -0,0 +1,85 @@
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+licenses(["notice"]) # 3-clause BSD
+
+cc_library(
+ name = "test_config",
+ srcs = [
+ "test_config_cc.cc",
+ ],
+ hdrs = [
+ "test_config.h",
+ ],
+ visibility = ["//test:__subpackages__"],
+ deps = [
+ "//:gpr",
+ "//external:gflags",
+ ],
+)
+
+cc_library(
+ name = "grpc++_proto_reflection_desc_db",
+ srcs = [
+ "proto_reflection_descriptor_database.cc",
+ ],
+ hdrs = [
+ "proto_reflection_descriptor_database.h",
+ ],
+ visibility = ["//test:__subpackages__"],
+ deps = [
+ "//:grpc++_config_proto",
+ "//src/proto/grpc/reflection/v1alpha:reflection_proto",
+ ],
+)
+
+cc_library(
+ name = "test_util",
+ srcs = [
+ # "test/cpp/end2end/test_service_impl.cc",
+ "byte_buffer_proto_helper.cc",
+ "create_test_channel.cc",
+ "string_ref_helper.cc",
+ "subprocess.cc",
+ "test_credentials_provider.cc",
+ ],
+ hdrs = [
+ "byte_buffer_proto_helper.h",
+ "create_test_channel.h",
+ "string_ref_helper.h",
+ "subprocess.h",
+ "test_credentials_provider.h",
+ ],
+ visibility = ["//test:__subpackages__"],
+ deps = [
+ "//:grpc++",
+ "//test/core/end2end:ssl_test_data",
+ "//test/core/util:gpr_test_util",
+ ],
+)