diff options
Diffstat (limited to 'test')
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 Binary files differnew file mode 100644 index 0000000000..70ca3a336e --- /dev/null +++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960 diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296 Binary files differnew file mode 100644 index 0000000000..65cc6a2209 --- /dev/null +++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296 diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448 Binary files differnew file mode 100644 index 0000000000..49c02c2f12 --- /dev/null +++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448 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", + ], +) |