diff options
Diffstat (limited to 'test')
110 files changed, 4728 insertions, 1466 deletions
diff --git a/test/core/bad_client/BUILD b/test/core/bad_client/BUILD index 8cc9dfa77a..99593dc5f3 100644 --- a/test/core/bad_client/BUILD +++ b/test/core/bad_client/BUILD @@ -12,14 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/bad_client") licenses(["notice"]) # Apache v2 diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c index c3964ca84b..383d1240cb 100644 --- a/test/core/bad_client/bad_client.c +++ b/test/core/bad_client/bad_client.c @@ -45,18 +45,18 @@ typedef struct { } thd_args; static void thd_func(void *arg) { - thd_args *a = arg; + thd_args *a = (thd_args *)arg; a->validator(a->server, a->cq, a->registered_method); gpr_event_set(&a->done_thd, (void *)1); } static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - thd_args *a = arg; + thd_args *a = (thd_args *)arg; gpr_event_set(&a->done_write, (void *)1); } static void server_setup_transport(void *ts, grpc_transport *transport) { - thd_args *a = ts; + thd_args *a = (thd_args *)ts; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_server_setup_transport(&exec_ctx, a->server, transport, NULL, grpc_server_get_channel_args(a->server)); @@ -64,7 +64,7 @@ static void server_setup_transport(void *ts, grpc_transport *transport) { } static void read_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - gpr_event *read_done = arg; + gpr_event *read_done = (gpr_event *)arg; gpr_event_set(read_done, (void *)1); } diff --git a/test/core/bad_ssl/BUILD b/test/core/bad_ssl/BUILD index e13d43258a..0ea1520213 100644 --- a/test/core/bad_ssl/BUILD +++ b/test/core/bad_ssl/BUILD @@ -12,14 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/bad_ssl") licenses(["notice"]) # Apache v2 diff --git a/test/core/census/BUILD b/test/core/census/BUILD index 988d9a813a..24fd2807d0 100644 --- a/test/core/census/BUILD +++ b/test/core/census/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/census") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 grpc_cc_test( name = "context_test", diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD index 18dd112eb7..5ac77c449b 100644 --- a/test/core/channel/BUILD +++ b/test/core/channel/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/channel") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 grpc_cc_test( name = "channel_args_test", @@ -46,3 +41,15 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "channel_stack_builder_test", + srcs = ["channel_stack_builder_test.c"], + language = "C", + deps = [ + "//:gpr", + "//:grpc", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + ], +) diff --git a/test/core/channel/channel_stack_builder_test.c b/test/core/channel/channel_stack_builder_test.c new file mode 100644 index 0000000000..682efd1438 --- /dev/null +++ b/test/core/channel/channel_stack_builder_test.c @@ -0,0 +1,146 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/channel/channel_stack_builder.h" + +#include <limits.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> + +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/channel_init.h" +#include "test/core/util/test_config.h" + +static grpc_error *channel_init_func(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + return GRPC_ERROR_NONE; +} + +static grpc_error *call_init_func(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + return GRPC_ERROR_NONE; +} + +static void channel_destroy_func(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +static void call_destroy_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *ignored) {} + +static void call_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) {} + +static void channel_func(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_transport_op *op) { + if (op->disconnect_with_error != GRPC_ERROR_NONE) { + GRPC_ERROR_UNREF(op->disconnect_with_error); + } + GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); +} + +bool g_replacement_fn_called = false; +bool g_original_fn_called = false; +void set_arg_once_fn(grpc_channel_stack *channel_stack, + grpc_channel_element *elem, void *arg) { + bool *called = arg; + // Make sure this function is only called once per arg. + GPR_ASSERT(*called == false); + *called = true; +} + +static void test_channel_stack_builder_filter_replace(void) { + grpc_channel *channel = + grpc_insecure_channel_create("target name isn't used", NULL, NULL); + GPR_ASSERT(channel != NULL); + // Make sure the high priority filter has been created. + GPR_ASSERT(g_replacement_fn_called); + // ... and that the low priority one hasn't. + GPR_ASSERT(!g_original_fn_called); + grpc_channel_destroy(channel); +} + +const grpc_channel_filter replacement_filter = { + call_func, + channel_func, + 0, + call_init_func, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + call_destroy_func, + 0, + channel_init_func, + channel_destroy_func, + grpc_channel_next_get_info, + "filter_name"}; + +const grpc_channel_filter original_filter = { + call_func, + channel_func, + 0, + call_init_func, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + call_destroy_func, + 0, + channel_init_func, + channel_destroy_func, + grpc_channel_next_get_info, + "filter_name"}; + +static bool add_replacement_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *arg) { + const grpc_channel_filter *filter = arg; + // Get rid of any other version of the filter, as determined by having the + // same name. + GPR_ASSERT(grpc_channel_stack_builder_remove_filter(builder, filter->name)); + return grpc_channel_stack_builder_prepend_filter( + builder, filter, set_arg_once_fn, &g_replacement_fn_called); +} + +static bool add_original_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *arg) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, set_arg_once_fn, + &g_original_fn_called); +} + +static void init_plugin(void) { + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, + add_original_filter, + (void *)&original_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, + add_replacement_filter, + (void *)&replacement_filter); +} + +static void destroy_plugin(void) {} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_register_plugin(init_plugin, destroy_plugin); + grpc_init(); + test_channel_stack_builder_filter_replace(); + grpc_shutdown(); + return 0; +} diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index 0c4bae6ded..7c3614b4a2 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -67,10 +67,6 @@ static void channel_func(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, ++*(int *)(elem->channel_data); } -static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - return gpr_strdup("peer"); -} - static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_channel_stack_destroy(exec_ctx, arg); @@ -93,7 +89,6 @@ static void test_create_channel_stack(void) { sizeof(int), channel_init_func, channel_destroy_func, - get_peer, grpc_channel_next_get_info, "some_test_filter"}; const grpc_channel_filter *filters = &filter; diff --git a/test/core/channel/minimal_stack_is_minimal_test.c b/test/core/channel/minimal_stack_is_minimal_test.c index c99b54c6ac..b4528346f7 100644 --- a/test/core/channel/minimal_stack_is_minimal_test.c +++ b/test/core/channel/minimal_stack_is_minimal_test.c @@ -89,14 +89,14 @@ int main(int argc, char **argv) { "connected", NULL); errors += CHECK_STACK("unknown", NULL, GRPC_SERVER_CHANNEL, "server", "message_size", "deadline", "connected", NULL); - errors += - CHECK_STACK("chttp2", NULL, GRPC_CLIENT_DIRECT_CHANNEL, "message_size", - "deadline", "http-client", "compress", "connected", NULL); + errors += CHECK_STACK("chttp2", NULL, GRPC_CLIENT_DIRECT_CHANNEL, + "message_size", "deadline", "http-client", + "message_compress", "connected", NULL); errors += CHECK_STACK("chttp2", NULL, GRPC_CLIENT_SUBCHANNEL, "message_size", - "http-client", "compress", "connected", NULL); - errors += - CHECK_STACK("chttp2", NULL, GRPC_SERVER_CHANNEL, "server", "message_size", - "deadline", "http-server", "compress", "connected", NULL); + "http-client", "message_compress", "connected", NULL); + errors += CHECK_STACK("chttp2", NULL, GRPC_SERVER_CHANNEL, "server", + "message_size", "deadline", "http-server", + "message_compress", "connected", NULL); errors += CHECK_STACK(NULL, NULL, GRPC_CLIENT_CHANNEL, "client-channel", NULL); diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD index 7fc5b977a9..c4a93238f2 100644 --- a/test/core/client_channel/BUILD +++ b/test/core/client_channel/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/client_channel") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD index 8af4a2d5f0..0907e06623 100644 --- a/test/core/client_channel/resolvers/BUILD +++ b/test/core/client_channel/resolvers/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/client_channel_resolvers") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 grpc_cc_test( name = "dns_resolver_connectivity_test", diff --git a/test/core/compression/BUILD b/test/core/compression/BUILD index e4432b3b9d..1ab6e35f0d 100644 --- a/test/core/compression/BUILD +++ b/test/core/compression/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/compression") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 grpc_cc_test( name = "algorithm_test", diff --git a/test/core/debug/stats_test.cc b/test/core/debug/stats_test.cc new file mode 100644 index 0000000000..c85ab3598a --- /dev/null +++ b/test/core/debug/stats_test.cc @@ -0,0 +1,123 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +extern "C" { +#include "src/core/lib/debug/stats.h" +} + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <gtest/gtest.h> + +namespace grpc { +namespace testing { + +class Snapshot { + public: + Snapshot() { grpc_stats_collect(&begin_); } + + grpc_stats_data delta() { + grpc_stats_data now; + grpc_stats_collect(&now); + grpc_stats_data delta; + grpc_stats_diff(&now, &begin_, &delta); + return delta; + } + + private: + grpc_stats_data begin_; +}; + +TEST(StatsTest, IncCounters) { + for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) { + Snapshot snapshot; + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_STATS_INC_COUNTER(&exec_ctx, (grpc_stats_counters)i); + grpc_exec_ctx_finish(&exec_ctx); + + EXPECT_EQ(snapshot.delta().counters[i], 1); + } +} + +TEST(StatsTest, IncSpecificCounter) { + Snapshot snapshot; + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_STATS_INC_SYSCALL_POLL(&exec_ctx); + grpc_exec_ctx_finish(&exec_ctx); + + EXPECT_EQ(snapshot.delta().counters[GRPC_STATS_COUNTER_SYSCALL_POLL], 1); +} + +static int FindExpectedBucket(int i, int j) { + if (j < 0) { + return 0; + } + if (j >= grpc_stats_histo_bucket_boundaries[i][grpc_stats_histo_buckets[i]]) { + return grpc_stats_histo_buckets[i] - 1; + } + return std::upper_bound(grpc_stats_histo_bucket_boundaries[i], + grpc_stats_histo_bucket_boundaries[i] + + grpc_stats_histo_buckets[i], + j) - + grpc_stats_histo_bucket_boundaries[i] - 1; +} + +TEST(StatsTest, IncHistogram) { + for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) { + std::vector<int> test_values; + for (int j = -1000; + j < + grpc_stats_histo_bucket_boundaries[i] + [grpc_stats_histo_buckets[i] - 1] + + 1000; + j++) { + test_values.push_back(j); + } + std::random_shuffle(test_values.begin(), test_values.end()); + if (test_values.size() > 10000) { + test_values.resize(10000); + } + for (auto j : test_values) { + Snapshot snapshot; + + int expected_bucket = FindExpectedBucket(i, j); + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_stats_inc_histogram[i](&exec_ctx, j); + grpc_exec_ctx_finish(&exec_ctx); + + auto delta = snapshot.delta(); + + EXPECT_EQ(delta.histograms[grpc_stats_histo_start[i] + expected_bucket], + 1); + } + } +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc_init(); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; +} diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index 9e788bf7e5..49bfc43646 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/end2end") load(":generate_tests.bzl", "grpc_end2end_tests") diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c index 5f89058c45..eeabc769d3 100644 --- a/test/core/end2end/bad_server_response_test.c +++ b/test/core/end2end/bad_server_response_test.c @@ -136,7 +136,7 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, grpc_pollset *accepting_pollset, grpc_tcp_server_acceptor *acceptor) { gpr_free(acceptor); - test_tcp_server *server = arg; + test_tcp_server *server = (test_tcp_server *)arg; GRPC_CLOSURE_INIT(&on_read, handle_read, NULL, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_INIT(&on_write, done_write, NULL, grpc_schedule_on_exec_ctx); grpc_slice_buffer_init(&state.temp_incoming_buffer); @@ -237,7 +237,7 @@ typedef struct { } poll_args; static void actually_poll_server(void *arg) { - poll_args *pa = arg; + poll_args *pa = (poll_args *)arg; gpr_timespec deadline = n_sec_deadline(10); while (true) { bool done = gpr_atm_acq_load(&state.done_atm) != 0; @@ -259,7 +259,7 @@ static void poll_server_until_read_done(test_tcp_server *server, gpr_atm_rel_store(&state.done_atm, 0); state.write_done = 0; gpr_thd_id id; - poll_args *pa = gpr_malloc(sizeof(*pa)); + poll_args *pa = (poll_args *)gpr_malloc(sizeof(*pa)); pa->server = server; pa->signal_when_done = signal_when_done; gpr_thd_new(&id, actually_poll_server, pa, NULL); diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c index 6a061a4e2d..3236feea56 100644 --- a/test/core/end2end/end2end_nosec_tests.c +++ b/test/core/end2end/end2end_nosec_tests.c @@ -130,6 +130,12 @@ extern void simple_metadata(grpc_end2end_test_config config); extern void simple_metadata_pre_init(void); extern void simple_request(grpc_end2end_test_config config); extern void simple_request_pre_init(void); +extern void stream_compression_compressed_payload(grpc_end2end_test_config config); +extern void stream_compression_compressed_payload_pre_init(void); +extern void stream_compression_payload(grpc_end2end_test_config config); +extern void stream_compression_payload_pre_init(void); +extern void stream_compression_ping_pong_streaming(grpc_end2end_test_config config); +extern void stream_compression_ping_pong_streaming_pre_init(void); extern void streaming_error_response(grpc_end2end_test_config config); extern void streaming_error_response_pre_init(void); extern void trailing_metadata(grpc_end2end_test_config config); @@ -195,6 +201,9 @@ void grpc_end2end_tests_pre_init(void) { simple_delayed_request_pre_init(); simple_metadata_pre_init(); simple_request_pre_init(); + stream_compression_compressed_payload_pre_init(); + stream_compression_payload_pre_init(); + stream_compression_ping_pong_streaming_pre_init(); streaming_error_response_pre_init(); trailing_metadata_pre_init(); workaround_cronet_compression_pre_init(); @@ -259,6 +268,9 @@ void grpc_end2end_tests(int argc, char **argv, simple_delayed_request(config); simple_metadata(config); simple_request(config); + stream_compression_compressed_payload(config); + stream_compression_payload(config); + stream_compression_ping_pong_streaming(config); streaming_error_response(config); trailing_metadata(config); workaround_cronet_compression(config); @@ -468,6 +480,18 @@ void grpc_end2end_tests(int argc, char **argv, simple_request(config); continue; } + if (0 == strcmp("stream_compression_compressed_payload", argv[i])) { + stream_compression_compressed_payload(config); + continue; + } + if (0 == strcmp("stream_compression_payload", argv[i])) { + stream_compression_payload(config); + continue; + } + if (0 == strcmp("stream_compression_ping_pong_streaming", argv[i])) { + stream_compression_ping_pong_streaming(config); + continue; + } if (0 == strcmp("streaming_error_response", argv[i])) { streaming_error_response(config); continue; diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c index 3fc7c3fb6c..ca9443b642 100644 --- a/test/core/end2end/end2end_tests.c +++ b/test/core/end2end/end2end_tests.c @@ -132,6 +132,12 @@ extern void simple_metadata(grpc_end2end_test_config config); extern void simple_metadata_pre_init(void); extern void simple_request(grpc_end2end_test_config config); extern void simple_request_pre_init(void); +extern void stream_compression_compressed_payload(grpc_end2end_test_config config); +extern void stream_compression_compressed_payload_pre_init(void); +extern void stream_compression_payload(grpc_end2end_test_config config); +extern void stream_compression_payload_pre_init(void); +extern void stream_compression_ping_pong_streaming(grpc_end2end_test_config config); +extern void stream_compression_ping_pong_streaming_pre_init(void); extern void streaming_error_response(grpc_end2end_test_config config); extern void streaming_error_response_pre_init(void); extern void trailing_metadata(grpc_end2end_test_config config); @@ -198,6 +204,9 @@ void grpc_end2end_tests_pre_init(void) { simple_delayed_request_pre_init(); simple_metadata_pre_init(); simple_request_pre_init(); + stream_compression_compressed_payload_pre_init(); + stream_compression_payload_pre_init(); + stream_compression_ping_pong_streaming_pre_init(); streaming_error_response_pre_init(); trailing_metadata_pre_init(); workaround_cronet_compression_pre_init(); @@ -263,6 +272,9 @@ void grpc_end2end_tests(int argc, char **argv, simple_delayed_request(config); simple_metadata(config); simple_request(config); + stream_compression_compressed_payload(config); + stream_compression_payload(config); + stream_compression_ping_pong_streaming(config); streaming_error_response(config); trailing_metadata(config); workaround_cronet_compression(config); @@ -476,6 +488,18 @@ void grpc_end2end_tests(int argc, char **argv, simple_request(config); continue; } + if (0 == strcmp("stream_compression_compressed_payload", argv[i])) { + stream_compression_compressed_payload(config); + continue; + } + if (0 == strcmp("stream_compression_payload", argv[i])) { + stream_compression_payload(config); + continue; + } + if (0 == strcmp("stream_compression_ping_pong_streaming", argv[i])) { + stream_compression_ping_pong_streaming(config); + continue; + } if (0 == strcmp("streaming_error_response", argv[i])) { streaming_error_response(config); continue; diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c index 385e2cbf70..8a05bb722a 100644 --- a/test/core/end2end/fixtures/h2_load_reporting.c +++ b/test/core/end2end/fixtures/h2_load_reporting.c @@ -28,7 +28,7 @@ #include <grpc/support/useful.h> #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/http/server/http_server_filter.h" -#include "src/core/ext/filters/load_reporting/load_reporting.h" +#include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" diff --git a/test/core/end2end/fixtures/proxy.c b/test/core/end2end/fixtures/proxy.c index d457aeefe8..9ad862728f 100644 --- a/test/core/end2end/fixtures/proxy.c +++ b/test/core/end2end/fixtures/proxy.c @@ -80,7 +80,7 @@ grpc_end2end_proxy *grpc_end2end_proxy_create(const grpc_end2end_proxy_def *def, int proxy_port = grpc_pick_unused_port_or_die(); int server_port = grpc_pick_unused_port_or_die(); - grpc_end2end_proxy *proxy = gpr_malloc(sizeof(*proxy)); + grpc_end2end_proxy *proxy = (grpc_end2end_proxy *)gpr_malloc(sizeof(*proxy)); memset(proxy, 0, sizeof(*proxy)); gpr_join_host_port(&proxy->proxy_port, "localhost", proxy_port); @@ -106,14 +106,14 @@ grpc_end2end_proxy *grpc_end2end_proxy_create(const grpc_end2end_proxy_def *def, } static closure *new_closure(void (*func)(void *arg, int success), void *arg) { - closure *cl = gpr_malloc(sizeof(*cl)); + closure *cl = (closure *)gpr_malloc(sizeof(*cl)); cl->func = func; cl->arg = arg; return cl; } static void shutdown_complete(void *arg, int success) { - grpc_end2end_proxy *proxy = arg; + grpc_end2end_proxy *proxy = (grpc_end2end_proxy *)arg; proxy->shutdown = 1; grpc_completion_queue_shutdown(proxy->cq); } @@ -146,12 +146,12 @@ static void unrefpc(proxy_call *pc, const char *reason) { static void refpc(proxy_call *pc, const char *reason) { gpr_ref(&pc->refs); } static void on_c2p_sent_initial_metadata(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; unrefpc(pc, "on_c2p_sent_initial_metadata"); } static void on_p2s_recv_initial_metadata(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -172,14 +172,14 @@ static void on_p2s_recv_initial_metadata(void *arg, int success) { } static void on_p2s_sent_initial_metadata(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; unrefpc(pc, "on_p2s_sent_initial_metadata"); } static void on_c2p_recv_msg(void *arg, int success); static void on_p2s_sent_message(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -199,12 +199,12 @@ static void on_p2s_sent_message(void *arg, int success) { } static void on_p2s_sent_close(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; unrefpc(pc, "on_p2s_sent_close"); } static void on_c2p_recv_msg(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -235,7 +235,7 @@ static void on_c2p_recv_msg(void *arg, int success) { static void on_p2s_recv_msg(void *arg, int success); static void on_c2p_sent_message(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -255,7 +255,7 @@ static void on_c2p_sent_message(void *arg, int success) { } static void on_p2s_recv_msg(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -275,12 +275,12 @@ static void on_p2s_recv_msg(void *arg, int success) { } static void on_c2p_sent_status(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; unrefpc(pc, "on_c2p_sent_status"); } static void on_p2s_status(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; grpc_op op; grpc_call_error err; @@ -305,18 +305,18 @@ static void on_p2s_status(void *arg, int success) { } static void on_c2p_closed(void *arg, int success) { - proxy_call *pc = arg; + proxy_call *pc = (proxy_call *)arg; unrefpc(pc, "on_c2p_closed"); } static void on_new_call(void *arg, int success) { - grpc_end2end_proxy *proxy = arg; + grpc_end2end_proxy *proxy = (grpc_end2end_proxy *)arg; grpc_call_error err; if (success) { grpc_op op; memset(&op, 0, sizeof(op)); - proxy_call *pc = gpr_malloc(sizeof(*pc)); + proxy_call *pc = (proxy_call *)gpr_malloc(sizeof(*pc)); memset(pc, 0, sizeof(*pc)); pc->proxy = proxy; GPR_SWAP(grpc_metadata_array, pc->c2p_initial_metadata, @@ -404,7 +404,7 @@ static void request_call(grpc_end2end_proxy *proxy) { } static void thread_main(void *arg) { - grpc_end2end_proxy *proxy = arg; + grpc_end2end_proxy *proxy = (grpc_end2end_proxy *)arg; closure *cl; for (;;) { grpc_event ev = grpc_completion_queue_next( @@ -416,7 +416,7 @@ static void thread_main(void *arg) { case GRPC_QUEUE_SHUTDOWN: return; case GRPC_OP_COMPLETE: - cl = ev.tag; + cl = (closure *)ev.tag; cl->func(cl->arg, ev.success); gpr_free(cl); break; diff --git a/test/core/end2end/fuzzers/BUILD b/test/core/end2end/fuzzers/BUILD index bf3a62ad37..4ed9a70578 100644 --- a/test/core/end2end/fuzzers/BUILD +++ b/test/core/end2end/fuzzers/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/end2end/fuzzers") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary index 2bb9de34c5..7c77512aa9 100644 --- a/test/core/end2end/fuzzers/hpack.dictionary +++ b/test/core/end2end/fuzzers/hpack.dictionary @@ -14,7 +14,10 @@ "\x0Dgrpc-tags-bin" "\x0Egrpc-trace-bin" "\x0Ccontent-type" +"\x10content-encoding" +"\x0Faccept-encoding" "\x1Egrpc-internal-encoding-request" +"%grpc-internal-stream-encoding-request" "\x0Auser-agent" "\x04host" "\x08lb-token" @@ -49,7 +52,6 @@ "\x03400" "\x03500" "\x0Eaccept-charset" -"\x0Faccept-encoding" "\x0Dgzip, deflate" "\x0Faccept-language" "\x0Daccept-ranges" @@ -60,7 +62,6 @@ "\x0Dauthorization" "\x0Dcache-control" "\x13content-disposition" -"\x10content-encoding" "\x10content-language" "\x0Econtent-length" "\x10content-location" @@ -134,6 +135,8 @@ "\x00\x0Dauthorization\x00" "\x00\x0Dcache-control\x00" "\x00\x13content-disposition\x00" +"\x00\x10content-encoding\x08identity" +"\x00\x10content-encoding\x04gzip" "\x00\x10content-encoding\x00" "\x00\x10content-language\x00" "\x00\x0Econtent-length\x00" @@ -179,3 +182,6 @@ "\x00\x14grpc-accept-encoding\x0Didentity,gzip" "\x00\x14grpc-accept-encoding\x0Cdeflate,gzip" "\x00\x14grpc-accept-encoding\x15identity,deflate,gzip" +"\x00\x0Faccept-encoding\x08identity" +"\x00\x0Faccept-encoding\x04gzip" +"\x00\x0Faccept-encoding\x0Didentity,gzip" diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index 18bae63a8a..33fd97f3bd 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -137,6 +137,10 @@ END2END_TESTS = { 'shutdown_finishes_calls': default_test_options._replace(cpu_cost=LOWCPU), 'shutdown_finishes_tags': default_test_options._replace(cpu_cost=LOWCPU), 'simple_cacheable_request': default_test_options._replace(cpu_cost=LOWCPU), + 'stream_compression_compressed_payload': default_test_options._replace(proxyable=False, + exclude_inproc=True), + 'stream_compression_payload': default_test_options._replace(exclude_inproc=True), + 'stream_compression_ping_pong_streaming': default_test_options._replace(exclude_inproc=True), 'simple_delayed_request': connectivity_test_options, 'simple_metadata': default_test_options, 'simple_request': default_test_options, diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl index 6d1917c0ff..9bbba26108 100755 --- a/test/core/end2end/generate_tests.bzl +++ b/test/core/end2end/generate_tests.bzl @@ -138,6 +138,9 @@ END2END_TESTS = { 'simple_metadata': test_options(), 'simple_request': test_options(), 'streaming_error_response': test_options(), + 'stream_compression_compressed_payload': test_options(proxyable=False, exclude_inproc=True), + 'stream_compression_payload': test_options(exclude_inproc=True), + 'stream_compression_ping_pong_streaming': test_options(exclude_inproc=True), 'trailing_metadata': test_options(), 'authority_not_supported': test_options(), 'filter_latency': test_options(), diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c index a360c6f0d2..c3ac0c3201 100644 --- a/test/core/end2end/tests/cancel_after_accept.c +++ b/test/core/end2end/tests/cancel_after_accept.c @@ -39,10 +39,13 @@ 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, + cancellation_mode mode, + bool use_service_config, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s/%s/%s", test_name, config.name, + mode.name, use_service_config ? "service_config" : "client_api"); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -135,8 +138,8 @@ static void test_cancel_after_accept(grpc_end2end_test_config config, args = grpc_channel_args_copy_and_add(args, &arg, 1); } - grpc_end2end_test_fixture f = - begin_test(config, "cancel_after_accept", args, NULL); + grpc_end2end_test_fixture f = begin_test(config, "cancel_after_accept", mode, + use_service_config, args, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); gpr_timespec deadline = use_service_config diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c index 502005b6af..0e2a751d83 100644 --- a/test/core/end2end/tests/cancel_after_client_done.c +++ b/test/core/end2end/tests/cancel_after_client_done.c @@ -33,10 +33,12 @@ 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, + cancellation_mode mode, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s/%s", test_name, config.name, + mode.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -93,7 +95,7 @@ static void test_cancel_after_accept_and_writes_closed( grpc_call *c; grpc_call *s; grpc_end2end_test_fixture f = begin_test( - config, "test_cancel_after_accept_and_writes_closed", NULL, NULL); + config, "test_cancel_after_accept_and_writes_closed", mode, NULL, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; diff --git a/test/core/end2end/tests/cancel_after_round_trip.c b/test/core/end2end/tests/cancel_after_round_trip.c index 0fc8b95ef7..bc41bd3a6d 100644 --- a/test/core/end2end/tests/cancel_after_round_trip.c +++ b/test/core/end2end/tests/cancel_after_round_trip.c @@ -39,10 +39,13 @@ 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, + cancellation_mode mode, + bool use_service_config, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s/%s/%s", test_name, config.name, + mode.name, use_service_config ? "service_config" : "client_api"); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -114,7 +117,9 @@ static void test_cancel_after_round_trip(grpc_end2end_test_config config, grpc_slice_from_copied_string("hello you"); grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); - grpc_byte_buffer *response_payload = + grpc_byte_buffer *response_payload1 = + grpc_raw_byte_buffer_create(&response_payload_slice, 1); + grpc_byte_buffer *response_payload2 = grpc_raw_byte_buffer_create(&response_payload_slice, 1); int was_cancelled = 2; @@ -135,8 +140,8 @@ static void test_cancel_after_round_trip(grpc_end2end_test_config config, args = grpc_channel_args_copy_and_add(args, &arg, 1); } - grpc_end2end_test_fixture f = - begin_test(config, "cancel_after_round_trip", args, NULL); + grpc_end2end_test_fixture f = begin_test( + config, "cancel_after_round_trip", mode, use_service_config, args, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); gpr_timespec deadline = use_service_config @@ -199,7 +204,7 @@ static void test_cancel_after_round_trip(grpc_end2end_test_config config, op->reserved = NULL; op++; op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.send_message = response_payload; + op->data.send_message.send_message = response_payload1; op->flags = 0; op->reserved = NULL; op++; @@ -242,7 +247,7 @@ static void test_cancel_after_round_trip(grpc_end2end_test_config config, op->reserved = NULL; op++; op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.send_message = response_payload; + op->data.send_message.send_message = response_payload2; op->flags = 0; op->reserved = NULL; op++; @@ -262,7 +267,8 @@ static void test_cancel_after_round_trip(grpc_end2end_test_config config, grpc_call_details_destroy(&call_details); grpc_byte_buffer_destroy(request_payload); - grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(response_payload1); + grpc_byte_buffer_destroy(response_payload2); grpc_byte_buffer_destroy(request_payload_recv); grpc_byte_buffer_destroy(response_payload_recv); grpc_slice_unref(details); diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c index 423194b63e..397e8b8ba6 100644 --- a/test/core/end2end/tests/cancel_before_invoke.c +++ b/test/core/end2end/tests/cancel_before_invoke.c @@ -32,10 +32,12 @@ 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, + size_t num_ops, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s [%" PRIdPTR " ops]", test_name, + config.name, num_ops); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -91,7 +93,7 @@ static void test_cancel_before_invoke(grpc_end2end_test_config config, grpc_op *op; grpc_call *c; grpc_end2end_test_fixture f = - begin_test(config, "cancel_before_invoke", NULL, NULL); + begin_test(config, "cancel_before_invoke", test_ops, NULL, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c index f64cbdf929..cd9551bef9 100644 --- a/test/core/end2end/tests/cancel_in_a_vacuum.c +++ b/test/core/end2end/tests/cancel_in_a_vacuum.c @@ -33,10 +33,12 @@ 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, + cancellation_mode mode, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s/%s", test_name, config.name, + mode.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -90,7 +92,7 @@ static void test_cancel_in_a_vacuum(grpc_end2end_test_config config, cancellation_mode mode) { grpc_call *c; grpc_end2end_test_fixture f = - begin_test(config, "test_cancel_in_a_vacuum", NULL, NULL); + begin_test(config, "test_cancel_in_a_vacuum", mode, NULL, NULL); cq_verifier *v_client = cq_verifier_create(f.cq); gpr_timespec deadline = five_seconds_from_now(); diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c index fd26fd122e..ab8c4f4187 100644 --- a/test/core/end2end/tests/cancel_with_status.c +++ b/test/core/end2end/tests/cancel_with_status.c @@ -35,10 +35,12 @@ 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, + size_t num_ops, grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; - gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + gpr_log(GPR_INFO, "Running test: %s/%s [%" PRIdPTR " ops]", test_name, + config.name, num_ops); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); config.init_client(&f, client_args); @@ -165,7 +167,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config, size_t num_ops) { grpc_end2end_test_fixture f; - f = begin_test(config, "test_invoke_simple_request", NULL, NULL); + f = begin_test(config, "test_invoke_simple_request", num_ops, NULL, NULL); simple_request_body(config, f, num_ops); end_test(&f); config.tear_down_data(&f); diff --git a/test/core/end2end/tests/connectivity.c b/test/core/end2end/tests/connectivity.c index a5af46e09e..610243ee3a 100644 --- a/test/core/end2end/tests/connectivity.c +++ b/test/core/end2end/tests/connectivity.c @@ -34,7 +34,7 @@ typedef struct { } child_events; static void child_thread(void *arg) { - child_events *ce = arg; + child_events *ce = (child_events *)arg; grpc_event ev; gpr_event_set(&ce->started, (void *)1); gpr_log(GPR_DEBUG, "verifying"); diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c index b6be375a51..09e9dbcd7b 100644 --- a/test/core/end2end/tests/filter_call_init_fails.c +++ b/test/core/end2end/tests/filter_call_init_fails.c @@ -430,7 +430,6 @@ static const grpc_channel_filter test_filter = { 0, init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, grpc_channel_next_get_info, "filter_call_init_fails"}; diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c index aff39dd89d..ee7aeb3f33 100644 --- a/test/core/end2end/tests/filter_causes_close.c +++ b/test/core/end2end/tests/filter_causes_close.c @@ -195,9 +195,9 @@ typedef struct { uint8_t unused; } channel_data; static void recv_im_ready(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_call_element *elem = arg; - call_data *calld = elem->call_data; - GRPC_CLOSURE_SCHED( + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + GRPC_CLOSURE_RUN( exec_ctx, calld->recv_im_ready, grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failure that's not preventable.", &error, 1), @@ -208,7 +208,7 @@ static void recv_im_ready(grpc_exec_ctx *exec_ctx, void *arg, static void start_transport_stream_op_batch( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *op) { - call_data *calld = elem->call_data; + call_data *calld = (call_data *)elem->call_data; if (op->recv_initial_metadata) { calld->recv_im_ready = op->payload->recv_initial_metadata.recv_initial_metadata_ready; @@ -247,7 +247,6 @@ static const grpc_channel_filter test_filter = { sizeof(channel_data), init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, grpc_channel_next_get_info, "filter_causes_close"}; diff --git a/test/core/end2end/tests/filter_latency.c b/test/core/end2end/tests/filter_latency.c index 5dbbc4d18d..c24934f05d 100644 --- a/test/core/end2end/tests/filter_latency.c +++ b/test/core/end2end/tests/filter_latency.c @@ -290,7 +290,6 @@ static const grpc_channel_filter test_client_filter = { 0, init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, grpc_channel_next_get_info, "client_filter_latency"}; @@ -304,7 +303,6 @@ static const grpc_channel_filter test_server_filter = { 0, init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, grpc_channel_next_get_info, "server_filter_latency"}; @@ -314,7 +312,7 @@ static const grpc_channel_filter test_server_filter = { static bool maybe_add_filter(grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { - grpc_channel_filter *filter = arg; + grpc_channel_filter *filter = (grpc_channel_filter *)arg; if (g_enable_filter) { // Want to add the filter as close to the end as possible, to make // sure that all of the filters work well together. However, we diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c index 3584d47887..7b503790db 100644 --- a/test/core/end2end/tests/load_reporting_hook.c +++ b/test/core/end2end/tests/load_reporting_hook.c @@ -26,8 +26,8 @@ #include <grpc/support/time.h> #include <grpc/support/useful.h> -#include "src/core/ext/filters/load_reporting/load_reporting.h" -#include "src/core/ext/filters/load_reporting/load_reporting_filter.h" +#include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h" +#include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/transport/static_metadata.h" diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c index 19fb4d9769..d98eed68e0 100644 --- a/test/core/end2end/tests/payload.c +++ b/test/core/end2end/tests/payload.c @@ -91,7 +91,7 @@ static grpc_slice generate_random_slice() { static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; char *output; const size_t output_size = 1024 * 1024; - output = gpr_malloc(output_size); + output = (char *)gpr_malloc(output_size); for (i = 0; i < output_size - 1; ++i) { output[i] = chars[rand() % (int)(sizeof(chars) - 1)]; } diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c index 010e20c4c2..0316920762 100644 --- a/test/core/end2end/tests/resource_quota_server.c +++ b/test/core/end2end/tests/resource_quota_server.c @@ -91,7 +91,7 @@ static grpc_slice generate_random_slice() { static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; char *output; const size_t output_size = 1024 * 1024; - output = gpr_malloc(output_size); + output = (char *)gpr_malloc(output_size); for (i = 0; i < output_size - 1; ++i) { output[i] = chars[rand() % (int)(sizeof(chars) - 1)]; } @@ -111,10 +111,10 @@ void resource_quota_server(grpc_end2end_test_config config) { grpc_resource_quota_resize(resource_quota, 5 * 1024 * 1024); #define NUM_CALLS 100 -#define CLIENT_BASE_TAG 1000 -#define SERVER_START_BASE_TAG 2000 -#define SERVER_RECV_BASE_TAG 3000 -#define SERVER_END_BASE_TAG 4000 +#define CLIENT_BASE_TAG 0x1000 +#define SERVER_START_BASE_TAG 0x2000 +#define SERVER_RECV_BASE_TAG 0x3000 +#define SERVER_END_BASE_TAG 0x4000 grpc_arg arg; arg.key = GRPC_ARG_RESOURCE_QUOTA; @@ -131,8 +131,10 @@ void resource_quota_server(grpc_end2end_test_config config) { * will be verified on completion. */ grpc_slice request_payload_slice = generate_random_slice(); - grpc_call **client_calls = malloc(sizeof(grpc_call *) * NUM_CALLS); - grpc_call **server_calls = malloc(sizeof(grpc_call *) * NUM_CALLS); + grpc_call **client_calls = + (grpc_call **)malloc(sizeof(grpc_call *) * NUM_CALLS); + grpc_call **server_calls = + (grpc_call **)malloc(sizeof(grpc_call *) * NUM_CALLS); grpc_metadata_array *initial_metadata_recv = malloc(sizeof(grpc_metadata_array) * NUM_CALLS); grpc_metadata_array *trailing_metadata_recv = @@ -141,11 +143,14 @@ void resource_quota_server(grpc_end2end_test_config config) { malloc(sizeof(grpc_metadata_array) * NUM_CALLS); grpc_call_details *call_details = malloc(sizeof(grpc_call_details) * NUM_CALLS); - grpc_status_code *status = malloc(sizeof(grpc_status_code) * NUM_CALLS); - grpc_slice *details = malloc(sizeof(grpc_slice) * NUM_CALLS); + grpc_status_code *status = + (grpc_status_code *)malloc(sizeof(grpc_status_code) * NUM_CALLS); + grpc_slice *details = (grpc_slice *)malloc(sizeof(grpc_slice) * NUM_CALLS); + grpc_byte_buffer **request_payload = + malloc(sizeof(grpc_byte_buffer *) * NUM_CALLS); grpc_byte_buffer **request_payload_recv = malloc(sizeof(grpc_byte_buffer *) * NUM_CALLS); - int *was_cancelled = malloc(sizeof(int) * NUM_CALLS); + int *was_cancelled = (int *)malloc(sizeof(int) * NUM_CALLS); grpc_call_error error; int pending_client_calls = 0; int pending_server_start_calls = 0; @@ -156,9 +161,6 @@ void resource_quota_server(grpc_end2end_test_config config) { int deadline_exceeded = 0; int unavailable = 0; - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); - grpc_op ops[6]; grpc_op *op; @@ -167,6 +169,7 @@ void resource_quota_server(grpc_end2end_test_config config) { grpc_metadata_array_init(&trailing_metadata_recv[i]); grpc_metadata_array_init(&request_metadata_recv[i]); grpc_call_details_init(&call_details[i]); + request_payload[i] = grpc_raw_byte_buffer_create(&request_payload_slice, 1); request_payload_recv[i] = NULL; was_cancelled[i] = 0; } @@ -195,7 +198,7 @@ void resource_quota_server(grpc_end2end_test_config config) { op->reserved = NULL; op++; op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.send_message = request_payload; + op->data.send_message.send_message = request_payload[i]; op->flags = 0; op->reserved = NULL; op++; @@ -261,6 +264,7 @@ void resource_quota_server(grpc_end2end_test_config config) { grpc_metadata_array_destroy(&trailing_metadata_recv[call_id]); grpc_call_unref(client_calls[call_id]); grpc_slice_unref(details[call_id]); + grpc_byte_buffer_destroy(request_payload[call_id]); pending_client_calls--; } else if (ev_tag < SERVER_RECV_BASE_TAG) { @@ -351,7 +355,6 @@ void resource_quota_server(grpc_end2end_test_config config) { NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client, deadline_exceeded, unavailable); - grpc_byte_buffer_destroy(request_payload); grpc_slice_unref(request_payload_slice); grpc_resource_quota_unref(resource_quota); @@ -366,6 +369,7 @@ void resource_quota_server(grpc_end2end_test_config config) { free(call_details); free(status); free(details); + free(request_payload); free(request_payload_recv); free(was_cancelled); } diff --git a/test/core/end2end/tests/shutdown_finishes_tags.c b/test/core/end2end/tests/shutdown_finishes_tags.c index f9b8e4c955..7914cc95ba 100644 --- a/test/core/end2end/tests/shutdown_finishes_tags.c +++ b/test/core/end2end/tests/shutdown_finishes_tags.c @@ -78,7 +78,7 @@ static void test_early_server_shutdown_finishes_tags( grpc_end2end_test_fixture f = begin_test( config, "test_early_server_shutdown_finishes_tags", NULL, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); - grpc_call *s = (void *)1; + grpc_call *s = (grpc_call *)(uintptr_t)1; grpc_call_details call_details; grpc_metadata_array request_metadata_recv; diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c index 7a81133dfa..82ab0a1cfe 100644 --- a/test/core/end2end/tests/simple_request.c +++ b/test/core/end2end/tests/simple_request.c @@ -27,6 +27,7 @@ #include <grpc/support/log.h> #include <grpc/support/time.h> #include <grpc/support/useful.h> +#include "src/core/lib/debug/stats.h" #include "src/core/lib/support/string.h" #include "test/core/end2end/cq_verifier.h" @@ -102,6 +103,10 @@ static void simple_request_body(grpc_end2end_test_config config, grpc_slice details; int was_cancelled = 2; char *peer; + grpc_stats_data before; + grpc_stats_data after; + + grpc_stats_collect(&before); gpr_timespec deadline = five_seconds_from_now(); c = grpc_channel_create_call( @@ -208,6 +213,23 @@ static void simple_request_body(grpc_end2end_test_config config, grpc_call_unref(s); cq_verifier_destroy(cqv); + + grpc_stats_collect(&after); + + char *stats = grpc_stats_data_as_json(&after); + gpr_log(GPR_DEBUG, "%s", stats); + gpr_free(stats); + + int expected_calls = 1; + if (config.feature_mask & FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) { + expected_calls *= 2; + } + GPR_ASSERT(after.counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] - + before.counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] == + expected_calls); + GPR_ASSERT(after.counters[GRPC_STATS_COUNTER_SERVER_CALLS_CREATED] - + before.counters[GRPC_STATS_COUNTER_SERVER_CALLS_CREATED] == + expected_calls); } static void test_invoke_simple_request(grpc_end2end_test_config config) { diff --git a/test/core/end2end/tests/stream_compression_compressed_payload.c b/test/core/end2end/tests/stream_compression_compressed_payload.c new file mode 100644 index 0000000000..11e7999a1c --- /dev/null +++ b/test/core/end2end/tests/stream_compression_compressed_payload.c @@ -0,0 +1,652 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test/core/end2end/end2end_tests.h" + +#include <stdio.h> +#include <string.h> + +#include <grpc/byte_buffer.h> +#include <grpc/byte_buffer_reader.h> +#include <grpc/compression.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 "src/core/lib/channel/channel_args.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/call_test_only.h" +#include "src/core/lib/transport/static_metadata.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, "Running test: %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_from_now(int n) { + return grpc_timeout_seconds_to_deadline(n); +} + +static gpr_timespec five_seconds_from_now(void) { + return n_seconds_from_now(5); +} + +static void drain_cq(grpc_completion_queue *cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_from_now(), 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->shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000), + grpc_timeout_seconds_to_deadline(5), + 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); + grpc_completion_queue_destroy(f->shutdown_cq); +} + +static void request_for_disabled_algorithm( + grpc_end2end_test_config config, const char *test_name, + uint32_t send_flags_bitmask, + grpc_stream_compression_algorithm algorithm_to_disable, + grpc_stream_compression_algorithm requested_client_compression_algorithm, + grpc_status_code expected_error, grpc_metadata *client_metadata) { + grpc_call *c; + grpc_call *s; + grpc_slice request_payload_slice; + grpc_byte_buffer *request_payload; + grpc_channel_args *client_args; + grpc_channel_args *server_args; + grpc_end2end_test_fixture f; + 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 *request_payload_recv = NULL; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + cq_verifier *cqv; + char str[1024]; + + memset(str, 'x', 1023); + str[1023] = '\0'; + request_payload_slice = grpc_slice_from_copied_string(str); + request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); + + client_args = grpc_channel_args_set_stream_compression_algorithm( + NULL, requested_client_compression_algorithm); + server_args = grpc_channel_args_set_stream_compression_algorithm( + NULL, GRPC_STREAM_COMPRESS_NONE); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + server_args = grpc_channel_args_stream_compression_algorithm_set_state( + &exec_ctx, &server_args, algorithm_to_disable, false); + grpc_exec_ctx_finish(&exec_ctx); + } + + f = begin_test(config, test_name, client_args, server_args); + cqv = cq_verifier_create(f.cq); + + gpr_timespec deadline = five_seconds_from_now(); + 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; + if (client_metadata != NULL) { + op->data.send_initial_metadata.count = 1; + op->data.send_initial_metadata.metadata = client_metadata; + } else { + op->data.send_initial_metadata.count = 0; + } + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = request_payload; + op->flags = send_flags_bitmask; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), true); + cq_verify(cqv); + + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &request_payload_recv; + op->flags = 0; + op->reserved = NULL; + 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), false); + + op = ops; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(103), true); + CQ_EXPECT_COMPLETION(cqv, tag(1), true); + cq_verify(cqv); + + /* call was cancelled (closed) ... */ + GPR_ASSERT(was_cancelled != 0); + /* with a certain error */ + GPR_ASSERT(status == expected_error); + + char *algo_name = NULL; + GPR_ASSERT( + grpc_stream_compression_algorithm_name(algorithm_to_disable, &algo_name)); + char *expected_details = NULL; + gpr_asprintf(&expected_details, + "Stream compression algorithm '%s' is disabled.", algo_name); + /* and we expect a specific reason for it */ + GPR_ASSERT(0 == grpc_slice_str_cmp(details, expected_details)); + gpr_free(expected_details); + GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); + validate_host_override_string("foo.test.google.fr:1234", call_details.host, + config); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + grpc_slice_unref(request_payload_slice); + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(request_payload_recv); + + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, client_args); + grpc_channel_args_destroy(&exec_ctx, server_args); + grpc_exec_ctx_finish(&exec_ctx); + } + + end_test(&f); + config.tear_down_data(&f); +} + +static void request_with_payload_template( + grpc_end2end_test_config config, const char *test_name, + uint32_t client_send_flags_bitmask, + grpc_stream_compression_algorithm + default_client_channel_compression_algorithm, + grpc_stream_compression_algorithm + default_server_channel_compression_algorithm, + grpc_stream_compression_algorithm expected_client_compression_algorithm, + grpc_stream_compression_algorithm expected_server_compression_algorithm, + grpc_metadata *client_init_metadata, bool set_server_level, + grpc_stream_compression_level server_compression_level, + bool send_message_before_initial_metadata, + bool set_default_server_message_compression_algorithm, + grpc_compression_algorithm default_server_message_compression_algorithm) { + grpc_call *c; + grpc_call *s; + grpc_slice request_payload_slice; + grpc_byte_buffer *request_payload = NULL; + grpc_channel_args *client_args; + grpc_channel_args *server_args; + grpc_end2end_test_fixture f; + 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 *request_payload_recv = NULL; + grpc_byte_buffer *response_payload; + grpc_byte_buffer *response_payload_recv; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + cq_verifier *cqv; + char request_str[1024]; + char response_str[1024]; + + memset(request_str, 'x', 1023); + request_str[1023] = '\0'; + + memset(response_str, 'y', 1023); + response_str[1023] = '\0'; + + request_payload_slice = grpc_slice_from_copied_string(request_str); + grpc_slice response_payload_slice = + grpc_slice_from_copied_string(response_str); + + client_args = grpc_channel_args_set_stream_compression_algorithm( + NULL, default_client_channel_compression_algorithm); + if (set_default_server_message_compression_algorithm) { + server_args = grpc_channel_args_set_compression_algorithm( + NULL, default_server_message_compression_algorithm); + } else { + server_args = grpc_channel_args_set_stream_compression_algorithm( + NULL, default_server_channel_compression_algorithm); + } + + f = begin_test(config, test_name, client_args, server_args); + cqv = cq_verifier_create(f.cq); + + gpr_timespec deadline = five_seconds_from_now(); + 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); + + if (send_message_before_initial_metadata) { + request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = request_payload; + op->flags = client_send_flags_bitmask; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(2), true); + } + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + if (client_init_metadata != NULL) { + op->data.send_initial_metadata.count = 1; + op->data.send_initial_metadata.metadata = client_init_metadata; + } else { + op->data.send_initial_metadata.count = 0; + } + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(100)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(100), true); + cq_verify(cqv); + + GPR_ASSERT(GPR_BITCOUNT(grpc_call_test_only_get_encodings_accepted_by_peer( + s)) == GRPC_COMPRESS_ALGORITHMS_COUNT); + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), + GRPC_COMPRESS_NONE) != 0); + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), + GRPC_COMPRESS_DEFLATE) != 0); + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), + GRPC_COMPRESS_GZIP) != 0); + GPR_ASSERT( + GPR_BITCOUNT(grpc_call_test_only_get_stream_encodings_accepted_by_peer( + s)) == GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT); + GPR_ASSERT( + GPR_BITGET(grpc_call_test_only_get_stream_encodings_accepted_by_peer(s), + GRPC_STREAM_COMPRESS_NONE) != 0); + GPR_ASSERT( + GPR_BITGET(grpc_call_test_only_get_stream_encodings_accepted_by_peer(s), + GRPC_STREAM_COMPRESS_GZIP) != 0); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + if (set_server_level) { + op->data.send_initial_metadata.maybe_stream_compression_level.is_set = true; + op->data.send_initial_metadata.maybe_stream_compression_level.level = + server_compression_level; + } + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + for (int i = 0; i < 2; i++) { + response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1); + + if (i > 0 || !send_message_before_initial_metadata) { + request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = request_payload; + op->flags = client_send_flags_bitmask; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(2), 1); + } + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &request_payload_recv; + op->flags = 0; + op->reserved = NULL; + 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); + + GPR_ASSERT(request_payload_recv->type == GRPC_BB_RAW); + GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, request_str)); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = response_payload; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload_recv; + op->flags = 0; + op->reserved = NULL; + 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(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(3), 1); + cq_verify(cqv); + + GPR_ASSERT(response_payload_recv->type == GRPC_BB_RAW); + GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, response_str)); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(request_payload_recv); + grpc_byte_buffer_destroy(response_payload_recv); + } + + grpc_slice_unref(request_payload_slice); + grpc_slice_unref(response_payload_slice); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_OK; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + CQ_EXPECT_COMPLETION(cqv, tag(4), 1); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + CQ_EXPECT_COMPLETION(cqv, tag(104), 1); + cq_verify(cqv); + + GPR_ASSERT(status == GRPC_STATUS_OK); + GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); + 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_ASSERT(was_cancelled == 0); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, client_args); + grpc_channel_args_destroy(&exec_ctx, server_args); + grpc_exec_ctx_finish(&exec_ctx); + } + + end_test(&f); + config.tear_down_data(&f); +} + +static void test_invoke_request_with_compressed_payload( + grpc_end2end_test_config config) { + request_with_payload_template( + config, "test_invoke_request_with_compressed_payload", 0, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_GZIP, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_GZIP, NULL, + false, /* ignored */ + GRPC_STREAM_COMPRESS_LEVEL_NONE, false, false, GRPC_COMPRESS_NONE); +} + +static void test_invoke_request_with_send_message_before_initial_metadata( + grpc_end2end_test_config config) { + request_with_payload_template( + config, "test_invoke_request_with_send_message_before_initial_metadata", + 0, GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_GZIP, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_GZIP, NULL, + false, /* ignored */ + GRPC_STREAM_COMPRESS_LEVEL_NONE, true, false, GRPC_COMPRESS_NONE); +} + +static void test_invoke_request_with_server_level( + grpc_end2end_test_config config) { + request_with_payload_template( + config, "test_invoke_request_with_server_level", 0, + GRPC_STREAM_COMPRESS_NONE, GRPC_STREAM_COMPRESS_NONE, + GRPC_STREAM_COMPRESS_NONE, GRPC_STREAM_COMPRESS_GZIP, + /* ignored */ NULL, true, GRPC_STREAM_COMPRESS_LEVEL_HIGH, false, false, + GRPC_COMPRESS_NONE); +} + +static void test_invoke_request_with_compressed_payload_md_override( + grpc_end2end_test_config config) { + grpc_metadata gzip_compression_override; + grpc_metadata identity_compression_override; + + gzip_compression_override.key = + GRPC_MDSTR_GRPC_INTERNAL_STREAM_ENCODING_REQUEST; + gzip_compression_override.value = grpc_slice_from_static_string("gzip"); + memset(&gzip_compression_override.internal_data, 0, + sizeof(gzip_compression_override.internal_data)); + + identity_compression_override.key = + GRPC_MDSTR_GRPC_INTERNAL_STREAM_ENCODING_REQUEST; + identity_compression_override.value = + grpc_slice_from_static_string("identity"); + memset(&identity_compression_override.internal_data, 0, + sizeof(identity_compression_override.internal_data)); + + /* Channel default NONE (aka IDENTITY), call override to stream GZIP */ + request_with_payload_template( + config, "test_invoke_request_with_compressed_payload_md_override_1", 0, + GRPC_STREAM_COMPRESS_NONE, GRPC_STREAM_COMPRESS_NONE, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_NONE, + &gzip_compression_override, false, + /*ignored*/ GRPC_STREAM_COMPRESS_LEVEL_NONE, false, false, + GRPC_COMPRESS_NONE); + + /* Channel default stream GZIP, call override to NONE (aka IDENTITY) */ + request_with_payload_template( + config, "test_invoke_request_with_compressed_payload_md_override_3", 0, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_NONE, + GRPC_STREAM_COMPRESS_NONE, GRPC_STREAM_COMPRESS_NONE, + &identity_compression_override, false, + /*ignored*/ GRPC_STREAM_COMPRESS_LEVEL_NONE, false, false, + GRPC_COMPRESS_NONE); +} + +static void test_invoke_request_with_disabled_algorithm( + grpc_end2end_test_config config) { + request_for_disabled_algorithm( + config, "test_invoke_request_with_disabled_algorithm", 0, + GRPC_STREAM_COMPRESS_GZIP, GRPC_STREAM_COMPRESS_GZIP, + GRPC_STATUS_UNIMPLEMENTED, NULL); +} + +static void test_stream_compression_override_message_compression( + grpc_end2end_test_config config) { + grpc_stream_compression_level level = GRPC_STREAM_COMPRESS_LEVEL_MED; + request_with_payload_template( + config, "test_stream_compression_override_message_compression", 0, + GRPC_STREAM_COMPRESS_NONE, GRPC_STREAM_COMPRESS_NONE, + GRPC_STREAM_COMPRESS_NONE, + grpc_stream_compression_algorithm_for_level( + level, (1u << GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT) - 1), + /* ignored */ NULL, true, level, false, true, GRPC_COMPRESS_GZIP); +} + +void stream_compression_compressed_payload(grpc_end2end_test_config config) { + test_invoke_request_with_compressed_payload(config); + test_invoke_request_with_send_message_before_initial_metadata(config); + test_invoke_request_with_server_level(config); + test_invoke_request_with_compressed_payload_md_override(config); + test_invoke_request_with_disabled_algorithm(config); + test_stream_compression_override_message_compression(config); +} + +void stream_compression_compressed_payload_pre_init(void) {} diff --git a/test/core/end2end/tests/stream_compression_payload.c b/test/core/end2end/tests/stream_compression_payload.c new file mode 100644 index 0000000000..e47d2aa93c --- /dev/null +++ b/test/core/end2end/tests/stream_compression_payload.c @@ -0,0 +1,305 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test/core/end2end/end2end_tests.h" + +#include <stdio.h> +#include <string.h> + +#include <grpc/byte_buffer.h> +#include <grpc/compression.h> +#include <grpc/compression.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/surface/call.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, "Running test: %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_from_now(int n) { + return grpc_timeout_seconds_to_deadline(n); +} + +static gpr_timespec five_seconds_from_now(void) { + return n_seconds_from_now(5); +} + +static void drain_cq(grpc_completion_queue *cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_from_now(), 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->shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000), + grpc_timeout_seconds_to_deadline(5), + 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); + grpc_completion_queue_destroy(f->shutdown_cq); +} + +/* Creates and returns a grpc_slice containing random alphanumeric characters. + */ +static grpc_slice generate_random_slice() { + size_t i; + static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + char *output; + const size_t output_size = 1024 * 1024; + output = (char *)gpr_malloc(output_size); + for (i = 0; i < output_size - 1; ++i) { + output[i] = chars[rand() % (int)(sizeof(chars) - 1)]; + } + output[output_size - 1] = '\0'; + grpc_slice out = grpc_slice_from_copied_string(output); + gpr_free(output); + return out; +} + +static void request_response_with_payload(grpc_end2end_test_config config, + grpc_end2end_test_fixture f) { + /* Create large request and response bodies. These are big enough to require + * multiple round trips to deliver to the peer, and their exact contents of + * will be verified on completion. */ + grpc_slice request_payload_slice = generate_random_slice(); + grpc_slice response_payload_slice = generate_random_slice(); + + grpc_call *c; + grpc_call *s; + grpc_byte_buffer *request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_byte_buffer *response_payload = + grpc_raw_byte_buffer_create(&response_payload_slice, 1); + 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 *request_payload_recv = NULL; + grpc_byte_buffer *response_payload_recv = NULL; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + + gpr_timespec deadline = n_seconds_from_now(60); + 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->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = request_payload; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + cq_verify(cqv); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &request_payload_recv; + op->flags = 0; + op->reserved = NULL; + 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); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = response_payload; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_OK; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(status == GRPC_STATUS_OK); + GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); + 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_ASSERT(was_cancelled == 0); + GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice)); + GPR_ASSERT( + byte_buffer_eq_slice(response_payload_recv, response_payload_slice)); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(request_payload_recv); + grpc_byte_buffer_destroy(response_payload_recv); +} + +/* Client sends a request with payload, server reads then returns a response + payload and status. */ +static void test_invoke_request_response_with_payload( + grpc_end2end_test_config config) { + grpc_channel_args *client_args = + grpc_channel_args_set_stream_compression_algorithm( + NULL, GRPC_STREAM_COMPRESS_GZIP); + grpc_channel_args *server_args = + grpc_channel_args_set_stream_compression_algorithm( + NULL, GRPC_STREAM_COMPRESS_GZIP); + grpc_end2end_test_fixture f = + begin_test(config, "test_invoke_request_response_with_payload", + client_args, server_args); + request_response_with_payload(config, f); + end_test(&f); + config.tear_down_data(&f); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, client_args); + grpc_channel_args_destroy(&exec_ctx, server_args); + grpc_exec_ctx_finish(&exec_ctx); + } +} + +static void test_invoke_10_request_response_with_payload( + grpc_end2end_test_config config) { + int i; + grpc_end2end_test_fixture f = begin_test( + config, "test_invoke_10_request_response_with_payload", NULL, NULL); + for (i = 0; i < 10; i++) { + request_response_with_payload(config, f); + } + end_test(&f); + config.tear_down_data(&f); +} + +void stream_compression_payload(grpc_end2end_test_config config) { + test_invoke_request_response_with_payload(config); + test_invoke_10_request_response_with_payload(config); +} + +void stream_compression_payload_pre_init(void) {} diff --git a/test/core/end2end/tests/stream_compression_ping_pong_streaming.c b/test/core/end2end/tests/stream_compression_ping_pong_streaming.c new file mode 100644 index 0000000000..4c1a34cc64 --- /dev/null +++ b/test/core/end2end/tests/stream_compression_ping_pong_streaming.c @@ -0,0 +1,291 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test/core/end2end/end2end_tests.h" + +#include <stdio.h> +#include <string.h> + +#include <grpc/byte_buffer.h> +#include <grpc/compression.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/surface/call.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, "Running test: %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_from_now(int n) { + return grpc_timeout_seconds_to_deadline(n); +} + +static gpr_timespec five_seconds_from_now(void) { + return n_seconds_from_now(5); +} + +static void drain_cq(grpc_completion_queue *cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_from_now(), 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->shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000), + grpc_timeout_seconds_to_deadline(5), + 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); + grpc_completion_queue_destroy(f->shutdown_cq); +} + +/* Client pings and server pongs. Repeat messages rounds before finishing. */ +static void test_pingpong_streaming(grpc_end2end_test_config config, + int messages) { + grpc_channel_args *client_args = + grpc_channel_args_set_stream_compression_algorithm( + NULL, GRPC_STREAM_COMPRESS_GZIP); + grpc_channel_args *server_args = + grpc_channel_args_set_stream_compression_algorithm( + NULL, GRPC_STREAM_COMPRESS_GZIP); + grpc_end2end_test_fixture f = + begin_test(config, "test_pingpong_streaming", client_args, server_args); + grpc_call *c; + grpc_call *s; + 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_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + grpc_byte_buffer *request_payload; + grpc_byte_buffer *request_payload_recv; + grpc_byte_buffer *response_payload; + grpc_byte_buffer *response_payload_recv; + int i; + grpc_slice request_payload_slice = + grpc_slice_from_copied_string("hello world"); + grpc_slice response_payload_slice = + grpc_slice_from_copied_string("hello you"); + + gpr_timespec deadline = five_seconds_from_now(); + 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->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(100)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(100), 1); + cq_verify(cqv); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + for (i = 0; i < messages; i++) { + request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); + response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = request_payload; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload_recv; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &request_payload_recv; + op->flags = 0; + op->reserved = NULL; + 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); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = response_payload; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(2), 1); + cq_verify(cqv); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(request_payload_recv); + grpc_byte_buffer_destroy(response_payload_recv); + } + + grpc_slice_unref(request_payload_slice); + grpc_slice_unref(response_payload_slice); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + CQ_EXPECT_COMPLETION(cqv, tag(3), 1); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + CQ_EXPECT_COMPLETION(cqv, tag(104), 1); + cq_verify(cqv); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + grpc_slice_unref(details); + + end_test(&f); + config.tear_down_data(&f); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, client_args); + grpc_channel_args_destroy(&exec_ctx, server_args); + grpc_exec_ctx_finish(&exec_ctx); + } +} + +void stream_compression_ping_pong_streaming(grpc_end2end_test_config config) { + int i; + + for (i = 1; i < 10; i++) { + test_pingpong_streaming(config, i); + } +} + +void stream_compression_ping_pong_streaming_pre_init(void) {} diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c index fd8fa7ff6c..9d562b9090 100644 --- a/test/core/end2end/tests/streaming_error_response.c +++ b/test/core/end2end/tests/streaming_error_response.c @@ -185,6 +185,19 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { CQ_EXPECT_COMPLETION(cqv, tag(103), 1); cq_verify(cqv); + if (!request_status_early) { + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload2_recv; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(2), 1); + cq_verify(cqv); + } + memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; @@ -199,21 +212,9 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL); GPR_ASSERT(GRPC_CALL_OK == error); - if (!request_status_early) { - memset(ops, 0, sizeof(ops)); - op = ops; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message.recv_message = &response_payload2_recv; - op++; - error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL); - GPR_ASSERT(GRPC_CALL_OK == error); - } - CQ_EXPECT_COMPLETION(cqv, tag(104), 1); if (request_status_early) { CQ_EXPECT_COMPLETION(cqv, tag(1), 1); - } else { - CQ_EXPECT_COMPLETION(cqv, tag(2), 1); } cq_verify(cqv); diff --git a/test/core/fling/BUILD b/test/core/fling/BUILD index b0d34e9eb0..27b2b5bec6 100644 --- a/test/core/fling/BUILD +++ b/test/core/fling/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/fling") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/handshake/BUILD b/test/core/handshake/BUILD index c93ddc8c21..8e462cfc5b 100644 --- a/test/core/handshake/BUILD +++ b/test/core/handshake/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/handshake") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 grpc_cc_test( name = "client_ssl", diff --git a/test/core/http/BUILD b/test/core/http/BUILD index 28313082c6..fffdac5e08 100644 --- a/test/core/http/BUILD +++ b/test/core/http/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/http") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD index 3e6fd37ec6..7620d1de21 100644 --- a/test/core/iomgr/BUILD +++ b/test/core/iomgr/BUILD @@ -12,19 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") -package( - default_visibility = ["//visibility:public"], # Useful for third party devs to test their io manager implementation. - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/iomgr", visibility = "public") # Useful for third party devs to test their io manager implementation. grpc_cc_library( name = "endpoint_tests", diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c index 11b45e8e08..895cc0e158 100644 --- a/test/core/iomgr/endpoint_tests.c +++ b/test/core/iomgr/endpoint_tests.c @@ -77,7 +77,7 @@ static void end_test(grpc_endpoint_test_config config) { config.clean_up(); } static grpc_slice *allocate_blocks(size_t num_bytes, size_t slice_size, size_t *num_blocks, uint8_t *current_data) { size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0); - grpc_slice *slices = gpr_malloc(sizeof(grpc_slice) * nslices); + grpc_slice *slices = (grpc_slice *)gpr_malloc(sizeof(grpc_slice) * nslices); size_t num_bytes_left = num_bytes; size_t i; size_t j; @@ -117,7 +117,8 @@ struct read_and_write_test_state { static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx, void *data, grpc_error *error) { - struct read_and_write_test_state *state = data; + struct read_and_write_test_state *state = + (struct read_and_write_test_state *)data; state->bytes_read += count_slices( state->incoming.slices, state->incoming.count, &state->current_read_data); @@ -135,7 +136,8 @@ static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx, static void read_and_write_test_write_handler(grpc_exec_ctx *exec_ctx, void *data, grpc_error *error) { - struct read_and_write_test_state *state = data; + struct read_and_write_test_state *state = + (struct read_and_write_test_state *)data; grpc_slice *slices = NULL; size_t nslices; diff --git a/test/core/iomgr/ev_epollsig_linux_test.c b/test/core/iomgr/ev_epollsig_linux_test.c index c702065d4d..cca07bf002 100644 --- a/test/core/iomgr/ev_epollsig_linux_test.c +++ b/test/core/iomgr/ev_epollsig_linux_test.c @@ -26,6 +26,7 @@ #include <string.h> #include <unistd.h> +#include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/thd.h> @@ -308,9 +309,8 @@ static void test_threading(void) { int main(int argc, char **argv) { const char *poll_strategy = NULL; grpc_test_init(argc, argv); + grpc_init(); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_iomgr_init(&exec_ctx); - grpc_iomgr_start(&exec_ctx); poll_strategy = grpc_get_poll_strategy_name(); if (poll_strategy != NULL && strcmp(poll_strategy, "epollsig") == 0) { @@ -323,8 +323,8 @@ int main(int argc, char **argv) { poll_strategy); } - grpc_iomgr_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); return 0; } #else /* defined(GRPC_LINUX_EPOLL) */ diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c index 3c61173ecd..d29b1e8e41 100644 --- a/test/core/iomgr/fd_conservation_posix_test.c +++ b/test/core/iomgr/fd_conservation_posix_test.c @@ -30,9 +30,8 @@ int main(int argc, char **argv) { grpc_endpoint_pair p; grpc_test_init(argc, argv); + grpc_init(); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_iomgr_init(&exec_ctx); - grpc_iomgr_start(&exec_ctx); /* set max # of file descriptors to a low value, and verify we can create and destroy many more than this number @@ -51,7 +50,7 @@ int main(int argc, char **argv) { grpc_resource_quota_unref(resource_quota); - grpc_iomgr_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); return 0; } diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c index 85d5d9c07f..5791d17af6 100644 --- a/test/core/iomgr/fd_posix_test.c +++ b/test/core/iomgr/fd_posix_test.c @@ -35,6 +35,7 @@ #include <sys/time.h> #include <unistd.h> +#include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/sync.h> @@ -530,8 +531,7 @@ int main(int argc, char **argv) { grpc_closure destroyed; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_test_init(argc, argv); - grpc_iomgr_init(&exec_ctx); - grpc_iomgr_start(&exec_ctx); + grpc_init(); g_pollset = gpr_zalloc(grpc_pollset_size()); grpc_pollset_init(g_pollset, &g_mu); test_grpc_fd(); @@ -541,8 +541,8 @@ int main(int argc, char **argv) { grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed); grpc_exec_ctx_flush(&exec_ctx); gpr_free(g_pollset); - grpc_iomgr_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); return 0; } diff --git a/test/core/iomgr/resolve_address_posix_test.c b/test/core/iomgr/resolve_address_posix_test.c index 9cc09ed5d3..e4be99f03c 100644 --- a/test/core/iomgr/resolve_address_posix_test.c +++ b/test/core/iomgr/resolve_address_posix_test.c @@ -21,12 +21,14 @@ #include <string.h> #include <sys/un.h> +#include <grpc/grpc.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 <grpc/support/useful.h> + #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr.h" #include "test/core/util/test_config.h" @@ -159,13 +161,12 @@ static void test_unix_socket_path_name_too_long(void) { int main(int argc, char **argv) { grpc_test_init(argc, argv); + grpc_init(); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_iomgr_init(&exec_ctx); - grpc_iomgr_start(&exec_ctx); test_unix_socket(); test_unix_socket_path_name_too_long(); grpc_executor_shutdown(&exec_ctx); - grpc_iomgr_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); return 0; } diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c index cb156ee61e..7f5c4073d8 100644 --- a/test/core/iomgr/resolve_address_test.c +++ b/test/core/iomgr/resolve_address_test.c @@ -17,6 +17,7 @@ */ #include "src/core/lib/iomgr/resolve_address.h" +#include <grpc/grpc.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/sync.h> @@ -250,9 +251,8 @@ static void test_unparseable_hostports(void) { int main(int argc, char **argv) { grpc_test_init(argc, argv); + grpc_init(); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_iomgr_init(&exec_ctx); - grpc_iomgr_start(&exec_ctx); test_localhost(); test_default_port(); test_non_numeric_default_port(); @@ -262,7 +262,7 @@ int main(int argc, char **argv) { test_invalid_ip_addresses(); test_unparseable_hostports(); grpc_executor_shutdown(&exec_ctx); - grpc_iomgr_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); return 0; } diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c index c45068e7ec..cdaa2ce2af 100644 --- a/test/core/iomgr/tcp_posix_test.c +++ b/test/core/iomgr/tcp_posix_test.c @@ -89,7 +89,7 @@ static ssize_t fill_socket(int fd) { static size_t fill_socket_partial(int fd, size_t bytes) { ssize_t write_bytes; size_t total_bytes = 0; - unsigned char *buf = gpr_malloc(bytes); + unsigned char *buf = (unsigned char *)gpr_malloc(bytes); unsigned i; for (i = 0; i < bytes; ++i) { buf[i] = (uint8_t)(i % 256); @@ -267,7 +267,7 @@ struct write_socket_state { static grpc_slice *allocate_blocks(size_t num_bytes, size_t slice_size, size_t *num_blocks, uint8_t *current_data) { size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1u : 0u); - grpc_slice *slices = gpr_malloc(sizeof(grpc_slice) * nslices); + grpc_slice *slices = (grpc_slice *)gpr_malloc(sizeof(grpc_slice) * nslices); size_t num_bytes_left = num_bytes; unsigned i, j; unsigned char *buf; @@ -301,7 +301,7 @@ static void write_done(grpc_exec_ctx *exec_ctx, } void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) { - unsigned char *buf = gpr_malloc(read_size); + unsigned char *buf = (unsigned char *)gpr_malloc(read_size); ssize_t bytes_read; size_t bytes_left = num_bytes; int flags; @@ -404,7 +404,7 @@ static void write_test(size_t num_bytes, size_t slice_size) { } void on_fd_released(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *errors) { - int *done = arg; + int *done = (int *)arg; *done = 1; GPR_ASSERT( GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL))); @@ -548,7 +548,7 @@ static grpc_endpoint_test_config configs[] = { static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) { - grpc_pollset_destroy(exec_ctx, p); + grpc_pollset_destroy(exec_ctx, (grpc_pollset *)p); } int main(int argc, char **argv) { @@ -556,7 +556,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_zalloc(grpc_pollset_size()); + g_pollset = (grpc_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/json/BUILD b/test/core/json/BUILD index 36b0897d80..3ff7918677 100644 --- a/test/core/json/BUILD +++ b/test/core/json/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/json") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/nanopb/BUILD b/test/core/nanopb/BUILD index bdb468867d..f332207e2d 100644 --- a/test/core/nanopb/BUILD +++ b/test/core/nanopb/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/nanopb") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/network_benchmarks/BUILD b/test/core/network_benchmarks/BUILD index cee23ecd51..0e15393030 100644 --- a/test/core/network_benchmarks/BUILD +++ b/test/core/network_benchmarks/BUILD @@ -12,17 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 - -package( - features = [ - "-layering_check", - "-parse_headers", - ], +grpc_package(name = "test/core/network_benchmarks", + features = ["-layering_check", "-parse_headers" ] ) +licenses(["notice"]) # Apache v2 + grpc_cc_binary( name = "low_level_ping_pong", srcs = ["low_level_ping_pong.c"], diff --git a/test/core/security/BUILD b/test/core/security/BUILD index 241ffc0591..dc41759922 100644 --- a/test/core/security/BUILD +++ b/test/core/security/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/security") load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c index 7ecd947e1f..839a05fa9b 100644 --- a/test/core/security/secure_endpoint_test.c +++ b/test/core/security/secure_endpoint_test.c @@ -36,12 +36,19 @@ static gpr_mu *g_mu; static grpc_pollset *g_pollset; static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair( - size_t slice_size, grpc_slice *leftover_slices, size_t leftover_nslices) { + size_t slice_size, grpc_slice *leftover_slices, size_t leftover_nslices, + bool use_zero_copy_protector) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; tsi_frame_protector *fake_read_protector = tsi_create_fake_frame_protector(NULL); tsi_frame_protector *fake_write_protector = tsi_create_fake_frame_protector(NULL); + tsi_zero_copy_grpc_protector *fake_read_zero_copy_protector = + use_zero_copy_protector ? tsi_create_fake_zero_copy_grpc_protector(NULL) + : NULL; + tsi_zero_copy_grpc_protector *fake_write_zero_copy_protector = + use_zero_copy_protector ? tsi_create_fake_zero_copy_grpc_protector(NULL) + : NULL; grpc_endpoint_test_fixture f; grpc_endpoint_pair tcp; @@ -54,15 +61,16 @@ static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair( grpc_endpoint_add_to_pollset(&exec_ctx, tcp.server, g_pollset); if (leftover_nslices == 0) { - f.client_ep = - grpc_secure_endpoint_create(fake_read_protector, tcp.client, NULL, 0); + f.client_ep = grpc_secure_endpoint_create(fake_read_protector, + fake_read_zero_copy_protector, + tcp.client, NULL, 0); } else { unsigned i; tsi_result result; size_t still_pending_size; size_t total_buffer_size = 8192; size_t buffer_size = total_buffer_size; - uint8_t *encrypted_buffer = gpr_malloc(buffer_size); + uint8_t *encrypted_buffer = (uint8_t *)gpr_malloc(buffer_size); uint8_t *cur = encrypted_buffer; grpc_slice encrypted_leftover; for (i = 0; i < leftover_nslices; i++) { @@ -96,31 +104,47 @@ static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair( } while (still_pending_size > 0); encrypted_leftover = grpc_slice_from_copied_buffer( (const char *)encrypted_buffer, total_buffer_size - buffer_size); - f.client_ep = grpc_secure_endpoint_create(fake_read_protector, tcp.client, - &encrypted_leftover, 1); + f.client_ep = grpc_secure_endpoint_create( + fake_read_protector, fake_read_zero_copy_protector, tcp.client, + &encrypted_leftover, 1); grpc_slice_unref(encrypted_leftover); gpr_free(encrypted_buffer); } - f.server_ep = - grpc_secure_endpoint_create(fake_write_protector, tcp.server, NULL, 0); + f.server_ep = grpc_secure_endpoint_create(fake_write_protector, + fake_write_zero_copy_protector, + tcp.server, NULL, 0); grpc_exec_ctx_finish(&exec_ctx); return f; } static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair_noleftover(size_t slice_size) { - return secure_endpoint_create_fixture_tcp_socketpair(slice_size, NULL, 0); + return secure_endpoint_create_fixture_tcp_socketpair(slice_size, NULL, 0, + false); +} + +static grpc_endpoint_test_fixture +secure_endpoint_create_fixture_tcp_socketpair_noleftover_zero_copy( + size_t slice_size) { + return secure_endpoint_create_fixture_tcp_socketpair(slice_size, NULL, 0, + true); } static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair_leftover(size_t slice_size) { grpc_slice s = grpc_slice_from_copied_string("hello world 12345678900987654321"); - grpc_endpoint_test_fixture f; + return secure_endpoint_create_fixture_tcp_socketpair(slice_size, &s, 1, + false); +} - f = secure_endpoint_create_fixture_tcp_socketpair(slice_size, &s, 1); - return f; +static grpc_endpoint_test_fixture +secure_endpoint_create_fixture_tcp_socketpair_leftover_zero_copy( + size_t slice_size) { + grpc_slice s = + grpc_slice_from_copied_string("hello world 12345678900987654321"); + return secure_endpoint_create_fixture_tcp_socketpair(slice_size, &s, 1, true); } static void clean_up(void) {} @@ -128,8 +152,14 @@ static void clean_up(void) {} static grpc_endpoint_test_config configs[] = { {"secure_ep/tcp_socketpair", secure_endpoint_create_fixture_tcp_socketpair_noleftover, clean_up}, + {"secure_ep/tcp_socketpair_zero_copy", + secure_endpoint_create_fixture_tcp_socketpair_noleftover_zero_copy, + clean_up}, {"secure_ep/tcp_socketpair_leftover", secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up}, + {"secure_ep/tcp_socketpair_leftover_zero_copy", + secure_endpoint_create_fixture_tcp_socketpair_leftover_zero_copy, + clean_up}, }; static void inc_call_ctr(grpc_exec_ctx *exec_ctx, void *arg, @@ -172,7 +202,7 @@ static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) { - grpc_pollset_destroy(exec_ctx, p); + grpc_pollset_destroy(exec_ctx, (grpc_pollset *)p); } int main(int argc, char **argv) { @@ -181,10 +211,12 @@ int main(int argc, char **argv) { grpc_test_init(argc, argv); grpc_init(); - g_pollset = gpr_zalloc(grpc_pollset_size()); + g_pollset = (grpc_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); + grpc_endpoint_tests(configs[1], g_pollset, g_mu); + test_leftover(configs[2], 1); + test_leftover(configs[3], 1); GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset, grpc_schedule_on_exec_ctx); grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed); diff --git a/test/core/slice/BUILD b/test/core/slice/BUILD index 9f2225adfb..f86a3a6082 100644 --- a/test/core/slice/BUILD +++ b/test/core/slice/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -licenses(["notice"]) # Apache v2 +grpc_package(name = "test/core/slice") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +licenses(["notice"]) # Apache v2 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/support/BUILD b/test/core/support/BUILD index 7e142c1e3f..096576e13c 100644 --- a/test/core/support/BUILD +++ b/test/core/support/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/support") grpc_cc_test( name = "alloc_test", diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c index a3c33c3fa4..bee2139477 100644 --- a/test/core/support/string_test.c +++ b/test/core/support/string_test.c @@ -279,6 +279,21 @@ static void test_memrchr(void) { GPR_ASSERT(0 == strcmp((const char *)gpr_memrchr("hello", 'l', 5), "lo")); } +static void test_is_true(void) { + LOG_TEST_NAME("test_is_true"); + + GPR_ASSERT(true == gpr_is_true("True")); + GPR_ASSERT(true == gpr_is_true("true")); + GPR_ASSERT(true == gpr_is_true("TRUE")); + GPR_ASSERT(true == gpr_is_true("Yes")); + GPR_ASSERT(true == gpr_is_true("yes")); + GPR_ASSERT(true == gpr_is_true("YES")); + GPR_ASSERT(true == gpr_is_true("1")); + GPR_ASSERT(false == gpr_is_true(NULL)); + GPR_ASSERT(false == gpr_is_true("")); + GPR_ASSERT(false == gpr_is_true("0")); +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); test_strdup(); @@ -292,5 +307,6 @@ int main(int argc, char **argv) { test_leftpad(); test_stricmp(); test_memrchr(); + test_is_true(); return 0; } diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD index 2923927412..17db7737f7 100644 --- a/test/core/surface/BUILD +++ b/test/core/surface/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/surface") grpc_cc_test( name = "alarm_test", diff --git a/test/core/surface/alarm_test.c b/test/core/surface/alarm_test.c index 6971d92074..4fd7cb93c6 100644 --- a/test/core/surface/alarm_test.c +++ b/test/core/surface/alarm_test.c @@ -48,45 +48,50 @@ static void test_alarm(void) { /* regular expiry */ grpc_event ev; void *tag = create_test_tag(); - grpc_alarm *alarm = - grpc_alarm_create(cc, grpc_timeout_seconds_to_deadline(1), tag); + grpc_alarm *alarm = grpc_alarm_create(NULL); + grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(1), tag, NULL); ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(2), NULL); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.tag == tag); GPR_ASSERT(ev.success); - grpc_alarm_destroy(alarm); + grpc_alarm_destroy(alarm, NULL); } { /* cancellation */ grpc_event ev; void *tag = create_test_tag(); - grpc_alarm *alarm = - grpc_alarm_create(cc, grpc_timeout_seconds_to_deadline(2), tag); + grpc_alarm *alarm = grpc_alarm_create(NULL); + grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(2), tag, NULL); - grpc_alarm_cancel(alarm); + grpc_alarm_cancel(alarm, NULL); ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(1), NULL); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.tag == tag); GPR_ASSERT(ev.success == 0); - grpc_alarm_destroy(alarm); + grpc_alarm_destroy(alarm, NULL); } { /* alarm_destroy before cq_next */ grpc_event ev; void *tag = create_test_tag(); - grpc_alarm *alarm = - grpc_alarm_create(cc, grpc_timeout_seconds_to_deadline(2), tag); + grpc_alarm *alarm = grpc_alarm_create(NULL); + grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(2), tag, NULL); - grpc_alarm_destroy(alarm); + grpc_alarm_destroy(alarm, NULL); ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(1), NULL); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.tag == tag); GPR_ASSERT(ev.success == 0); } + { + /* alarm_destroy before set */ + grpc_alarm *alarm = grpc_alarm_create(NULL); + grpc_alarm_destroy(alarm, NULL); + } shutdown_and_destroy(cc); } diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 3b1c53390b..0d7f68c0ad 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -36,6 +36,7 @@ #include <grpc/impl/codegen/slice.h> #include <grpc/impl/codegen/status.h> #include <grpc/impl/codegen/sync.h> +#include <grpc/impl/codegen/sync_custom.h> #include <grpc/impl/codegen/sync_generic.h> #include <grpc/load_reporting.h> #include <grpc/slice.h> @@ -53,6 +54,7 @@ #include <grpc/support/string_util.h> #include <grpc/support/subprocess.h> #include <grpc/support/sync.h> +#include <grpc/support/sync_custom.h> #include <grpc/support/sync_generic.h> #include <grpc/support/thd.h> #include <grpc/support/time.h> diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD index 040c0c35c2..12e36132c8 100644 --- a/test/core/transport/BUILD +++ b/test/core/transport/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/transport") grpc_cc_test( name = "bdp_estimator_test", diff --git a/test/core/transport/chttp2/BUILD b/test/core/transport/chttp2/BUILD index e3989f7059..6081940243 100644 --- a/test/core/transport/chttp2/BUILD +++ b/test/core/transport/chttp2/BUILD @@ -12,16 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/transport/chttp2") load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") diff --git a/test/core/tsi/BUILD b/test/core/tsi/BUILD index 3bbc50b27e..0c5509dda6 100644 --- a/test/core/tsi/BUILD +++ b/test/core/tsi/BUILD @@ -12,14 +12,59 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - features = [ - "-layering_check", - "-parse_headers", +grpc_package(name = "test/core/tsi") + +grpc_cc_library( + name = "transport_security_test_lib", + srcs = ["transport_security_test_lib.c"], + hdrs = ["transport_security_test_lib.h"], + deps = [ + "//:grpc", + "//:tsi", + ], +) + +grpc_cc_test( + name = "fake_transport_security_test", + srcs = ["fake_transport_security_test.c"], + language = "C", + deps = [ + ":transport_security_test_lib", + "//:grpc", + "//:gpr", + "//:tsi", + "//test/core/util:gpr_test_util", + ], +) + + +grpc_cc_test( + name = "ssl_transport_security_test", + srcs = ["ssl_transport_security_test.c"], + data = [ + "//src/core/tsi/test_creds:badclient.key", + "//src/core/tsi/test_creds:badclient.pem", + "//src/core/tsi/test_creds:badserver.key", + "//src/core/tsi/test_creds:badserver.pem", + "//src/core/tsi/test_creds:ca.pem", + "//src/core/tsi/test_creds:client.key", + "//src/core/tsi/test_creds:client.pem", + "//src/core/tsi/test_creds:server0.key", + "//src/core/tsi/test_creds:server0.pem", + "//src/core/tsi/test_creds:server1.key", + "//src/core/tsi/test_creds:server1.pem", + ], + language = "C", + deps = [ + ":transport_security_test_lib", + "//:grpc", + "//:gpr", + "//:tsi", + "//test/core/util:gpr_test_util", ], ) @@ -28,8 +73,8 @@ grpc_cc_test( srcs = ["transport_security_test.c"], language = "C", deps = [ - "//:gpr", "//:grpc", + "//:gpr", "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", ], diff --git a/test/core/tsi/fake_transport_security_test.c b/test/core/tsi/fake_transport_security_test.c new file mode 100644 index 0000000000..11be8802b7 --- /dev/null +++ b/test/core/tsi/fake_transport_security_test.c @@ -0,0 +1,148 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "src/core/lib/security/transport/security_connector.h" +#include "src/core/tsi/fake_transport_security.h" +#include "test/core/tsi/transport_security_test_lib.h" +#include "test/core/util/test_config.h" + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +typedef struct fake_tsi_test_fixture { + tsi_test_fixture base; +} fake_tsi_test_fixture; + +static void fake_test_setup_handshakers(tsi_test_fixture *fixture) { + fixture->client_handshaker = + tsi_create_fake_handshaker(true /* is_client. */); + fixture->server_handshaker = + tsi_create_fake_handshaker(false /* is_client. */); +} + +static void validate_handshaker_peers(tsi_handshaker_result *result) { + GPR_ASSERT(result != NULL); + tsi_peer peer; + GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) == TSI_OK); + const tsi_peer_property *property = + tsi_peer_get_property_by_name(&peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); + GPR_ASSERT(property != NULL); + GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_CERTIFICATE_TYPE, + property->value.length) == 0); + tsi_peer_destruct(&peer); +} + +static void fake_test_check_handshaker_peers(tsi_test_fixture *fixture) { + validate_handshaker_peers(fixture->client_result); + validate_handshaker_peers(fixture->server_result); +} + +static void fake_test_destruct(tsi_test_fixture *fixture) {} + +static const struct tsi_test_fixture_vtable vtable = { + fake_test_setup_handshakers, fake_test_check_handshaker_peers, + fake_test_destruct}; + +static tsi_test_fixture *fake_tsi_test_fixture_create() { + fake_tsi_test_fixture *fake_fixture = gpr_zalloc(sizeof(*fake_fixture)); + tsi_test_fixture_init(&fake_fixture->base); + fake_fixture->base.vtable = &vtable; + return &fake_fixture->base; +} + +void fake_tsi_test_do_handshake_tiny_handshake_buffer() { + tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); + fixture->handshake_buffer_size = TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void fake_tsi_test_do_handshake_small_handshake_buffer() { + tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); + fixture->handshake_buffer_size = TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void fake_tsi_test_do_handshake() { + tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void fake_tsi_test_do_round_trip_for_all_configs() { + unsigned int *bit_array = + gpr_zalloc(sizeof(unsigned int) * TSI_TEST_NUM_OF_ARGUMENTS); + const unsigned int mask = 1U << (TSI_TEST_NUM_OF_ARGUMENTS - 1); + for (unsigned int val = 0; val < TSI_TEST_NUM_OF_COMBINATIONS; val++) { + unsigned int v = val; + for (unsigned int ind = 0; ind < TSI_TEST_NUM_OF_ARGUMENTS; ind++) { + bit_array[ind] = (v & mask) ? 1 : 0; + v <<= 1; + } + tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); + fake_tsi_test_fixture *fake_fixture = (fake_tsi_test_fixture *)fixture; + tsi_test_frame_protector_config_destroy(fake_fixture->base.config); + fake_fixture->base.config = tsi_test_frame_protector_config_create( + bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4], + bit_array[5], bit_array[6], bit_array[7]); + tsi_test_do_round_trip(&fake_fixture->base); + tsi_test_fixture_destroy(fixture); + } + gpr_free(bit_array); +} + +void fake_tsi_test_do_round_trip_odd_buffer_size() { + const size_t odd_sizes[] = {1025, 2051, 4103, 8207, 16409}; + const size_t size = sizeof(odd_sizes) / sizeof(size_t); + for (size_t ind1 = 0; ind1 < size; ind1++) { + for (size_t ind2 = 0; ind2 < size; ind2++) { + for (size_t ind3 = 0; ind3 < size; ind3++) { + for (size_t ind4 = 0; ind4 < size; ind4++) { + for (size_t ind5 = 0; ind5 < size; ind5++) { + tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); + fake_tsi_test_fixture *fake_fixture = + (fake_tsi_test_fixture *)fixture; + tsi_test_frame_protector_config_set_buffer_size( + fake_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2], + odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]); + tsi_test_do_round_trip(&fake_fixture->base); + tsi_test_fixture_destroy(fixture); + } + } + } + } + } +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_init(); + fake_tsi_test_do_handshake_tiny_handshake_buffer(); + fake_tsi_test_do_handshake_small_handshake_buffer(); + fake_tsi_test_do_handshake(); + fake_tsi_test_do_round_trip_for_all_configs(); + fake_tsi_test_do_round_trip_odd_buffer_size(); + grpc_shutdown(); + return 0; +} diff --git a/test/core/tsi/ssl_transport_security_test.c b/test/core/tsi/ssl_transport_security_test.c new file mode 100644 index 0000000000..364dfa1b73 --- /dev/null +++ b/test/core/tsi/ssl_transport_security_test.c @@ -0,0 +1,558 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "src/core/lib/iomgr/load_file.h" +#include "src/core/lib/security/transport/security_connector.h" +#include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_adapter.h" +#include "test/core/tsi/transport_security_test_lib.h" +#include "test/core/util/test_config.h" + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> + +#define SSL_TSI_TEST_ALPN1 "foo" +#define SSL_TSI_TEST_ALPN2 "toto" +#define SSL_TSI_TEST_ALPN3 "baz" +#define SSL_TSI_TEST_ALPN_NUM 2 +#define SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM 2 +#define SSL_TSI_TEST_BAD_SERVER_KEY_CERT_PAIRS_NUM 1 +#define SSL_TSI_TEST_CREDENTIALS_DIR "src/core/tsi/test_creds/" + +typedef enum AlpnMode { + NO_ALPN, + ALPN_CLIENT_NO_SERVER, + ALPN_SERVER_NO_CLIENT, + ALPN_CLIENT_SERVER_OK, + ALPN_CLIENT_SERVER_MISMATCH +} AlpnMode; + +typedef struct ssl_alpn_lib { + AlpnMode alpn_mode; + char **server_alpn_protocols; + char **client_alpn_protocols; + uint16_t num_server_alpn_protocols; + uint16_t num_client_alpn_protocols; +} ssl_alpn_lib; + +typedef struct ssl_key_cert_lib { + bool use_bad_server_cert; + bool use_bad_client_cert; + char *root_cert; + tsi_ssl_pem_key_cert_pair *server_pem_key_cert_pairs; + tsi_ssl_pem_key_cert_pair *bad_server_pem_key_cert_pairs; + tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair; + tsi_ssl_pem_key_cert_pair bad_client_pem_key_cert_pair; + uint16_t server_num_key_cert_pairs; + uint16_t bad_server_num_key_cert_pairs; +} ssl_key_cert_lib; + +typedef struct ssl_tsi_test_fixture { + tsi_test_fixture base; + ssl_key_cert_lib *key_cert_lib; + ssl_alpn_lib *alpn_lib; + bool force_client_auth; + char *server_name_indication; + tsi_ssl_server_handshaker_factory *server_handshaker_factory; + tsi_ssl_client_handshaker_factory *client_handshaker_factory; +} ssl_tsi_test_fixture; + +static void ssl_test_setup_handshakers(tsi_test_fixture *fixture) { + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + GPR_ASSERT(ssl_fixture != NULL); + GPR_ASSERT(ssl_fixture->key_cert_lib != NULL); + GPR_ASSERT(ssl_fixture->alpn_lib != NULL); + ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; + ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; + /* Create client handshaker factory. */ + tsi_ssl_pem_key_cert_pair *client_key_cert_pair = NULL; + if (ssl_fixture->force_client_auth) { + client_key_cert_pair = key_cert_lib->use_bad_client_cert + ? &key_cert_lib->bad_client_pem_key_cert_pair + : &key_cert_lib->client_pem_key_cert_pair; + } + char **client_alpn_protocols = NULL; + uint16_t num_client_alpn_protocols = 0; + if (alpn_lib->alpn_mode == ALPN_CLIENT_NO_SERVER || + alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || + alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { + client_alpn_protocols = alpn_lib->client_alpn_protocols; + num_client_alpn_protocols = alpn_lib->num_client_alpn_protocols; + } + GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( + client_key_cert_pair, key_cert_lib->root_cert, NULL, + (const char **)client_alpn_protocols, + num_client_alpn_protocols, + &ssl_fixture->client_handshaker_factory) == TSI_OK); + /* Create server handshaker factory. */ + char **server_alpn_protocols = NULL; + uint16_t num_server_alpn_protocols = 0; + if (alpn_lib->alpn_mode == ALPN_SERVER_NO_CLIENT || + alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || + alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { + server_alpn_protocols = alpn_lib->server_alpn_protocols; + num_server_alpn_protocols = alpn_lib->num_server_alpn_protocols; + if (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { + num_server_alpn_protocols--; + } + } + GPR_ASSERT(tsi_create_ssl_server_handshaker_factory( + key_cert_lib->use_bad_server_cert + ? key_cert_lib->bad_server_pem_key_cert_pairs + : key_cert_lib->server_pem_key_cert_pairs, + key_cert_lib->use_bad_server_cert + ? key_cert_lib->bad_server_num_key_cert_pairs + : key_cert_lib->server_num_key_cert_pairs, + key_cert_lib->root_cert, ssl_fixture->force_client_auth, NULL, + (const char **)server_alpn_protocols, + num_server_alpn_protocols, + &ssl_fixture->server_handshaker_factory) == TSI_OK); + /* Create server and client handshakers. */ + tsi_handshaker *client_handshaker = NULL; + GPR_ASSERT(tsi_ssl_client_handshaker_factory_create_handshaker( + ssl_fixture->client_handshaker_factory, + ssl_fixture->server_name_indication, + &client_handshaker) == TSI_OK); + ssl_fixture->base.client_handshaker = + tsi_create_adapter_handshaker(client_handshaker); + tsi_handshaker *server_handshaker = NULL; + GPR_ASSERT(tsi_ssl_server_handshaker_factory_create_handshaker( + ssl_fixture->server_handshaker_factory, &server_handshaker) == + TSI_OK); + ssl_fixture->base.server_handshaker = + tsi_create_adapter_handshaker(server_handshaker); +} + +static void check_alpn(ssl_tsi_test_fixture *ssl_fixture, + const tsi_peer *peer) { + GPR_ASSERT(ssl_fixture != NULL); + GPR_ASSERT(ssl_fixture->alpn_lib != NULL); + ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; + const tsi_peer_property *alpn_property = + tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); + if (alpn_lib->alpn_mode != ALPN_CLIENT_SERVER_OK) { + GPR_ASSERT(alpn_property == NULL); + } else { + GPR_ASSERT(alpn_property != NULL); + const char *expected_match = "baz"; + GPR_ASSERT(memcmp(alpn_property->value.data, expected_match, + alpn_property->value.length) == 0); + } +} + +static const tsi_peer_property * +check_basic_authenticated_peer_and_get_common_name(const tsi_peer *peer) { + const tsi_peer_property *cert_type_property = + tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); + GPR_ASSERT(cert_type_property != NULL); + GPR_ASSERT(memcmp(cert_type_property->value.data, TSI_X509_CERTIFICATE_TYPE, + cert_type_property->value.length) == 0); + const tsi_peer_property *property = tsi_peer_get_property_by_name( + peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); + GPR_ASSERT(property != NULL); + return property; +} + +void check_server0_peer(tsi_peer *peer) { + const tsi_peer_property *property = + check_basic_authenticated_peer_and_get_common_name(peer); + const char *expected_match = "*.test.google.com.au"; + GPR_ASSERT(memcmp(property->value.data, expected_match, + property->value.length) == 0); + GPR_ASSERT(tsi_peer_get_property_by_name( + peer, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == + NULL); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.google.com.au") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.com.au") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.blah") == 0); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.bar.test.google.com.au") == + 0); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "test.google.com.au") == 0); + tsi_peer_destruct(peer); +} + +static bool check_subject_alt_name(tsi_peer *peer, const char *name) { + for (size_t i = 0; i < peer->property_count; i++) { + const tsi_peer_property *prop = &peer->properties[i]; + if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == + 0) { + if (memcmp(prop->value.data, name, prop->value.length) == 0) { + return true; + } + } + } + return false; +} + +void check_server1_peer(tsi_peer *peer) { + const tsi_peer_property *property = + check_basic_authenticated_peer_and_get_common_name(peer); + const char *expected_match = "*.test.google.com"; + GPR_ASSERT(memcmp(property->value.data, expected_match, + property->value.length) == 0); + GPR_ASSERT(check_subject_alt_name(peer, "*.test.google.fr") == 1); + GPR_ASSERT(check_subject_alt_name(peer, "waterzooi.test.google.be") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.google.fr") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.fr") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "waterzooi.test.google.be") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.youtube.com") == 1); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.foo.test.google.com") == 0); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "test.google.fr") == 0); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "tartines.test.google.be") == 0); + GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "tartines.youtube.com") == 0); + tsi_peer_destruct(peer); +} + +static void check_client_peer(ssl_tsi_test_fixture *ssl_fixture, + tsi_peer *peer) { + GPR_ASSERT(ssl_fixture != NULL); + GPR_ASSERT(ssl_fixture->alpn_lib != NULL); + ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; + if (!ssl_fixture->force_client_auth) { + GPR_ASSERT(peer->property_count == + (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0)); + } else { + const tsi_peer_property *property = + check_basic_authenticated_peer_and_get_common_name(peer); + const char *expected_match = "testclient"; + GPR_ASSERT(memcmp(property->value.data, expected_match, + property->value.length) == 0); + } + tsi_peer_destruct(peer); +} + +static void ssl_test_check_handshaker_peers(tsi_test_fixture *fixture) { + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + GPR_ASSERT(ssl_fixture != NULL); + GPR_ASSERT(ssl_fixture->key_cert_lib != NULL); + ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; + tsi_peer peer; + bool expect_success = + !(key_cert_lib->use_bad_server_cert || + (key_cert_lib->use_bad_client_cert && ssl_fixture->force_client_auth)); + if (expect_success) { + GPR_ASSERT(tsi_handshaker_result_extract_peer( + ssl_fixture->base.client_result, &peer) == TSI_OK); + check_alpn(ssl_fixture, &peer); + + if (ssl_fixture->server_name_indication != NULL) { + check_server1_peer(&peer); + } else { + check_server0_peer(&peer); + } + } else { + GPR_ASSERT(ssl_fixture->base.client_result == NULL); + } + if (expect_success) { + GPR_ASSERT(tsi_handshaker_result_extract_peer( + ssl_fixture->base.server_result, &peer) == TSI_OK); + check_alpn(ssl_fixture, &peer); + check_client_peer(ssl_fixture, &peer); + } else { + GPR_ASSERT(ssl_fixture->base.server_result == NULL); + } +} + +static void ssl_test_pem_key_cert_pair_destroy(tsi_ssl_pem_key_cert_pair kp) { + gpr_free((void *)kp.private_key); + gpr_free((void *)kp.cert_chain); +} + +static void ssl_test_destruct(tsi_test_fixture *fixture) { + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + if (ssl_fixture == NULL) { + return; + } + /* Destroy ssl_alpn_lib. */ + ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; + for (size_t i = 0; i < alpn_lib->num_server_alpn_protocols; i++) { + gpr_free(alpn_lib->server_alpn_protocols[i]); + } + gpr_free(alpn_lib->server_alpn_protocols); + for (size_t i = 0; i < alpn_lib->num_client_alpn_protocols; i++) { + gpr_free(alpn_lib->client_alpn_protocols[i]); + } + gpr_free(alpn_lib->client_alpn_protocols); + gpr_free(alpn_lib); + /* Destroy ssl_key_cert_lib. */ + ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; + for (size_t i = 0; i < key_cert_lib->server_num_key_cert_pairs; i++) { + ssl_test_pem_key_cert_pair_destroy( + key_cert_lib->server_pem_key_cert_pairs[i]); + } + gpr_free(key_cert_lib->server_pem_key_cert_pairs); + for (size_t i = 0; i < key_cert_lib->bad_server_num_key_cert_pairs; i++) { + ssl_test_pem_key_cert_pair_destroy( + key_cert_lib->bad_server_pem_key_cert_pairs[i]); + } + gpr_free(key_cert_lib->bad_server_pem_key_cert_pairs); + ssl_test_pem_key_cert_pair_destroy(key_cert_lib->client_pem_key_cert_pair); + ssl_test_pem_key_cert_pair_destroy( + key_cert_lib->bad_client_pem_key_cert_pair); + gpr_free(key_cert_lib->root_cert); + gpr_free(key_cert_lib); + /* Destroy others. */ + tsi_ssl_server_handshaker_factory_destroy( + ssl_fixture->server_handshaker_factory); + tsi_ssl_client_handshaker_factory_destroy( + ssl_fixture->client_handshaker_factory); +} + +static const struct tsi_test_fixture_vtable vtable = { + ssl_test_setup_handshakers, ssl_test_check_handshaker_peers, + ssl_test_destruct}; + +static char *load_file(const char *dir_path, const char *file_name) { + char *file_path = + gpr_zalloc(sizeof(char) * (strlen(dir_path) + strlen(file_name) + 1)); + memcpy(file_path, dir_path, strlen(dir_path)); + memcpy(file_path + strlen(dir_path), file_name, strlen(file_name)); + grpc_slice slice; + GPR_ASSERT(grpc_load_file(file_path, 1, &slice) == GRPC_ERROR_NONE); + char *data = grpc_slice_to_c_string(slice); + grpc_slice_unref(slice); + gpr_free(file_path); + return data; +} + +static tsi_test_fixture *ssl_tsi_test_fixture_create() { + ssl_tsi_test_fixture *ssl_fixture = gpr_zalloc(sizeof(*ssl_fixture)); + tsi_test_fixture_init(&ssl_fixture->base); + ssl_fixture->base.test_unused_bytes = false; + ssl_fixture->base.vtable = &vtable; + /* Create ssl_key_cert_lib. */ + ssl_key_cert_lib *key_cert_lib = gpr_zalloc(sizeof(*key_cert_lib)); + key_cert_lib->use_bad_server_cert = false; + key_cert_lib->use_bad_client_cert = false; + key_cert_lib->server_num_key_cert_pairs = + SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM; + key_cert_lib->bad_server_num_key_cert_pairs = + SSL_TSI_TEST_BAD_SERVER_KEY_CERT_PAIRS_NUM; + key_cert_lib->server_pem_key_cert_pairs = + gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) * + key_cert_lib->server_num_key_cert_pairs); + key_cert_lib->bad_server_pem_key_cert_pairs = + gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) * + key_cert_lib->bad_server_num_key_cert_pairs); + key_cert_lib->server_pem_key_cert_pairs[0].private_key = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server0.key"); + key_cert_lib->server_pem_key_cert_pairs[0].cert_chain = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server0.pem"); + key_cert_lib->server_pem_key_cert_pairs[1].private_key = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server1.key"); + key_cert_lib->server_pem_key_cert_pairs[1].cert_chain = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server1.pem"); + key_cert_lib->bad_server_pem_key_cert_pairs[0].private_key = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badserver.key"); + key_cert_lib->bad_server_pem_key_cert_pairs[0].cert_chain = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badserver.pem"); + key_cert_lib->client_pem_key_cert_pair.private_key = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.key"); + key_cert_lib->client_pem_key_cert_pair.cert_chain = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem"); + key_cert_lib->bad_client_pem_key_cert_pair.private_key = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.key"); + key_cert_lib->bad_client_pem_key_cert_pair.cert_chain = + load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem"); + key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem"); + ssl_fixture->key_cert_lib = key_cert_lib; + /* Create ssl_alpn_lib. */ + ssl_alpn_lib *alpn_lib = gpr_zalloc(sizeof(*alpn_lib)); + alpn_lib->server_alpn_protocols = + gpr_zalloc(sizeof(char *) * SSL_TSI_TEST_ALPN_NUM); + alpn_lib->client_alpn_protocols = + gpr_zalloc(sizeof(char *) * SSL_TSI_TEST_ALPN_NUM); + alpn_lib->server_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN1); + alpn_lib->server_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3); + alpn_lib->client_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN2); + alpn_lib->client_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3); + alpn_lib->num_server_alpn_protocols = SSL_TSI_TEST_ALPN_NUM; + alpn_lib->num_client_alpn_protocols = SSL_TSI_TEST_ALPN_NUM; + alpn_lib->alpn_mode = NO_ALPN; + ssl_fixture->alpn_lib = alpn_lib; + ssl_fixture->base.vtable = &vtable; + ssl_fixture->server_name_indication = NULL; + ssl_fixture->force_client_auth = false; + return &ssl_fixture->base; +} + +void ssl_tsi_test_do_handshake_tiny_handshake_buffer() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + fixture->handshake_buffer_size = TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_small_handshake_buffer() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + fixture->handshake_buffer_size = TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_with_client_authentication() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->force_client_auth = true; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() { + /* server1 cert contains "waterzooi.test.google.be" in SAN. */ + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->server_name_indication = "waterzooi.test.google.be"; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain() { + /* server1 cert contains "*.test.google.fr" in SAN. */ + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->server_name_indication = "juju.test.google.fr"; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_with_bad_server_cert() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->key_cert_lib->use_bad_server_cert = true; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_with_bad_client_cert() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->key_cert_lib->use_bad_client_cert = true; + ssl_fixture->force_client_auth = true; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_alpn_client_no_server() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_NO_SERVER; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_alpn_server_no_client() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->alpn_lib->alpn_mode = ALPN_SERVER_NO_CLIENT; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_alpn_client_server_mismatch() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_MISMATCH; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_handshake_alpn_client_server_ok() { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_OK; + tsi_test_do_handshake(fixture); + tsi_test_fixture_destroy(fixture); +} + +void ssl_tsi_test_do_round_trip_for_all_configs() { + unsigned int *bit_array = + gpr_zalloc(sizeof(unsigned int) * TSI_TEST_NUM_OF_ARGUMENTS); + const unsigned int mask = 1U << (TSI_TEST_NUM_OF_ARGUMENTS - 1); + for (unsigned int val = 0; val < TSI_TEST_NUM_OF_COMBINATIONS; val++) { + unsigned int v = val; + for (unsigned int ind = 0; ind < TSI_TEST_NUM_OF_ARGUMENTS; ind++) { + bit_array[ind] = (v & mask) ? 1 : 0; + v <<= 1; + } + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + tsi_test_frame_protector_config_destroy(ssl_fixture->base.config); + ssl_fixture->base.config = tsi_test_frame_protector_config_create( + bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4], + bit_array[5], bit_array[6], bit_array[7]); + tsi_test_do_round_trip(&ssl_fixture->base); + tsi_test_fixture_destroy(fixture); + } + gpr_free(bit_array); +} + +void ssl_tsi_test_do_round_trip_odd_buffer_size() { + const size_t odd_sizes[] = {1025, 2051, 4103, 8207, 16409}; + const size_t size = sizeof(odd_sizes) / sizeof(size_t); + for (size_t ind1 = 0; ind1 < size; ind1++) { + for (size_t ind2 = 0; ind2 < size; ind2++) { + for (size_t ind3 = 0; ind3 < size; ind3++) { + for (size_t ind4 = 0; ind4 < size; ind4++) { + for (size_t ind5 = 0; ind5 < size; ind5++) { + tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); + ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; + tsi_test_frame_protector_config_set_buffer_size( + ssl_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2], + odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]); + tsi_test_do_round_trip(&ssl_fixture->base); + tsi_test_fixture_destroy(fixture); + } + } + } + } + } +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_init(); + ssl_tsi_test_do_handshake_tiny_handshake_buffer(); + ssl_tsi_test_do_handshake_small_handshake_buffer(); + ssl_tsi_test_do_handshake(); + ssl_tsi_test_do_handshake_with_client_authentication(); + ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain(); + ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain(); + ssl_tsi_test_do_handshake_with_bad_server_cert(); + ssl_tsi_test_do_handshake_with_bad_client_cert(); + ssl_tsi_test_do_handshake_alpn_client_no_server(); + ssl_tsi_test_do_handshake_alpn_server_no_client(); + ssl_tsi_test_do_handshake_alpn_client_server_mismatch(); + ssl_tsi_test_do_handshake_alpn_client_server_ok(); + ssl_tsi_test_do_round_trip_for_all_configs(); + ssl_tsi_test_do_round_trip_odd_buffer_size(); + grpc_shutdown(); + return 0; +} diff --git a/test/core/tsi/transport_security_test_lib.c b/test/core/tsi/transport_security_test_lib.c new file mode 100644 index 0000000000..7d66e110f2 --- /dev/null +++ b/test/core/tsi/transport_security_test_lib.c @@ -0,0 +1,550 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include "src/core/lib/security/transport/tsi_error.h" +#include "test/core/tsi/transport_security_test_lib.h" + +typedef struct handshaker_args { + tsi_test_fixture *fixture; + unsigned char *handshake_buffer; + size_t handshake_buffer_size; + bool is_client; + bool transferred_data; + bool appended_unused_bytes; + grpc_error *error; +} handshaker_args; + +static handshaker_args *handshaker_args_create(tsi_test_fixture *fixture, + bool is_client) { + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(fixture->config != NULL); + handshaker_args *args = gpr_zalloc(sizeof(*args)); + args->fixture = fixture; + args->handshake_buffer_size = fixture->handshake_buffer_size; + args->handshake_buffer = gpr_zalloc(args->handshake_buffer_size); + args->is_client = is_client; + args->error = GRPC_ERROR_NONE; + return args; +} + +static void handshaker_args_destroy(handshaker_args *args) { + gpr_free(args->handshake_buffer); + GRPC_ERROR_UNREF(args->error); + gpr_free(args); +} + +static void do_handshaker_next(handshaker_args *args); + +static void setup_handshakers(tsi_test_fixture *fixture) { + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(fixture->vtable != NULL); + GPR_ASSERT(fixture->vtable->setup_handshakers != NULL); + fixture->vtable->setup_handshakers(fixture); +} + +static void check_unused_bytes(tsi_test_fixture *fixture) { + tsi_handshaker_result *result_with_unused_bytes = + fixture->has_client_finished_first ? fixture->server_result + : fixture->client_result; + tsi_handshaker_result *result_without_unused_bytes = + fixture->has_client_finished_first ? fixture->client_result + : fixture->server_result; + const unsigned char *bytes = NULL; + size_t bytes_size = 0; + GPR_ASSERT(tsi_handshaker_result_get_unused_bytes( + result_with_unused_bytes, &bytes, &bytes_size) == TSI_OK); + GPR_ASSERT(bytes_size == strlen(TSI_TEST_UNUSED_BYTES)); + GPR_ASSERT(memcmp(bytes, TSI_TEST_UNUSED_BYTES, bytes_size) == 0); + GPR_ASSERT(tsi_handshaker_result_get_unused_bytes( + result_without_unused_bytes, &bytes, &bytes_size) == TSI_OK); + GPR_ASSERT(bytes_size == 0); + GPR_ASSERT(bytes == NULL); +} + +static void check_handshake_results(tsi_test_fixture *fixture) { + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(fixture->vtable != NULL); + GPR_ASSERT(fixture->vtable->check_handshaker_peers != NULL); + /* Check handshaker peers. */ + fixture->vtable->check_handshaker_peers(fixture); + /* Check unused bytes. */ + if (fixture->test_unused_bytes) { + if (fixture->server_result != NULL && fixture->client_result != NULL) { + check_unused_bytes(fixture); + } + fixture->bytes_written_to_server_channel = 0; + fixture->bytes_written_to_client_channel = 0; + fixture->bytes_read_from_client_channel = 0; + fixture->bytes_read_from_server_channel = 0; + } +} + +static void send_bytes_to_peer(tsi_test_fixture *fixture, + const unsigned char *buf, size_t buf_size, + bool is_client) { + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(buf != NULL); + uint8_t *channel = + is_client ? fixture->server_channel : fixture->client_channel; + GPR_ASSERT(channel != NULL); + size_t *bytes_written = is_client ? &fixture->bytes_written_to_server_channel + : &fixture->bytes_written_to_client_channel; + GPR_ASSERT(bytes_written != NULL); + GPR_ASSERT(*bytes_written + buf_size <= TSI_TEST_DEFAULT_CHANNEL_SIZE); + /* Write data to channel. */ + memcpy(channel + *bytes_written, buf, buf_size); + *bytes_written += buf_size; +} + +static void maybe_append_unused_bytes(handshaker_args *args) { + GPR_ASSERT(args != NULL); + GPR_ASSERT(args->fixture != NULL); + tsi_test_fixture *fixture = args->fixture; + if (fixture->test_unused_bytes && !args->appended_unused_bytes) { + args->appended_unused_bytes = true; + send_bytes_to_peer(fixture, (const unsigned char *)TSI_TEST_UNUSED_BYTES, + strlen(TSI_TEST_UNUSED_BYTES), args->is_client); + if (fixture->client_result != NULL && fixture->server_result == NULL) { + fixture->has_client_finished_first = true; + } + } +} + +static void receive_bytes_from_peer(tsi_test_fixture *fixture, + unsigned char **buf, size_t *buf_size, + bool is_client) { + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(*buf != NULL); + GPR_ASSERT(buf_size != NULL); + uint8_t *channel = + is_client ? fixture->client_channel : fixture->server_channel; + GPR_ASSERT(channel != NULL); + size_t *bytes_read = is_client ? &fixture->bytes_read_from_client_channel + : &fixture->bytes_read_from_server_channel; + size_t *bytes_written = is_client ? &fixture->bytes_written_to_client_channel + : &fixture->bytes_written_to_server_channel; + GPR_ASSERT(bytes_read != NULL); + GPR_ASSERT(bytes_written != NULL); + size_t to_read = *buf_size < *bytes_written - *bytes_read + ? *buf_size + : *bytes_written - *bytes_read; + /* Read data from channel. */ + memcpy(*buf, channel + *bytes_read, to_read); + *buf_size = to_read; + *bytes_read += to_read; +} + +static void send_message_to_peer(tsi_test_fixture *fixture, + tsi_frame_protector *protector, + bool is_client) { + /* Initialization. */ + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(fixture->config != NULL); + GPR_ASSERT(protector != NULL); + tsi_test_frame_protector_config *config = fixture->config; + unsigned char *protected_buffer = gpr_zalloc(config->protected_buffer_size); + size_t message_size = + is_client ? config->client_message_size : config->server_message_size; + uint8_t *message = + is_client ? config->client_message : config->server_message; + GPR_ASSERT(message != NULL); + const unsigned char *message_bytes = (const unsigned char *)message; + tsi_result result = TSI_OK; + /* Do protect and send protected data to peer. */ + while (message_size > 0 && result == TSI_OK) { + size_t protected_buffer_size_to_send = config->protected_buffer_size; + size_t processed_message_size = message_size; + /* Do protect. */ + result = tsi_frame_protector_protect( + protector, message_bytes, &processed_message_size, protected_buffer, + &protected_buffer_size_to_send); + GPR_ASSERT(result == TSI_OK); + /* Send protected data to peer. */ + send_bytes_to_peer(fixture, protected_buffer, protected_buffer_size_to_send, + is_client); + message_bytes += processed_message_size; + message_size -= processed_message_size; + /* Flush if we're done. */ + if (message_size == 0) { + size_t still_pending_size; + do { + protected_buffer_size_to_send = config->protected_buffer_size; + result = tsi_frame_protector_protect_flush( + protector, protected_buffer, &protected_buffer_size_to_send, + &still_pending_size); + GPR_ASSERT(result == TSI_OK); + send_bytes_to_peer(fixture, protected_buffer, + protected_buffer_size_to_send, is_client); + } while (still_pending_size > 0 && result == TSI_OK); + GPR_ASSERT(result == TSI_OK); + } + } + GPR_ASSERT(result == TSI_OK); + gpr_free(protected_buffer); +} + +static void receive_message_from_peer(tsi_test_fixture *fixture, + tsi_frame_protector *protector, + unsigned char *message, + size_t *bytes_received, bool is_client) { + /* Initialization. */ + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(protector != NULL); + GPR_ASSERT(message != NULL); + GPR_ASSERT(bytes_received != NULL); + GPR_ASSERT(fixture->config != NULL); + tsi_test_frame_protector_config *config = fixture->config; + size_t read_offset = 0; + size_t message_offset = 0; + size_t read_from_peer_size = 0; + tsi_result result = TSI_OK; + bool done = false; + unsigned char *read_buffer = gpr_zalloc(config->read_buffer_allocated_size); + unsigned char *message_buffer = + gpr_zalloc(config->message_buffer_allocated_size); + /* Do unprotect on data received from peer. */ + while (!done && result == TSI_OK) { + /* Receive data from peer. */ + if (read_from_peer_size == 0) { + read_from_peer_size = config->read_buffer_allocated_size; + receive_bytes_from_peer(fixture, &read_buffer, &read_from_peer_size, + is_client); + read_offset = 0; + } + if (read_from_peer_size == 0) { + done = true; + } + /* Do unprotect. */ + size_t message_buffer_size; + do { + message_buffer_size = config->message_buffer_allocated_size; + size_t processed_size = read_from_peer_size; + result = tsi_frame_protector_unprotect( + protector, read_buffer + read_offset, &processed_size, message_buffer, + &message_buffer_size); + GPR_ASSERT(result == TSI_OK); + if (message_buffer_size > 0) { + memcpy(message + message_offset, message_buffer, message_buffer_size); + message_offset += message_buffer_size; + } + read_offset += processed_size; + read_from_peer_size -= processed_size; + } while ((read_from_peer_size > 0 || message_buffer_size > 0) && + result == TSI_OK); + GPR_ASSERT(result == TSI_OK); + } + GPR_ASSERT(result == TSI_OK); + *bytes_received = message_offset; + gpr_free(read_buffer); + gpr_free(message_buffer); +} + +grpc_error *on_handshake_next_done(tsi_result result, void *user_data, + const unsigned char *bytes_to_send, + size_t bytes_to_send_size, + tsi_handshaker_result *handshaker_result) { + handshaker_args *args = (handshaker_args *)user_data; + GPR_ASSERT(args != NULL); + GPR_ASSERT(args->fixture != NULL); + tsi_test_fixture *fixture = args->fixture; + grpc_error *error = GRPC_ERROR_NONE; + /* Read more data if we need to. */ + if (result == TSI_INCOMPLETE_DATA) { + GPR_ASSERT(bytes_to_send_size == 0); + return error; + } + if (result != TSI_OK) { + return grpc_set_tsi_error_result( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); + } + /* Update handshaker result. */ + if (handshaker_result != NULL) { + tsi_handshaker_result **result_to_write = + args->is_client ? &fixture->client_result : &fixture->server_result; + GPR_ASSERT(*result_to_write == NULL); + *result_to_write = handshaker_result; + } + /* Send data to peer, if needed. */ + if (bytes_to_send_size > 0) { + send_bytes_to_peer(args->fixture, bytes_to_send, bytes_to_send_size, + args->is_client); + args->transferred_data = true; + } + if (handshaker_result != NULL) { + maybe_append_unused_bytes(args); + } + return error; +} + +static void on_handshake_next_done_wrapper( + tsi_result result, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) { + handshaker_args *args = (handshaker_args *)user_data; + args->error = on_handshake_next_done(result, user_data, bytes_to_send, + bytes_to_send_size, handshaker_result); +} + +static bool is_handshake_finished_properly(handshaker_args *args) { + GPR_ASSERT(args != NULL); + GPR_ASSERT(args->fixture != NULL); + tsi_test_fixture *fixture = args->fixture; + if ((args->is_client && fixture->client_result != NULL) || + (!args->is_client && fixture->server_result != NULL)) { + return true; + } + return false; +} + +static void do_handshaker_next(handshaker_args *args) { + /* Initialization. */ + GPR_ASSERT(args != NULL); + GPR_ASSERT(args->fixture != NULL); + tsi_test_fixture *fixture = args->fixture; + tsi_handshaker *handshaker = + args->is_client ? fixture->client_handshaker : fixture->server_handshaker; + if (is_handshake_finished_properly(args)) { + return; + } + tsi_handshaker_result *handshaker_result = NULL; + unsigned char *bytes_to_send = NULL; + size_t bytes_to_send_size = 0; + /* Receive data from peer, if available. */ + size_t buf_size = args->handshake_buffer_size; + receive_bytes_from_peer(args->fixture, &args->handshake_buffer, &buf_size, + args->is_client); + if (buf_size > 0) { + args->transferred_data = true; + } + /* Peform handshaker next. */ + tsi_result result = tsi_handshaker_next( + handshaker, args->handshake_buffer, buf_size, + (const unsigned char **)&bytes_to_send, &bytes_to_send_size, + &handshaker_result, &on_handshake_next_done_wrapper, args); + if (result != TSI_ASYNC) { + args->error = on_handshake_next_done(result, args, bytes_to_send, + bytes_to_send_size, handshaker_result); + } +} + +void tsi_test_do_handshake(tsi_test_fixture *fixture) { + /* Initializaiton. */ + setup_handshakers(fixture); + handshaker_args *client_args = + handshaker_args_create(fixture, true /* is_client */); + handshaker_args *server_args = + handshaker_args_create(fixture, false /* is_client */); + /* Do handshake. */ + do { + client_args->transferred_data = false; + server_args->transferred_data = false; + do_handshaker_next(client_args); + if (client_args->error != GRPC_ERROR_NONE) { + break; + } + do_handshaker_next(server_args); + if (server_args->error != GRPC_ERROR_NONE) { + break; + } + GPR_ASSERT(client_args->transferred_data || server_args->transferred_data); + } while (fixture->client_result == NULL || fixture->server_result == NULL); + /* Verify handshake results. */ + check_handshake_results(fixture); + /* Cleanup. */ + handshaker_args_destroy(client_args); + handshaker_args_destroy(server_args); +} + +void tsi_test_do_round_trip(tsi_test_fixture *fixture) { + /* Initialization. */ + GPR_ASSERT(fixture != NULL); + GPR_ASSERT(fixture->config != NULL); + tsi_test_frame_protector_config *config = fixture->config; + tsi_frame_protector *client_frame_protector = NULL; + tsi_frame_protector *server_frame_protector = NULL; + /* Perform handshake. */ + tsi_test_do_handshake(fixture); + /* Create frame protectors.*/ + size_t client_max_output_protected_frame_size = + config->client_max_output_protected_frame_size; + GPR_ASSERT(tsi_handshaker_result_create_frame_protector( + fixture->client_result, + client_max_output_protected_frame_size == 0 + ? NULL + : &client_max_output_protected_frame_size, + &client_frame_protector) == TSI_OK); + size_t server_max_output_protected_frame_size = + config->server_max_output_protected_frame_size; + GPR_ASSERT(tsi_handshaker_result_create_frame_protector( + fixture->server_result, + server_max_output_protected_frame_size == 0 + ? NULL + : &server_max_output_protected_frame_size, + &server_frame_protector) == TSI_OK); + /* Client sends a message to server. */ + send_message_to_peer(fixture, client_frame_protector, true /* is_client */); + unsigned char *server_received_message = + gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); + size_t server_received_message_size = 0; + receive_message_from_peer( + fixture, server_frame_protector, server_received_message, + &server_received_message_size, false /* is_client */); + GPR_ASSERT(config->client_message_size == server_received_message_size); + GPR_ASSERT(memcmp(config->client_message, server_received_message, + server_received_message_size) == 0); + /* Server sends a message to client. */ + send_message_to_peer(fixture, server_frame_protector, false /* is_client */); + unsigned char *client_received_message = + gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); + size_t client_received_message_size = 0; + receive_message_from_peer( + fixture, client_frame_protector, client_received_message, + &client_received_message_size, true /* is_client */); + GPR_ASSERT(config->server_message_size == client_received_message_size); + GPR_ASSERT(memcmp(config->server_message, client_received_message, + client_received_message_size) == 0); + /* Destroy server and client frame protectors. */ + tsi_frame_protector_destroy(client_frame_protector); + tsi_frame_protector_destroy(server_frame_protector); + gpr_free(server_received_message); + gpr_free(client_received_message); +} + +static unsigned char *generate_random_message(size_t size) { + size_t i; + unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + unsigned char *output = gpr_zalloc(sizeof(unsigned char) * size); + for (i = 0; i < size - 1; ++i) { + output[i] = chars[rand() % (int)(sizeof(chars) - 1)]; + } + return output; +} + +tsi_test_frame_protector_config *tsi_test_frame_protector_config_create( + bool use_default_read_buffer_allocated_size, + bool use_default_message_buffer_allocated_size, + bool use_default_protected_buffer_size, bool use_default_client_message, + bool use_default_server_message, + bool use_default_client_max_output_protected_frame_size, + bool use_default_server_max_output_protected_frame_size, + bool use_default_handshake_buffer_size) { + tsi_test_frame_protector_config *config = gpr_zalloc(sizeof(*config)); + /* Set the value for read_buffer_allocated_size. */ + config->read_buffer_allocated_size = + use_default_read_buffer_allocated_size + ? TSI_TEST_DEFAULT_BUFFER_SIZE + : TSI_TEST_SMALL_READ_BUFFER_ALLOCATED_SIZE; + /* Set the value for message_buffer_allocated_size. */ + config->message_buffer_allocated_size = + use_default_message_buffer_allocated_size + ? TSI_TEST_DEFAULT_BUFFER_SIZE + : TSI_TEST_SMALL_MESSAGE_BUFFER_ALLOCATED_SIZE; + /* Set the value for protected_buffer_size. */ + config->protected_buffer_size = use_default_protected_buffer_size + ? TSI_TEST_DEFAULT_PROTECTED_BUFFER_SIZE + : TSI_TEST_SMALL_PROTECTED_BUFFER_SIZE; + /* Set the value for client message. */ + config->client_message_size = use_default_client_message + ? TSI_TEST_BIG_MESSAGE_SIZE + : TSI_TEST_SMALL_MESSAGE_SIZE; + config->client_message = + use_default_client_message + ? generate_random_message(TSI_TEST_BIG_MESSAGE_SIZE) + : generate_random_message(TSI_TEST_SMALL_MESSAGE_SIZE); + /* Set the value for server message. */ + config->server_message_size = use_default_server_message + ? TSI_TEST_BIG_MESSAGE_SIZE + : TSI_TEST_SMALL_MESSAGE_SIZE; + config->server_message = + use_default_server_message + ? generate_random_message(TSI_TEST_BIG_MESSAGE_SIZE) + : generate_random_message(TSI_TEST_SMALL_MESSAGE_SIZE); + /* Set the value for client max_output_protected_frame_size. + If it is 0, we pass NULL to tsi_handshaker_result_create_frame_protector(), + which then uses default protected frame size for it. */ + config->client_max_output_protected_frame_size = + use_default_client_max_output_protected_frame_size + ? 0 + : TSI_TEST_SMALL_CLIENT_MAX_OUTPUT_PROTECTED_FRAME_SIZE; + /* Set the value for server max_output_protected_frame_size. + If it is 0, we pass NULL to tsi_handshaker_result_create_frame_protector(), + which then uses default protected frame size for it. */ + config->server_max_output_protected_frame_size = + use_default_server_max_output_protected_frame_size + ? 0 + : TSI_TEST_SMALL_SERVER_MAX_OUTPUT_PROTECTED_FRAME_SIZE; + return config; +} + +void tsi_test_frame_protector_config_set_buffer_size( + tsi_test_frame_protector_config *config, size_t read_buffer_allocated_size, + size_t message_buffer_allocated_size, size_t protected_buffer_size, + size_t client_max_output_protected_frame_size, + size_t server_max_output_protected_frame_size) { + GPR_ASSERT(config != NULL); + config->read_buffer_allocated_size = read_buffer_allocated_size; + config->message_buffer_allocated_size = message_buffer_allocated_size; + config->protected_buffer_size = protected_buffer_size; + config->client_max_output_protected_frame_size = + client_max_output_protected_frame_size; + config->server_max_output_protected_frame_size = + server_max_output_protected_frame_size; +} + +void tsi_test_frame_protector_config_destroy( + tsi_test_frame_protector_config *config) { + GPR_ASSERT(config != NULL); + gpr_free(config->client_message); + gpr_free(config->server_message); + gpr_free(config); +} + +void tsi_test_fixture_init(tsi_test_fixture *fixture) { + fixture->config = tsi_test_frame_protector_config_create( + true, true, true, true, true, true, true, true); + fixture->handshake_buffer_size = TSI_TEST_DEFAULT_BUFFER_SIZE; + fixture->client_channel = gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); + fixture->server_channel = gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); + fixture->bytes_written_to_client_channel = 0; + fixture->bytes_written_to_server_channel = 0; + fixture->bytes_read_from_client_channel = 0; + fixture->bytes_read_from_server_channel = 0; + fixture->test_unused_bytes = true; + fixture->has_client_finished_first = false; +} + +void tsi_test_fixture_destroy(tsi_test_fixture *fixture) { + GPR_ASSERT(fixture != NULL); + tsi_test_frame_protector_config_destroy(fixture->config); + tsi_handshaker_destroy(fixture->client_handshaker); + tsi_handshaker_destroy(fixture->server_handshaker); + tsi_handshaker_result_destroy(fixture->client_result); + tsi_handshaker_result_destroy(fixture->server_result); + gpr_free(fixture->client_channel); + gpr_free(fixture->server_channel); + GPR_ASSERT(fixture->vtable != NULL); + GPR_ASSERT(fixture->vtable->destruct != NULL); + fixture->vtable->destruct(fixture); + gpr_free(fixture); +} diff --git a/test/core/tsi/transport_security_test_lib.h b/test/core/tsi/transport_security_test_lib.h new file mode 100644 index 0000000000..8ae2024ee4 --- /dev/null +++ b/test/core/tsi/transport_security_test_lib.h @@ -0,0 +1,165 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_ +#define GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_ + +#include "src/core/tsi/transport_security_interface.h" + +#define TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE 32 +#define TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE 128 +#define TSI_TEST_SMALL_READ_BUFFER_ALLOCATED_SIZE 41 +#define TSI_TEST_SMALL_PROTECTED_BUFFER_SIZE 37 +#define TSI_TEST_SMALL_MESSAGE_BUFFER_ALLOCATED_SIZE 42 +#define TSI_TEST_SMALL_CLIENT_MAX_OUTPUT_PROTECTED_FRAME_SIZE 39 +#define TSI_TEST_SMALL_SERVER_MAX_OUTPUT_PROTECTED_FRAME_SIZE 43 +#define TSI_TEST_DEFAULT_BUFFER_SIZE 4096 +#define TSI_TEST_DEFAULT_PROTECTED_BUFFER_SIZE 16384 +#define TSI_TEST_DEFAULT_CHANNEL_SIZE 32768 +#define TSI_TEST_BIG_MESSAGE_SIZE 17000 +#define TSI_TEST_SMALL_MESSAGE_SIZE 10 +#define TSI_TEST_NUM_OF_ARGUMENTS 8 +#define TSI_TEST_NUM_OF_COMBINATIONS 256 +#define TSI_TEST_UNUSED_BYTES "HELLO GOOGLE" + +/* --- tsi_test_fixture object --- + The tests for specific TSI implementations should create their own + custom "subclass" of this fixture, which wraps all information + that will be used to test correctness of TSI handshakes and frame + protect/unprotect operations with respect to TSI implementations. */ +typedef struct tsi_test_fixture tsi_test_fixture; + +/* --- tsi_test_frame_protector_config object --- + + This object is used to configure different parameters of TSI frame protector + APIs. */ +typedef struct tsi_test_frame_protector_config tsi_test_frame_protector_config; + +/* V-table for tsi_test_fixture operations that are implemented differently in + different TSI implementations. */ +typedef struct tsi_test_fixture_vtable { + void (*setup_handshakers)(tsi_test_fixture *fixture); + void (*check_handshaker_peers)(tsi_test_fixture *fixture); + void (*destruct)(tsi_test_fixture *fixture); +} tranport_security_test_vtable; + +struct tsi_test_fixture { + const struct tsi_test_fixture_vtable *vtable; + /* client/server TSI handshaker used to perform TSI handshakes, and will get + instantiated during the call to setup_handshakers. */ + tsi_handshaker *client_handshaker; + tsi_handshaker *server_handshaker; + /* client/server TSI handshaker results used to store the result of TSI + handshake. If the handshake fails, the result will store NULL upon + finishing the handshake. */ + tsi_handshaker_result *client_result; + tsi_handshaker_result *server_result; + /* size of buffer used to store data received from the peer. */ + size_t handshake_buffer_size; + /* simulated channels between client and server. If the server (client) + wants to send data to the client (server), he will write data to + client_channel (server_channel), which will be read by client (server). */ + uint8_t *client_channel; + uint8_t *server_channel; + /* size of data written to the client/server channel. */ + size_t bytes_written_to_client_channel; + size_t bytes_written_to_server_channel; + /* size of data read from the client/server channel */ + size_t bytes_read_from_client_channel; + size_t bytes_read_from_server_channel; + /* tsi_test_frame_protector_config instance */ + tsi_test_frame_protector_config *config; + /* a flag indicating if client has finished TSI handshake first (i.e., before + server). + The flag should be referred if and only if TSI handshake finishes + successfully. */ + bool has_client_finished_first; + /* a flag indicating whether to test tsi_handshaker_result_get_unused_bytes() + for TSI implementation. This field is true by default, and false + for SSL TSI implementation due to grpc issue #12164 + (https://github.com/grpc/grpc/issues/12164). + */ + bool test_unused_bytes; +}; + +struct tsi_test_frame_protector_config { + /* size of buffer used to store protected frames to be unprotected. */ + size_t read_buffer_allocated_size; + /* size of buffer used to store bytes resulted from unprotect operations. */ + size_t message_buffer_allocated_size; + /* size of buffer used to store frames resulted from protect operations. */ + size_t protected_buffer_size; + /* size of client/server maximum frame size. */ + size_t client_max_output_protected_frame_size; + size_t server_max_output_protected_frame_size; + /* pointer that points to client/server message to be protected. */ + uint8_t *client_message; + uint8_t *server_message; + /* size of client/server message. */ + size_t client_message_size; + size_t server_message_size; +}; + +/* This method creates a tsi_test_frame_protector_config instance. Each + parameter of this function is a boolean value indicating whether to set the + corresponding parameter with a default value or not. If it's false, it will + be set with a specific value which is usually much smaller than the default. + Both values are defined with #define directive. */ +tsi_test_frame_protector_config *tsi_test_frame_protector_config_create( + bool use_default_read_buffer_allocated_size, + bool use_default_message_buffer_allocated_size, + bool use_default_protected_buffer_size, bool use_default_client_message, + bool use_default_server_message, + bool use_default_client_max_output_protected_frame_size, + bool use_default_server_max_output_protected_frame_size, + bool use_default_handshake_buffer_size); + +/* This method sets different buffer and frame sizes of a + tsi_test_frame_protector_config instance with user provided values. */ +void tsi_test_frame_protector_config_set_buffer_size( + tsi_test_frame_protector_config *config, size_t read_buffer_allocated_size, + size_t message_buffer_allocated_size, size_t protected_buffer_size, + size_t client_max_output_protected_frame_size, + size_t server_max_output_protected_frame_size); + +/* This method destroys a tsi_test_frame_protector_config instance. */ +void tsi_test_frame_protector_config_destroy( + tsi_test_frame_protector_config *config); + +/* This method initializes members of tsi_test_fixture instance. + Note that the struct instance should be allocated before making + this call. */ +void tsi_test_fixture_init(tsi_test_fixture *fixture); + +/* This method destroys a tsi_test_fixture instance. Note that the + fixture intance must be dynamically allocated and will be freed by + this function. */ +void tsi_test_fixture_destroy(tsi_test_fixture *fixture); + +/* This method performs a full TSI handshake between a client and a server. + Note that the test library will implement the new TSI handshaker API to + perform handshakes. */ +void tsi_test_do_handshake(tsi_test_fixture *fixture); + +/* This method performs a round trip test between the client and the server. + That is, the client sends a protected message to a server who receives the + message, and unprotects it. The same operation is triggered again with + the client and server switching its role. */ +void tsi_test_do_round_trip(tsi_test_fixture *fixture); + +#endif // GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_ diff --git a/test/core/util/BUILD b/test/core/util/BUILD index 1268c2cd10..10eefe159a 100644 --- a/test/core/util/BUILD +++ b/test/core/util/BUILD @@ -12,17 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") licenses(["notice"]) # Apache v2 -package( - default_visibility = ["//visibility:public"], - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/core/util", visibility = "public") grpc_cc_library( name = "gpr_test_util", diff --git a/test/core/util/memory_counters.c b/test/core/util/memory_counters.c index b898057034..9fb3ffe095 100644 --- a/test/core/util/memory_counters.c +++ b/test/core/util/memory_counters.c @@ -48,13 +48,13 @@ static void *guard_malloc(size_t 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_t *)g_old_allocs.malloc_fn(size + sizeof(size)); *ptr++ = size; return ptr; } static void *guard_realloc(void *vptr, size_t size) { - size_t *ptr = vptr; + size_t *ptr = (size_t *)vptr; if (vptr == NULL) { return guard_malloc(size); } @@ -67,13 +67,13 @@ static void *guard_realloc(void *vptr, size_t 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_t *)g_old_allocs.realloc_fn(ptr, size + sizeof(size)); *ptr++ = size; return ptr; } static void guard_free(void *vptr) { - size_t *ptr = vptr; + size_t *ptr = (size_t *)vptr; if (!vptr) return; --ptr; NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr); diff --git a/test/core/util/mock_endpoint.c b/test/core/util/mock_endpoint.c index 40cf0a2652..bd386b2148 100644 --- a/test/core/util/mock_endpoint.c +++ b/test/core/util/mock_endpoint.c @@ -110,7 +110,7 @@ static const grpc_endpoint_vtable vtable = { grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(grpc_slice slice), grpc_resource_quota *resource_quota) { - grpc_mock_endpoint *m = gpr_malloc(sizeof(*m)); + grpc_mock_endpoint *m = (grpc_mock_endpoint *)gpr_malloc(sizeof(*m)); m->base.vtable = &vtable; char *name; gpr_asprintf(&name, "mock_endpoint_%" PRIxPTR, (intptr_t)m); diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c index eef1f163f0..38a47584d5 100644 --- a/test/core/util/passthru_endpoint.c +++ b/test/core/util/passthru_endpoint.c @@ -183,7 +183,7 @@ void grpc_passthru_endpoint_create(grpc_endpoint **client, grpc_endpoint **server, grpc_resource_quota *resource_quota, grpc_passthru_endpoint_stats *stats) { - passthru_endpoint *m = gpr_malloc(sizeof(*m)); + passthru_endpoint *m = (passthru_endpoint *)gpr_malloc(sizeof(*m)); m->halves = 2; m->shutdown = 0; m->stats = stats == NULL ? &m->dummy_stats : stats; diff --git a/test/core/util/port.c b/test/core/util/port.c index b1fc722858..61f2e5018f 100644 --- a/test/core/util/port.c +++ b/test/core/util/port.c @@ -75,7 +75,8 @@ static void chose_port(int port) { atexit(free_chosen_ports); } num_chosen_ports++; - chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports); + chosen_ports = + (int *)gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports); chosen_ports[num_chosen_ports - 1] = port; } diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c index d5739effb3..851c50941e 100644 --- a/test/core/util/port_server_client.c +++ b/test/core/util/port_server_client.c @@ -42,14 +42,14 @@ typedef struct freereq { static void destroy_pops_and_shutdown(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) { - grpc_pollset *pollset = grpc_polling_entity_pollset(p); + grpc_pollset *pollset = grpc_polling_entity_pollset((grpc_polling_entity *)p); grpc_pollset_destroy(exec_ctx, pollset); gpr_free(pollset); } static void freed_port_from_server(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - freereq *pr = arg; + freereq *pr = (freereq *)arg; gpr_mu_lock(pr->mu); pr->done = 1; GRPC_LOG_IF_ERROR( @@ -73,7 +73,7 @@ void grpc_free_port_using_server(int port) { memset(&req, 0, sizeof(req)); memset(&rsp, 0, sizeof(rsp)); - grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size()); + grpc_pollset *pollset = (grpc_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, @@ -130,7 +130,7 @@ static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { size_t i; int port = 0; - portreq *pr = arg; + portreq *pr = (portreq *)arg; int failed = 0; grpc_httpcli_response *response = &pr->response; @@ -204,7 +204,7 @@ int grpc_pick_port_using_server(void) { memset(&pr, 0, sizeof(pr)); memset(&req, 0, sizeof(req)); - grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size()); + grpc_pollset *pollset = (grpc_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, diff --git a/test/core/util/slice_splitter.c b/test/core/util/slice_splitter.c index f6d892f166..6fcef9acce 100644 --- a/test/core/util/slice_splitter.c +++ b/test/core/util/slice_splitter.c @@ -44,7 +44,8 @@ void grpc_split_slices(grpc_slice_split_mode mode, grpc_slice *src_slices, switch (mode) { case GRPC_SLICE_SPLIT_IDENTITY: *dst_slice_count = src_slice_count; - *dst_slices = gpr_malloc(sizeof(grpc_slice) * src_slice_count); + *dst_slices = + (grpc_slice *)gpr_malloc(sizeof(grpc_slice) * src_slice_count); for (i = 0; i < src_slice_count; i++) { (*dst_slices)[i] = src_slices[i]; grpc_slice_ref((*dst_slices)[i]); @@ -56,7 +57,7 @@ void grpc_split_slices(grpc_slice_split_mode mode, grpc_slice *src_slices, for (i = 0; i < src_slice_count; i++) { length += GRPC_SLICE_LENGTH(src_slices[i]); } - *dst_slices = gpr_malloc(sizeof(grpc_slice)); + *dst_slices = (grpc_slice *)gpr_malloc(sizeof(grpc_slice)); **dst_slices = grpc_slice_malloc(length); length = 0; for (i = 0; i < src_slice_count; i++) { @@ -72,7 +73,7 @@ void grpc_split_slices(grpc_slice_split_mode mode, grpc_slice *src_slices, length += GRPC_SLICE_LENGTH(src_slices[i]); } *dst_slice_count = length; - *dst_slices = gpr_malloc(sizeof(grpc_slice) * length); + *dst_slices = (grpc_slice *)gpr_malloc(sizeof(grpc_slice) * length); length = 0; for (i = 0; i < src_slice_count; i++) { for (j = 0; j < GRPC_SLICE_LENGTH(src_slices[i]); j++) { @@ -112,7 +113,7 @@ grpc_slice grpc_slice_merge(grpc_slice *slices, size_t nslices) { for (i = 0; i < nslices; i++) { if (GRPC_SLICE_LENGTH(slices[i]) + length > capacity) { capacity = GPR_MAX(capacity * 2, GRPC_SLICE_LENGTH(slices[i]) + length); - out = gpr_realloc(out, capacity); + out = (uint8_t *)gpr_realloc(out, capacity); } memcpy(out + length, GRPC_SLICE_START_PTR(slices[i]), GRPC_SLICE_LENGTH(slices[i])); diff --git a/test/core/util/trickle_endpoint.c b/test/core/util/trickle_endpoint.c index 4f3c30dcf6..fc066f9d80 100644 --- a/test/core/util/trickle_endpoint.c +++ b/test/core/util/trickle_endpoint.c @@ -128,7 +128,7 @@ static int te_get_fd(grpc_endpoint *ep) { static void te_finish_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - trickle_endpoint *te = arg; + trickle_endpoint *te = (trickle_endpoint *)arg; gpr_mu_lock(&te->mu); te->writing = false; grpc_slice_buffer_reset_and_unref(&te->writing_buffer); @@ -142,7 +142,7 @@ static const grpc_endpoint_vtable vtable = { grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap, double bytes_per_second) { - trickle_endpoint *te = gpr_malloc(sizeof(*te)); + trickle_endpoint *te = (trickle_endpoint *)gpr_malloc(sizeof(*te)); te->base.vtable = &vtable; te->wrapped = wrap; te->bytes_per_second = bytes_per_second; diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD index 4780800645..8de46be816 100644 --- a/test/cpp/codegen/BUILD +++ b/test/cpp/codegen/BUILD @@ -14,14 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_test") +load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/codegen") grpc_cc_test( name = "codegen_test_full", diff --git a/test/cpp/common/BUILD b/test/cpp/common/BUILD index be9c279f13..e2b6365b13 100644 --- a/test/cpp/common/BUILD +++ b/test/cpp/common/BUILD @@ -14,14 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_test") +load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/common") grpc_cc_test( name = "alarm_cpp_test", diff --git a/test/cpp/common/alarm_cpp_test.cc b/test/cpp/common/alarm_cpp_test.cc index ce4168843c..212972d25d 100644 --- a/test/cpp/common/alarm_cpp_test.cc +++ b/test/cpp/common/alarm_cpp_test.cc @@ -18,6 +18,8 @@ #include <grpc++/alarm.h> #include <grpc++/completion_queue.h> +#include <thread> + #include <gtest/gtest.h> #include "test/core/util/test_config.h" @@ -28,6 +30,46 @@ namespace { TEST(AlarmTest, RegularExpiry) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); + Alarm alarm; + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk); + + void* output_tag; + bool ok; + const CompletionQueue::NextStatus status = cq.AsyncNext( + (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2)); + + EXPECT_EQ(status, CompletionQueue::GOT_EVENT); + EXPECT_TRUE(ok); + EXPECT_EQ(junk, output_tag); +} + +TEST(AlarmTest, MultithreadedRegularExpiry) { + CompletionQueue cq; + void* junk = reinterpret_cast<void*>(1618033); + void* output_tag; + bool ok; + CompletionQueue::NextStatus status; + Alarm alarm; + + std::thread t1([&alarm, &cq, &junk] { + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk); + }); + + std::thread t2([&cq, &ok, &output_tag, &status] { + status = cq.AsyncNext((void**)&output_tag, &ok, + grpc_timeout_seconds_to_deadline(2)); + }); + + t1.join(); + t2.join(); + EXPECT_EQ(status, CompletionQueue::GOT_EVENT); + EXPECT_TRUE(ok); + EXPECT_EQ(junk, output_tag); +} + +TEST(AlarmTest, DeprecatedRegularExpiry) { + CompletionQueue cq; + void* junk = reinterpret_cast<void*>(1618033); Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(1), junk); void* output_tag; @@ -43,7 +85,8 @@ TEST(AlarmTest, RegularExpiry) { TEST(AlarmTest, MoveConstructor) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); - Alarm first(&cq, grpc_timeout_seconds_to_deadline(1), junk); + Alarm first; + first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk); Alarm second(std::move(first)); void* output_tag; bool ok; @@ -57,7 +100,8 @@ TEST(AlarmTest, MoveConstructor) { TEST(AlarmTest, MoveAssignment) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); - Alarm first(&cq, grpc_timeout_seconds_to_deadline(1), junk); + Alarm first; + first.Set(&cq, grpc_timeout_seconds_to_deadline(1), junk); Alarm second(std::move(first)); first = std::move(second); @@ -76,7 +120,8 @@ TEST(AlarmTest, RegularExpiryChrono) { void* junk = reinterpret_cast<void*>(1618033); std::chrono::system_clock::time_point one_sec_deadline = std::chrono::system_clock::now() + std::chrono::seconds(1); - Alarm alarm(&cq, one_sec_deadline, junk); + Alarm alarm; + alarm.Set(&cq, one_sec_deadline, junk); void* output_tag; bool ok; @@ -91,7 +136,8 @@ TEST(AlarmTest, RegularExpiryChrono) { TEST(AlarmTest, ZeroExpiry) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); - Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(0), junk); + Alarm alarm; + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(0), junk); void* output_tag; bool ok; @@ -106,7 +152,8 @@ TEST(AlarmTest, ZeroExpiry) { TEST(AlarmTest, NegativeExpiry) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); - Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(-1), junk); + Alarm alarm; + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(-1), junk); void* output_tag; bool ok; @@ -121,7 +168,8 @@ TEST(AlarmTest, NegativeExpiry) { TEST(AlarmTest, Cancellation) { CompletionQueue cq; void* junk = reinterpret_cast<void*>(1618033); - Alarm alarm(&cq, grpc_timeout_seconds_to_deadline(2), junk); + Alarm alarm; + alarm.Set(&cq, grpc_timeout_seconds_to_deadline(2), junk); alarm.Cancel(); void* output_tag; diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index 27c5492c17..b29a13d4fb 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -14,15 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") -package( - default_visibility=["//visibility:public"], # Allows external users to implement end2end tests. - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/end2end", visibility = "public") # Allows external users to implement end2end tests. grpc_cc_library( name = "test_service_impl", @@ -199,6 +193,7 @@ grpc_cc_test( "//test/cpp/util:test_util", ], external_deps = [ + "gmock", "gtest", ], ) @@ -241,6 +236,7 @@ grpc_cc_test( "//test/cpp/util:test_util", ], external_deps = [ + "gmock", "gtest", ], ) diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 7cb7b262de..41090d161a 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -260,11 +260,31 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { server_address_ << "localhost:" << port_; // Setup server + BuildAndStartServer(); + + gpr_tls_set(&g_is_async_end2end_test, 1); + } + + void TearDown() override { + gpr_tls_set(&g_is_async_end2end_test, 0); + server_->Shutdown(); + void* ignored_tag; + bool ignored_ok; + cq_->Shutdown(); + while (cq_->Next(&ignored_tag, &ignored_ok)) + ; + stub_.reset(); + poll_overrider_.reset(); + grpc_recycle_unused_port(port_); + } + + void BuildAndStartServer() { ServerBuilder builder; auto server_creds = GetCredentialsProvider()->GetServerCredentials( GetParam().credentials_type); builder.AddListeningPort(server_address_.str(), server_creds); - builder.RegisterService(&service_); + service_.reset(new grpc::testing::EchoTestService::AsyncService()); + builder.RegisterService(service_.get()); if (GetParam().health_check_service) { builder.RegisterService(&health_check_); } @@ -276,20 +296,6 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { new ServerBuilderSyncPluginDisabler()); builder.SetOption(move(sync_plugin_disabler)); server_ = builder.BuildAndStart(); - - gpr_tls_set(&g_is_async_end2end_test, 1); - } - - void TearDown() override { - server_->Shutdown(); - void* ignored_tag; - bool ignored_ok; - cq_->Shutdown(); - while (cq_->Next(&ignored_tag, &ignored_ok)) - ; - poll_overrider_.reset(); - gpr_tls_set(&g_is_async_end2end_test, 0); - grpc_recycle_unused_port(port_); } void ResetStub() { @@ -319,8 +325,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, + cq_.get(), cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); @@ -341,7 +347,7 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { std::unique_ptr<ServerCompletionQueue> cq_; std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; std::unique_ptr<Server> server_; - grpc::testing::EchoTestService::AsyncService service_; + std::unique_ptr<grpc::testing::EchoTestService::AsyncService> service_; HealthCheck health_check_; std::ostringstream server_address_; int port_; @@ -359,6 +365,26 @@ TEST_P(AsyncEnd2endTest, SequentialRpcs) { SendRpc(10); } +TEST_P(AsyncEnd2endTest, ReconnectChannel) { + if (GetParam().inproc) { + return; + } + ResetStub(); + SendRpc(1); + server_->Shutdown(); + void* ignored_tag; + bool ignored_ok; + cq_->Shutdown(); + while (cq_->Next(&ignored_tag, &ignored_ok)) + ; + BuildAndStartServer(); + // It needs more than kConnectivityCheckIntervalMsec time to reconnect the + // channel. + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(1600, GPR_TIMESPAN))); + SendRpc(1); +} + // We do not need to protect notify because the use is synchronized. void ServerWait(Server* server, int* notify) { server->Wait(); @@ -370,6 +396,7 @@ TEST_P(AsyncEnd2endTest, WaitAndShutdownTest) { ResetStub(); SendRpc(1); EXPECT_EQ(0, notify); + gpr_tls_set(&g_is_async_end2end_test, 0); server_->Shutdown(); wait_thread.join(); EXPECT_EQ(1, notify); @@ -378,8 +405,9 @@ TEST_P(AsyncEnd2endTest, WaitAndShutdownTest) { TEST_P(AsyncEnd2endTest, ShutdownThenWait) { ResetStub(); SendRpc(1); - server_->Shutdown(); + std::thread t([this]() { server_->Shutdown(); }); server_->Wait(); + t.join(); } // Test a simple RPC using the async version of Next @@ -407,8 +435,8 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) { Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now); Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking) .Expect(2, true) @@ -444,8 +472,8 @@ TEST_P(AsyncEnd2endTest, SimpleClientStreaming) { std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream( stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1))); - service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); Verifier(GetParam().disable_blocking) .Expect(2, true) @@ -506,8 +534,8 @@ TEST_P(AsyncEnd2endTest, SimpleClientStreamingWithCoalescingApi) { std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream( stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1))); - service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); cli_stream->Write(send_request, tag(3)); @@ -579,8 +607,8 @@ TEST_P(AsyncEnd2endTest, SimpleServerStreaming) { std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream( stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1))); - service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, - cq_.get(), cq_.get(), tag(2)); + service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, + cq_.get(), cq_.get(), tag(2)); Verifier(GetParam().disable_blocking) .Expect(1, true) @@ -635,8 +663,8 @@ TEST_P(AsyncEnd2endTest, SimpleServerStreamingWithCoalescingApiWAF) { std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream( stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1))); - service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, - cq_.get(), cq_.get(), tag(2)); + service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, + cq_.get(), cq_.get(), tag(2)); Verifier(GetParam().disable_blocking) .Expect(1, true) @@ -687,8 +715,8 @@ TEST_P(AsyncEnd2endTest, SimpleServerStreamingWithCoalescingApiWL) { std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream( stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1))); - service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, - cq_.get(), cq_.get(), tag(2)); + service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, + cq_.get(), cq_.get(), tag(2)); Verifier(GetParam().disable_blocking) .Expect(1, true) @@ -741,8 +769,8 @@ TEST_P(AsyncEnd2endTest, SimpleBidiStreaming) { std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>> cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1))); - service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); Verifier(GetParam().disable_blocking) .Expect(1, true) @@ -801,8 +829,8 @@ TEST_P(AsyncEnd2endTest, SimpleBidiStreamingWithCoalescingApiWAF) { std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>> cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1))); - service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); cli_stream->WriteLast(send_request, WriteOptions(), tag(3)); @@ -869,8 +897,8 @@ TEST_P(AsyncEnd2endTest, SimpleBidiStreamingWithCoalescingApiWL) { std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>> cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1))); - service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); cli_stream->WriteLast(send_request, WriteOptions(), tag(3)); @@ -946,8 +974,8 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); @@ -991,8 +1019,8 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); srv_ctx.AddInitialMetadata(meta1.first, meta1.second); @@ -1041,8 +1069,8 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); response_writer.SendInitialMetadata(tag(3)); @@ -1104,8 +1132,8 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader( stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); @@ -1168,8 +1196,8 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) { stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); srv_ctx.AsyncNotifyWhenDone(tag(5)); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); @@ -1203,8 +1231,8 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) { stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); srv_ctx.AsyncNotifyWhenDone(tag(5)); - service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), - cq_.get(), tag(2)); + service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(), + cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); @@ -1295,8 +1323,8 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { // On the server, request to be notified of 'RequestStream' calls // and receive the 'RequestStream' call just made by the client srv_ctx.AsyncNotifyWhenDone(tag(11)); - service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); // Client sends 3 messages (tags 3, 4 and 5) @@ -1426,8 +1454,8 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { // On the server, request to be notified of 'ResponseStream' calls and // receive the call just made by the client srv_ctx.AsyncNotifyWhenDone(tag(11)); - service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, - cq_.get(), cq_.get(), tag(2)); + service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, + cq_.get(), cq_.get(), tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); @@ -1562,8 +1590,8 @@ class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest { // On the server, request to be notified of the 'BidiStream' call and // receive the call just made by the client srv_ctx.AsyncNotifyWhenDone(tag(11)); - service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), - tag(2)); + service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(), + tag(2)); Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get()); // Client sends the first and the only message diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index e1160ecdc6..c236f76e89 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -85,7 +85,8 @@ class MyTestServiceImpl : public TestServiceImpl { class ClientLbEnd2endTest : public ::testing::Test { protected: - ClientLbEnd2endTest() : server_host_("localhost") {} + ClientLbEnd2endTest() + : server_host_("localhost"), kRequestMessage_("Live long and prosper.") {} void SetUp() override { response_generator_ = grpc_fake_resolver_response_generator_create(); @@ -139,6 +140,7 @@ class ClientLbEnd2endTest : public ::testing::Test { } // else, default to pick first args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, response_generator_); + args.SetInt("grpc.testing.fixed_reconnect_backoff_ms", 2000); std::ostringstream uri; uri << "fake:///"; for (size_t i = 0; i < servers_.size() - 1; ++i) { @@ -150,18 +152,27 @@ class ClientLbEnd2endTest : public ::testing::Test { stub_ = grpc::testing::EchoTestService::NewStub(channel_); } - void SendRpc(bool expect_ok = true) { + Status SendRpc(EchoResponse* response = nullptr) { + const bool local_response = (response == nullptr); + if (local_response) response = new EchoResponse; EchoRequest request; - EchoResponse response; - request.set_message("Live long and prosper."); + request.set_message(kRequestMessage_); ClientContext context; - Status status = stub_->Echo(&context, request, &response); - if (expect_ok) { - EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.message(), request.message()); - } else { - EXPECT_FALSE(status.ok()); - } + Status status = stub_->Echo(&context, request, response); + if (local_response) delete response; + return status; + } + + void CheckRpcSendOk() { + EchoResponse response; + const Status status = SendRpc(&response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.message(), kRequestMessage_); + } + + void CheckRpcSendFailure() { + const Status status = SendRpc(); + EXPECT_FALSE(status.ok()); } struct ServerData { @@ -169,16 +180,18 @@ class ClientLbEnd2endTest : public ::testing::Test { std::unique_ptr<Server> server_; MyTestServiceImpl service_; std::unique_ptr<std::thread> thread_; + bool server_ready_ = false; explicit ServerData(const grpc::string& server_host, int port = 0) { port_ = port > 0 ? port : grpc_pick_unused_port_or_die(); gpr_log(GPR_INFO, "starting server on port %d", port_); std::mutex mu; + std::unique_lock<std::mutex> lock(mu); std::condition_variable cond; thread_.reset(new std::thread( std::bind(&ServerData::Start, this, server_host, &mu, &cond))); - std::unique_lock<std::mutex> lock(mu); - cond.wait(lock); + cond.wait(lock, [this] { return server_ready_; }); + server_ready_ = false; gpr_log(GPR_INFO, "server startup complete"); } @@ -192,6 +205,7 @@ class ClientLbEnd2endTest : public ::testing::Test { builder.RegisterService(&service_); server_ = builder.BuildAndStart(); std::lock_guard<std::mutex> lock(*mu); + server_ready_ = true; cond->notify_one(); } @@ -207,16 +221,42 @@ class ClientLbEnd2endTest : public ::testing::Test { void WaitForServer(size_t server_idx) { do { - SendRpc(); + CheckRpcSendOk(); } while (servers_[server_idx]->service_.request_count() == 0); ResetCounters(); } + bool SeenAllServers() { + for (const auto& server : servers_) { + if (server->service_.request_count() == 0) return false; + } + return true; + } + + // Updates \a connection_order by appending to it the index of the newly + // connected server. Must be called after every single RPC. + void UpdateConnectionOrder( + const std::vector<std::unique_ptr<ServerData>>& servers, + std::vector<int>* connection_order) { + for (size_t i = 0; i < servers.size(); ++i) { + if (servers[i]->service_.request_count() == 1) { + // Was the server index known? If not, update connection_order. + const auto it = + std::find(connection_order->begin(), connection_order->end(), i); + if (it == connection_order->end()) { + connection_order->push_back(i); + return; + } + } + } + } + const grpc::string server_host_; std::shared_ptr<Channel> channel_; std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; std::vector<std::unique_ptr<ServerData>> servers_; grpc_fake_resolver_response_generator* response_generator_; + const grpc::string kRequestMessage_; }; TEST_F(ClientLbEnd2endTest, PickFirst) { @@ -230,7 +270,7 @@ TEST_F(ClientLbEnd2endTest, PickFirst) { } SetNextResolution(ports); for (size_t i = 0; i < servers_.size(); ++i) { - SendRpc(); + CheckRpcSendOk(); } // All requests should have gone to a single server. bool found = false; @@ -258,7 +298,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) { ports.emplace_back(servers_[0]->port_); SetNextResolution(ports); gpr_log(GPR_INFO, "****** SET [0] *******"); - SendRpc(); + CheckRpcSendOk(); EXPECT_EQ(servers_[0]->service_.request_count(), 1); // An empty update will result in the channel going into TRANSIENT_FAILURE. @@ -304,7 +344,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) { ports.emplace_back(servers_[0]->port_); SetNextResolution(ports); gpr_log(GPR_INFO, "****** SET [0] *******"); - SendRpc(); + CheckRpcSendOk(); EXPECT_EQ(servers_[0]->service_.request_count(), 1); servers_[0]->service_.ResetCounters(); @@ -314,7 +354,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) { ports.emplace_back(servers_[0]->port_); SetNextResolution(ports); gpr_log(GPR_INFO, "****** SET superset *******"); - SendRpc(); + CheckRpcSendOk(); // We stick to the previously connected server. WaitForServer(0); EXPECT_EQ(0, servers_[1]->service_.request_count()); @@ -338,7 +378,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) { for (size_t i = 0; i < 1000; ++i) { std::random_shuffle(ports.begin(), ports.end()); SetNextResolution(ports); - if (i % 10 == 0) SendRpc(); + if (i % 10 == 0) CheckRpcSendOk(); } } // Check LB policy name for the channel. @@ -355,13 +395,23 @@ TEST_F(ClientLbEnd2endTest, RoundRobin) { ports.emplace_back(server->port_); } SetNextResolution(ports); + // Wait until all backends are ready. + do { + CheckRpcSendOk(); + } while (!SeenAllServers()); + ResetCounters(); + // "Sync" to the end of the list. Next sequence of picks will start at the + // first server (index 0). + WaitForServer(servers_.size() - 1); + std::vector<int> connection_order; for (size_t i = 0; i < servers_.size(); ++i) { - SendRpc(); - } - // One request should have gone to each server. - for (size_t i = 0; i < servers_.size(); ++i) { - EXPECT_EQ(1, servers_[i]->service_.request_count()); + CheckRpcSendOk(); + UpdateConnectionOrder(servers_, &connection_order); } + // Backends should be iterated over in the order in which the addresses were + // given. + const auto expected = std::vector<int>{0, 1, 2}; + EXPECT_EQ(expected, connection_order); // Check LB policy name for the channel. EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName()); } @@ -378,7 +428,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { SetNextResolution(ports); WaitForServer(0); // Send RPCs. They should all go servers_[0] - for (size_t i = 0; i < 10; ++i) SendRpc(); + for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(); EXPECT_EQ(10, servers_[0]->service_.request_count()); EXPECT_EQ(0, servers_[1]->service_.request_count()); EXPECT_EQ(0, servers_[2]->service_.request_count()); @@ -394,7 +444,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { EXPECT_EQ(0, servers_[1]->service_.request_count()); WaitForServer(1); - for (size_t i = 0; i < 10; ++i) SendRpc(); + for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(); EXPECT_EQ(0, servers_[0]->service_.request_count()); EXPECT_EQ(10, servers_[1]->service_.request_count()); EXPECT_EQ(0, servers_[2]->service_.request_count()); @@ -406,7 +456,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { SetNextResolution(ports); WaitForServer(2); - for (size_t i = 0; i < 10; ++i) SendRpc(); + for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(); EXPECT_EQ(0, servers_[0]->service_.request_count()); EXPECT_EQ(0, servers_[1]->service_.request_count()); EXPECT_EQ(10, servers_[2]->service_.request_count()); @@ -423,7 +473,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { WaitForServer(2); // Send three RPCs, one per server. - for (size_t i = 0; i < 3; ++i) SendRpc(); + for (size_t i = 0; i < 3; ++i) CheckRpcSendOk(); EXPECT_EQ(1, servers_[0]->service_.request_count()); EXPECT_EQ(1, servers_[1]->service_.request_count()); EXPECT_EQ(1, servers_[2]->service_.request_count()); @@ -450,6 +500,37 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName()); } +TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) { + const int kNumServers = 3; + StartServers(kNumServers); + ResetStub("round_robin"); + std::vector<int> ports; + + // Start with a single server. + ports.emplace_back(servers_[0]->port_); + SetNextResolution(ports); + WaitForServer(0); + // Send RPCs. They should all go to servers_[0] + for (size_t i = 0; i < 10; ++i) SendRpc(); + EXPECT_EQ(10, servers_[0]->service_.request_count()); + EXPECT_EQ(0, servers_[1]->service_.request_count()); + EXPECT_EQ(0, servers_[2]->service_.request_count()); + servers_[0]->service_.ResetCounters(); + + // Shutdown one of the servers to be sent in the update. + servers_[1]->Shutdown(false); + ports.emplace_back(servers_[1]->port_); + ports.emplace_back(servers_[2]->port_); + SetNextResolution(ports); + WaitForServer(0); + WaitForServer(2); + + // Send three RPCs, one per server. + for (size_t i = 0; i < kNumServers; ++i) SendRpc(); + // The server in shutdown shouldn't receive any. + EXPECT_EQ(0, servers_[1]->service_.request_count()); +} + TEST_F(ClientLbEnd2endTest, RoundRobinManyUpdates) { // Start servers and send one RPC per server. const int kNumServers = 3; @@ -462,7 +543,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinManyUpdates) { for (size_t i = 0; i < 1000; ++i) { std::random_shuffle(ports.begin(), ports.end()); SetNextResolution(ports); - if (i % 10 == 0) SendRpc(); + if (i % 10 == 0) CheckRpcSendOk(); } // Check LB policy name for the channel. EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName()); @@ -473,37 +554,30 @@ TEST_F(ClientLbEnd2endTest, RoundRobinConcurrentUpdates) { // update provisions of RR. } -TEST_F(ClientLbEnd2endTest, RoundRobinReconnect) { +TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) { // Start servers and send one RPC per server. - const int kNumServers = 1; + const int kNumServers = 3; std::vector<int> ports; - ports.push_back(grpc_pick_unused_port_or_die()); + for (int i = 0; i < kNumServers; ++i) { + ports.push_back(grpc_pick_unused_port_or_die()); + } StartServers(kNumServers, ports); ResetStub("round_robin"); SetNextResolution(ports); - // Send one RPC per backend and make sure they are used in order. - // Note: This relies on the fact that the subchannels are reported in - // state READY in the order in which the addresses are specified, - // which is only true because the backends are all local. - for (size_t i = 0; i < servers_.size(); ++i) { - SendRpc(); - EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i; + // Send a number of RPCs, which succeed. + for (size_t i = 0; i < 100; ++i) { + CheckRpcSendOk(); } - // Check LB policy name for the channel. - EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName()); - // Kill all servers for (size_t i = 0; i < servers_.size(); ++i) { servers_[i]->Shutdown(false); } // Client request should fail. - SendRpc(false); - + CheckRpcSendFailure(); // Bring servers back up on the same port (we aren't recreating the channel). StartServers(kNumServers, ports); - // Client request should succeed. - SendRpc(); + CheckRpcSendOk(); } } // namespace diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 8bada48a2b..e54cd03ca2 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -238,6 +238,18 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> { int port = grpc_pick_unused_port_or_die(); server_address_ << "127.0.0.1:" << port; // Setup server + BuildAndStartServer(processor); + } + + void RestartServer(const std::shared_ptr<AuthMetadataProcessor>& processor) { + if (is_server_started_) { + server_->Shutdown(); + BuildAndStartServer(processor); + } + } + + void BuildAndStartServer( + const std::shared_ptr<AuthMetadataProcessor>& processor) { ServerBuilder builder; ConfigureServerBuilder(&builder); auto server_creds = GetCredentialsProvider()->GetServerCredentials( @@ -685,6 +697,20 @@ TEST_P(End2endTest, MultipleRpcs) { } } +TEST_P(End2endTest, ReconnectChannel) { + if (GetParam().inproc) { + return; + } + ResetStub(); + SendRpc(stub_.get(), 1, false); + RestartServer(std::shared_ptr<AuthMetadataProcessor>()); + // It needs more than kConnectivityCheckIntervalMsec time to reconnect the + // channel. + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(1600, GPR_TIMESPAN))); + SendRpc(stub_.get(), 1, false); +} + TEST_P(End2endTest, RequestStreamOneRequest) { ResetStub(); EchoRequest request; @@ -731,6 +757,22 @@ TEST_P(End2endTest, RequestStreamTwoRequests) { EXPECT_TRUE(s.ok()); } +TEST_P(End2endTest, RequestStreamTwoRequestsWithWriteThrough) { + ResetStub(); + EchoRequest request; + EchoResponse response; + ClientContext context; + + auto stream = stub_->RequestStream(&context, &response); + request.set_message("hello"); + EXPECT_TRUE(stream->Write(request, WriteOptions().set_write_through())); + EXPECT_TRUE(stream->Write(request, WriteOptions().set_write_through())); + stream->WritesDone(); + Status s = stream->Finish(); + EXPECT_EQ(response.message(), "hellohello"); + EXPECT_TRUE(s.ok()); +} + TEST_P(End2endTest, RequestStreamTwoRequestsWithCoalescingApi) { ResetStub(); EchoRequest request; diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index b5cff664f6..570a3d1067 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -332,7 +332,8 @@ class GrpclbEnd2endTest : public ::testing::Test { num_backends_(num_backends), num_balancers_(num_balancers), client_load_reporting_interval_seconds_( - client_load_reporting_interval_seconds) {} + client_load_reporting_interval_seconds), + kRequestMessage_("Live long and prosper.") {} void SetUp() override { response_generator_ = grpc_fake_resolver_response_generator_create(); @@ -378,6 +379,10 @@ class GrpclbEnd2endTest : public ::testing::Test { stub_ = grpc::testing::EchoTestService::NewStub(channel_); } + void ResetBackendCounters() { + for (const auto& backend : backends_) backend->ResetCounters(); + } + ClientStats WaitForLoadReports() { ClientStats client_stats; for (const auto& balancer : balancers_) { @@ -386,6 +391,27 @@ class GrpclbEnd2endTest : public ::testing::Test { return client_stats; } + bool SeenAllBackends() { + for (const auto& backend : backends_) { + if (backend->request_count() == 0) return false; + } + return true; + } + + void WaitForAllBackends() { + while (!SeenAllBackends()) { + CheckRpcSendOk(); + } + ResetBackendCounters(); + } + + void WaitForBackend(size_t backend_idx) { + do { + CheckRpcSendOk(); + } while (backends_[backend_idx]->request_count() == 0); + ResetBackendCounters(); + } + struct AddressData { int port; bool is_balancer; @@ -429,20 +455,31 @@ class GrpclbEnd2endTest : public ::testing::Test { balancers_.at(i)->add_response(response, delay_ms); } - std::vector<std::pair<Status, EchoResponse>> SendRpc(const string& message, - int num_rpcs, - int timeout_ms = 1000) { - std::vector<std::pair<Status, EchoResponse>> results; + Status SendRpc(EchoResponse* response = nullptr, int timeout_ms = 1000) { + const bool local_response = (response == nullptr); + if (local_response) response = new EchoResponse; EchoRequest request; - EchoResponse response; - request.set_message(message); - for (int i = 0; i < num_rpcs; i++) { - ClientContext context; - context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms)); - Status status = stub_->Echo(&context, request, &response); - results.push_back(std::make_pair(status, response)); + request.set_message(kRequestMessage_); + ClientContext context; + context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms)); + Status status = stub_->Echo(&context, request, response); + if (local_response) delete response; + return status; + } + + void CheckRpcSendOk(const size_t times = 1) { + for (size_t i = 0; i < times; ++i) { + EchoResponse response; + const Status status = SendRpc(&response); + EXPECT_TRUE(status.ok()) << "code=" << status.error_code() + << " message=" << status.error_message(); + EXPECT_EQ(response.message(), kRequestMessage_); } - return results; + } + + void CheckRpcSendFailure() { + const Status status = SendRpc(); + EXPECT_FALSE(status.ok()); } template <typename T> @@ -499,14 +536,12 @@ class GrpclbEnd2endTest : public ::testing::Test { const int client_load_reporting_interval_seconds_; std::shared_ptr<Channel> channel_; std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; - std::vector<std::unique_ptr<BackendServiceImpl>> backends_; std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_; - std::vector<ServerThread<BackendService>> backend_servers_; std::vector<ServerThread<BalancerService>> balancer_servers_; - grpc_fake_resolver_response_generator* response_generator_; + const grpc::string kRequestMessage_; }; class SingleBalancerTest : public GrpclbEnd2endTest { @@ -521,17 +556,12 @@ TEST_F(SingleBalancerTest, Vanilla) { 0); // Make sure that trying to connect works without a call. channel_->GetState(true /* try_to_connect */); - // Send 100 RPCs per server. - const auto& statuses_and_responses = - SendRpc(kMessage_, kNumRpcsPerAddress * num_backends_); - - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } + + // We need to wait for all backends to come online. + WaitForAllBackends(); + + // Send kNumRpcsPerAddress RPCs per server. + CheckRpcSendOk(kNumRpcsPerAddress * num_backends_); // Each backend should have gotten 100 requests. for (size_t i = 0; i < backends_.size(); ++i) { @@ -561,8 +591,7 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) { const auto t0 = system_clock::now(); // Client will block: LB will initially send empty serverlist. - const auto& statuses_and_responses = - SendRpc(kMessage_, num_backends_, kCallDeadlineMs); + CheckRpcSendOk(num_backends_); const auto ellapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>( system_clock::now() - t0); @@ -576,13 +605,6 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) { for (size_t i = 0; i < backends_.size(); ++i) { EXPECT_EQ(1U, backend_servers_[i].service_->request_count()); } - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } balancers_[0]->NotifyDoneWithServerlists(); // The balancer got a single request. EXPECT_EQ(1U, balancer_servers_[0].service_->request_count()); @@ -593,70 +615,6 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) { EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); } -TEST_F(SingleBalancerTest, RepeatedServerlist) { - constexpr int kServerlistDelayMs = 100; - - // Send a serverlist right away. - ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), - 0); - // ... and the same one a bit later. - ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), - kServerlistDelayMs); - - // Send num_backends/2 requests. - auto statuses_and_responses = SendRpc(kMessage_, num_backends_ / 2); - // only the first half of the backends will receive them. - for (size_t i = 0; i < backends_.size(); ++i) { - if (i < backends_.size() / 2) - EXPECT_EQ(1U, backend_servers_[i].service_->request_count()) - << "for backend #" << i; - else - EXPECT_EQ(0U, backend_servers_[i].service_->request_count()) - << "for backend #" << i; - } - EXPECT_EQ(statuses_and_responses.size(), num_backends_ / 2); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } - - // Wait for the (duplicated) serverlist update. - gpr_sleep_until(gpr_time_add( - gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(kServerlistDelayMs * 1.1, GPR_TIMESPAN))); - - // Verify the LB has sent two responses. - EXPECT_EQ(2U, balancer_servers_[0].service_->response_count()); - - // Some more calls to complete the total number of backends. - statuses_and_responses = SendRpc( - kMessage_, - num_backends_ / 2 + (num_backends_ & 0x1) /* extra one if num_bes odd */); - // Because a duplicated serverlist should have no effect, all backends must - // have been hit once now. - for (size_t i = 0; i < backends_.size(); ++i) { - EXPECT_EQ(1U, backend_servers_[i].service_->request_count()); - } - EXPECT_EQ(statuses_and_responses.size(), num_backends_ / 2); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } - balancers_[0]->NotifyDoneWithServerlists(); - // The balancer got a single request. - EXPECT_EQ(1U, balancer_servers_[0].service_->request_count()); - // Check LB policy name for the channel. - EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); -} - TEST_F(SingleBalancerTest, BackendsRestart) { const size_t kNumRpcsPerAddress = 100; ScheduleResponseForBalancer( @@ -664,21 +622,8 @@ TEST_F(SingleBalancerTest, BackendsRestart) { 0); // Make sure that trying to connect works without a call. channel_->GetState(true /* try_to_connect */); - // Send 100 RPCs per server. - auto statuses_and_responses = - SendRpc(kMessage_, kNumRpcsPerAddress * num_backends_); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } - // Each backend should have gotten 100 requests. - for (size_t i = 0; i < backends_.size(); ++i) { - EXPECT_EQ(kNumRpcsPerAddress, - backend_servers_[i].service_->request_count()); - } + // Send kNumRpcsPerAddress RPCs per server. + CheckRpcSendOk(kNumRpcsPerAddress * num_backends_); balancers_[0]->NotifyDoneWithServerlists(); // The balancer got a single request. EXPECT_EQ(1U, balancer_servers_[0].service_->request_count()); @@ -687,11 +632,7 @@ TEST_F(SingleBalancerTest, BackendsRestart) { for (size_t i = 0; i < backends_.size(); ++i) { if (backends_[i]->Shutdown()) backend_servers_[i].Shutdown(); } - statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - EXPECT_FALSE(status.ok()); - } + CheckRpcSendFailure(); for (size_t i = 0; i < num_backends_; ++i) { backends_.emplace_back(new BackendServiceImpl()); backend_servers_.emplace_back(ServerThread<BackendService>( @@ -703,11 +644,7 @@ TEST_F(SingleBalancerTest, BackendsRestart) { // TODO(dgq): implement the "backend restart" component as well. We need extra // machinery to either update the LB responses "on the fly" or instruct // backends which ports to restart on. - statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - EXPECT_FALSE(status.ok()); - } + CheckRpcSendFailure(); // Check LB policy name for the channel. EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); } @@ -727,13 +664,9 @@ TEST_F(UpdatesTest, UpdateBalancers) { // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); - auto statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should have gone to the first backend. EXPECT_EQ(10U, backend_servers_[0].service_->request_count()); @@ -758,22 +691,12 @@ TEST_F(UpdatesTest, UpdateBalancers) { // Wait until update has been processed, as signaled by the second backend // receiving a request. EXPECT_EQ(0U, backend_servers_[1].service_->request_count()); - do { - auto statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } - } while (backend_servers_[1].service_->request_count() == 0); + WaitForBackend(1); backend_servers_[1].service_->ResetCounters(); gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); - statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should have gone to the second backend. EXPECT_EQ(10U, backend_servers_[1].service_->request_count()); @@ -804,13 +727,9 @@ TEST_F(UpdatesTest, UpdateBalancersRepeated) { // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); - auto statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should have gone to the first backend. EXPECT_EQ(10U, backend_servers_[0].service_->request_count()); @@ -837,11 +756,7 @@ TEST_F(UpdatesTest, UpdateBalancersRepeated) { gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(10000, GPR_TIMESPAN)); // Send 10 seconds worth of RPCs do { - statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } + CheckRpcSendOk(); } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0); // grpclb continued using the original LB call to the first balancer, which // doesn't assign the second backend. @@ -860,11 +775,7 @@ TEST_F(UpdatesTest, UpdateBalancersRepeated) { gpr_time_from_millis(10000, GPR_TIMESPAN)); // Send 10 seconds worth of RPCs do { - statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } + CheckRpcSendOk(); } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0); // grpclb continued using the original LB call to the first balancer, which // doesn't assign the second backend. @@ -886,12 +797,8 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) { // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); - auto statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should have gone to the first backend. EXPECT_EQ(10U, backend_servers_[0].service_->request_count()); @@ -903,12 +810,8 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) { // This is serviced by the existing RR policy gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); - statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should again have gone to the first backend. EXPECT_EQ(20U, backend_servers_[0].service_->request_count()); EXPECT_EQ(0U, backend_servers_[1].service_->request_count()); @@ -935,23 +838,13 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) { // receiving a request. In the meantime, the client continues to be serviced // (by the first backend) without interruption. EXPECT_EQ(0U, backend_servers_[1].service_->request_count()); - do { - auto statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } - } while (backend_servers_[1].service_->request_count() == 0); + WaitForBackend(1); // This is serviced by the existing RR policy backend_servers_[1].service_->ResetCounters(); gpr_log(GPR_INFO, "========= BEFORE THIRD BATCH =========="); - statuses_and_responses = SendRpc(kMessage_, 10); + CheckRpcSendOk(10); gpr_log(GPR_INFO, "========= DONE WITH THIRD BATCH =========="); - for (const auto& status_and_response : statuses_and_responses) { - EXPECT_TRUE(status_and_response.first.ok()); - EXPECT_EQ(status_and_response.second.message(), kMessage_); - } // All 10 requests should have gone to the second backend. EXPECT_EQ(10U, backend_servers_[1].service_->request_count()); @@ -974,14 +867,11 @@ TEST_F(SingleBalancerTest, Drop) { 0, BalancerServiceImpl::BuildResponseForBackends( GetBackendPorts(), {{"rate_limiting", 1}, {"load_balancing", 2}}), 0); - // Send 100 RPCs for each server and drop address. - const auto& statuses_and_responses = - SendRpc(kMessage_, kNumRpcsPerAddress * (num_backends_ + 3)); - + // Send kNumRpcsPerAddress RPCs for each server and drop address. size_t num_drops = 0; - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; + for (size_t i = 0; i < kNumRpcsPerAddress * (num_backends_ + 3); ++i) { + EchoResponse response; + const Status status = SendRpc(&response); if (!status.ok() && status.error_message() == "Call dropped by load balancing policy") { ++num_drops; @@ -1010,12 +900,9 @@ TEST_F(SingleBalancerTest, DropAllFirst) { 0, BalancerServiceImpl::BuildResponseForBackends( {}, {{"rate_limiting", 1}, {"load_balancing", 1}}), 0); - const auto& statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - EXPECT_FALSE(status.ok()); - EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy"); - } + const Status status = SendRpc(); + EXPECT_FALSE(status.ok()); + EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy"); } TEST_F(SingleBalancerTest, DropAll) { @@ -1028,21 +915,13 @@ TEST_F(SingleBalancerTest, DropAll) { 1000); // First call succeeds. - auto statuses_and_responses = SendRpc(kMessage_, 1); - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } + CheckRpcSendOk(); // But eventually, the update with only dropped servers is processed and calls // fail. + Status status; do { - statuses_and_responses = SendRpc(kMessage_, 1); - ASSERT_EQ(statuses_and_responses.size(), 1UL); - } while (statuses_and_responses[0].first.ok()); - const Status& status = statuses_and_responses[0].first; + status = SendRpc(); + } while (status.ok()); EXPECT_FALSE(status.ok()); EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy"); } @@ -1057,18 +936,8 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Vanilla) { ScheduleResponseForBalancer( 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), 0); - // Send 100 RPCs per server. - const auto& statuses_and_responses = - SendRpc(kMessage_, kNumRpcsPerAddress * num_backends_); - - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; - EXPECT_TRUE(status.ok()) << "code=" << status.error_code() - << " message=" << status.error_message(); - EXPECT_EQ(response.message(), kMessage_); - } - + // Send kNumRpcsPerAddress RPCs per server. + CheckRpcSendOk(kNumRpcsPerAddress * num_backends_); // Each backend should have gotten 100 requests. for (size_t i = 0; i < backends_.size(); ++i) { EXPECT_EQ(kNumRpcsPerAddress, @@ -1096,14 +965,11 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) { 0, BalancerServiceImpl::BuildResponseForBackends( GetBackendPorts(), {{"rate_limiting", 2}, {"load_balancing", 1}}), 0); - // Send 100 RPCs for each server and drop address. - const auto& statuses_and_responses = - SendRpc(kMessage_, kNumRpcsPerAddress * (num_backends_ + 3)); size_t num_drops = 0; - for (const auto& status_and_response : statuses_and_responses) { - const Status& status = status_and_response.first; - const EchoResponse& response = status_and_response.second; + for (size_t i = 0; i < kNumRpcsPerAddress * (num_backends_ + 3); ++i) { + EchoResponse response; + const Status status = SendRpc(&response); if (!status.ok() && status.error_message() == "Call dropped by load balancing policy") { ++num_drops; diff --git a/test/cpp/interop/BUILD b/test/cpp/interop/BUILD index 9123bd929e..4f21551ff4 100644 --- a/test/cpp/interop/BUILD +++ b/test/cpp/interop/BUILD @@ -14,14 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/interop") grpc_cc_library( name = "server_helper_lib", diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD index 442da38426..985a335f1b 100644 --- a/test/cpp/microbenchmarks/BUILD +++ b/test/cpp/microbenchmarks/BUILD @@ -14,14 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library") +load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/microbenchmarks") grpc_cc_test( name = "noop-benchmark", @@ -33,75 +28,94 @@ grpc_cc_test( grpc_cc_library( name = "helpers", + testonly = 1, srcs = ["helpers.cc"], hdrs = [ "fullstack_context_mutators.h", "fullstack_fixtures.h", "helpers.h", ], + external_deps = [ + "benchmark", + ], deps = [ "//:grpc++_unsecure", "//src/proto/grpc/testing:echo_proto", "//test/core/util:grpc_test_util_unsecure", ], - external_deps = [ - "benchmark", - ], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_closure", + testonly = 1, srcs = ["bm_closure.cc"], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_cq", + testonly = 1, srcs = ["bm_cq.cc"], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_cq_multiple_threads", + testonly = 1, srcs = ["bm_cq_multiple_threads.cc"], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_error", + testonly = 1, srcs = ["bm_error.cc"], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_fullstack_streaming_ping_pong", - srcs = ["bm_fullstack_streaming_ping_pong.cc"], + testonly = 1, + srcs = [ + "bm_fullstack_streaming_ping_pong.cc", + "fullstack_streaming_ping_pong.h", + ], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_fullstack_streaming_pump", - srcs = ["bm_fullstack_streaming_pump.cc"], + testonly = 1, + srcs = [ + "bm_fullstack_streaming_pump.cc", + "fullstack_streaming_pump.h", + ], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_fullstack_trickle", + testonly = 1, srcs = ["bm_fullstack_trickle.cc"], - deps = [":helpers"], - external_deps = [ - "gflags", + deps = [ + ":helpers", + "//test/cpp/util:test_config", ], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_fullstack_unary_ping_pong", - srcs = ["bm_fullstack_unary_ping_pong.cc"], + testonly = 1, + srcs = [ + "bm_fullstack_unary_ping_pong.cc", + "fullstack_unary_ping_pong.h", + ], deps = [":helpers"], ) -grpc_cc_test( +grpc_cc_binary( name = "bm_metadata", + testonly = 1, srcs = ["bm_metadata.cc"], deps = [":helpers"], ) diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc index 508f7f94d6..cadc9b2a11 100644 --- a/test/cpp/microbenchmarks/bm_call_create.cc +++ b/test/cpp/microbenchmarks/bm_call_create.cc @@ -35,10 +35,11 @@ extern "C" { #include "src/core/ext/filters/http/client/http_client_filter.h" #include "src/core/ext/filters/http/message_compress/message_compress_filter.h" #include "src/core/ext/filters/http/server/http_server_filter.h" -#include "src/core/ext/filters/load_reporting/load_reporting_filter.h" +#include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h" #include "src/core/ext/filters/message_size/message_size_filter.h" #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/iomgr/call_combiner.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/transport_impl.h" @@ -396,10 +397,6 @@ grpc_error *InitChannelElem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, 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) {} @@ -412,7 +409,6 @@ static const grpc_channel_filter dummy_filter = {StartTransportStreamOp, 0, InitChannelElem, DestroyChannelElem, - GetPeer, GetChannelInfo, "dummy_filter"}; @@ -459,11 +455,6 @@ void DestroyStream(grpc_exec_ctx *exec_ctx, grpc_transport *self, /* 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; @@ -473,7 +464,7 @@ static const grpc_transport_vtable dummy_transport_vtable = { 0, "dummy_http2", InitStream, SetPollset, SetPollsetSet, PerformStreamOp, PerformOp, DestroyStream, Destroy, - GetPeer, GetEndpoint}; + GetEndpoint}; static grpc_transport dummy_transport = {&dummy_transport_vtable}; @@ -629,7 +620,7 @@ 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> +typedef Fixture<&grpc_server_load_reporting_filter, CHECKS_NOT_LAST> LoadReportingFilter; BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, NoOp); BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, SendEmptyMetadata); @@ -639,18 +630,22 @@ BENCHMARK_TEMPLATE(BM_IsolatedFilter, LoadReportingFilter, SendEmptyMetadata); namespace isolated_call_filter { +typedef struct { grpc_call_combiner *call_combiner; } call_data; + static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *op) { + call_data *calld = static_cast<call_data *>(elem->call_data); if (op->recv_initial_metadata) { - GRPC_CLOSURE_SCHED( - exec_ctx, + GRPC_CALL_COMBINER_START( + exec_ctx, calld->call_combiner, op->payload->recv_initial_metadata.recv_initial_metadata_ready, - GRPC_ERROR_NONE); + GRPC_ERROR_NONE, "recv_initial_metadata"); } if (op->recv_message) { - GRPC_CLOSURE_SCHED(exec_ctx, op->payload->recv_message.recv_message_ready, - GRPC_ERROR_NONE); + GRPC_CALL_COMBINER_START(exec_ctx, calld->call_combiner, + op->payload->recv_message.recv_message_ready, + GRPC_ERROR_NONE, "recv_message"); } GRPC_CLOSURE_SCHED(exec_ctx, op->on_complete, GRPC_ERROR_NONE); } @@ -667,6 +662,8 @@ static void StartTransportOp(grpc_exec_ctx *exec_ctx, static grpc_error *InitCallElem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_element_args *args) { + call_data *calld = static_cast<call_data *>(elem->call_data); + calld->call_combiner = args->call_combiner; return GRPC_ERROR_NONE; } @@ -687,24 +684,19 @@ grpc_error *InitChannelElem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, 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 isolated_call_filter = { StartTransportStreamOp, StartTransportOp, - 0, + sizeof(call_data), InitCallElem, SetPollsetOrPollsetSet, DestroyCallElem, 0, InitChannelElem, DestroyChannelElem, - GetPeer, GetChannelInfo, "isolated_call_filter"}; } // namespace isolated_call_filter diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc index cb113c5254..070034fe33 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc @@ -29,6 +29,7 @@ extern "C" { #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/internal.h" +#include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/resource_quota.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/transport/static_metadata.h" @@ -154,23 +155,59 @@ class Fixture { grpc_transport *t_; }; -static void DoNothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} +class Closure : public grpc_closure { + public: + virtual ~Closure() {} +}; + +template <class F> +std::unique_ptr<Closure> MakeClosure( + F f, grpc_closure_scheduler *sched = grpc_schedule_on_exec_ctx) { + struct C : public Closure { + C(const F &f, grpc_closure_scheduler *sched) : f_(f) { + GRPC_CLOSURE_INIT(this, Execute, this, sched); + } + F f_; + static void Execute(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + static_cast<C *>(arg)->f_(exec_ctx, error); + } + }; + return std::unique_ptr<Closure>(new C(f, sched)); +} + +template <class F> +grpc_closure *MakeOnceClosure( + F f, grpc_closure_scheduler *sched = grpc_schedule_on_exec_ctx) { + struct C : public grpc_closure { + C(const F &f) : f_(f) {} + F f_; + static void Execute(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + static_cast<C *>(arg)->f_(exec_ctx, error); + delete static_cast<C *>(arg); + } + }; + auto *c = new C{f}; + return GRPC_CLOSURE_INIT(c, C::Execute, c, sched); +} class Stream { public: Stream(Fixture *f) : f_(f) { - GRPC_STREAM_REF_INIT(&refcount_, 1, DoNothing, nullptr, "test_stream"); stream_size_ = grpc_transport_stream_size(f->transport()); stream_ = gpr_malloc(stream_size_); arena_ = gpr_arena_create(4096); } ~Stream() { + gpr_event_wait(&done_, gpr_inf_future(GPR_CLOCK_REALTIME)); gpr_free(stream_); gpr_arena_destroy(arena_); } void Init(benchmark::State &state) { + GRPC_STREAM_REF_INIT(&refcount_, 1, &Stream::FinishDestroy, this, + "test_stream"); + gpr_event_init(&done_); memset(stream_, 0, stream_size_); if ((state.iterations() & 0xffff) == 0) { gpr_arena_destroy(arena_); @@ -181,13 +218,17 @@ class Stream { NULL, arena_); } - void DestroyThen(grpc_closure *closure) { - grpc_transport_destroy_stream(f_->exec_ctx(), f_->transport(), - static_cast<grpc_stream *>(stream_), closure); + void DestroyThen(grpc_exec_ctx *exec_ctx, grpc_closure *closure) { + destroy_closure_ = closure; +#ifndef NDEBUG + grpc_stream_unref(exec_ctx, &refcount_, "DestroyThen"); +#else + grpc_stream_unref(exec_ctx, &refcount_); +#endif } - void Op(grpc_transport_stream_op_batch *op) { - grpc_transport_perform_stream_op(f_->exec_ctx(), f_->transport(), + void Op(grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op) { + grpc_transport_perform_stream_op(exec_ctx, f_->transport(), static_cast<grpc_stream *>(stream_), op); } @@ -196,48 +237,24 @@ class Stream { } private: + static void FinishDestroy(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + auto stream = static_cast<Stream *>(arg); + grpc_transport_destroy_stream(exec_ctx, stream->f_->transport(), + static_cast<grpc_stream *>(stream->stream_), + stream->destroy_closure_); + gpr_event_set(&stream->done_, (void *)1); + } + Fixture *f_; grpc_stream_refcount refcount_; gpr_arena *arena_; size_t stream_size_; void *stream_; + grpc_closure *destroy_closure_ = nullptr; + gpr_event done_; }; -class Closure : public grpc_closure { - public: - virtual ~Closure() {} -}; - -template <class F> -std::unique_ptr<Closure> MakeClosure( - F f, grpc_closure_scheduler *sched = grpc_schedule_on_exec_ctx) { - struct C : public Closure { - C(const F &f, grpc_closure_scheduler *sched) : f_(f) { - GRPC_CLOSURE_INIT(this, Execute, this, sched); - } - F f_; - static void Execute(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - static_cast<C *>(arg)->f_(exec_ctx, error); - } - }; - return std::unique_ptr<Closure>(new C(f, sched)); -} - -template <class F> -grpc_closure *MakeOnceClosure( - F f, grpc_closure_scheduler *sched = grpc_schedule_on_exec_ctx) { - struct C : public grpc_closure { - C(const F &f) : f_(f) {} - F f_; - static void Execute(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - static_cast<C *>(arg)->f_(exec_ctx, error); - delete static_cast<C *>(arg); - } - }; - auto *c = new C{f}; - return GRPC_CLOSURE_INIT(c, C::Execute, c, sched); -} - //////////////////////////////////////////////////////////////////////////////// // Benchmarks // @@ -246,11 +263,18 @@ static void BM_StreamCreateDestroy(benchmark::State &state) { TrackCounters track_counters; Fixture f(grpc::ChannelArguments(), true); Stream s(&f); + grpc_transport_stream_op_batch op; + grpc_transport_stream_op_batch_payload op_payload; + memset(&op, 0, sizeof(op)); + op.cancel_stream = true; + op.payload = &op_payload; + op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED; std::unique_ptr<Closure> next = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { if (!state.KeepRunning()) return; s.Init(state); - s.DestroyThen(next.get()); + s.Op(exec_ctx, &op); + s.DestroyThen(exec_ctx, next.get()); }); GRPC_CLOSURE_RUN(f.exec_ctx(), next.get(), GRPC_ERROR_NONE); f.FlushExecCtx(); @@ -286,6 +310,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State &state) { Stream s(&f); grpc_transport_stream_op_batch op; grpc_transport_stream_op_batch_payload op_payload; + memset(&op_payload, 0, sizeof(op_payload)); std::unique_ptr<Closure> start; std::unique_ptr<Closure> done; @@ -313,14 +338,14 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State &state) { op.on_complete = done.get(); op.send_initial_metadata = true; op.payload->send_initial_metadata.send_initial_metadata = &b; - s.Op(&op); + s.Op(exec_ctx, &op); }); done = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { reset_op(); op.cancel_stream = true; op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED; - s.Op(&op); - s.DestroyThen(start.get()); + s.Op(exec_ctx, &op); + s.DestroyThen(exec_ctx, start.get()); }); GRPC_CLOSURE_SCHED(f.exec_ctx(), start.get(), GRPC_ERROR_NONE); f.FlushExecCtx(); @@ -337,6 +362,7 @@ static void BM_TransportEmptyOp(benchmark::State &state) { s.Init(state); grpc_transport_stream_op_batch op; grpc_transport_stream_op_batch_payload op_payload; + memset(&op_payload, 0, sizeof(op_payload)); auto reset_op = [&]() { memset(&op, 0, sizeof(op)); op.payload = &op_payload; @@ -346,24 +372,31 @@ static void BM_TransportEmptyOp(benchmark::State &state) { if (!state.KeepRunning()) return; reset_op(); op.on_complete = c.get(); - s.Op(&op); + s.Op(exec_ctx, &op); }); GRPC_CLOSURE_SCHED(f.exec_ctx(), c.get(), GRPC_ERROR_NONE); f.FlushExecCtx(); - s.DestroyThen( - MakeOnceClosure([](grpc_exec_ctx *exec_ctx, grpc_error *error) {})); + reset_op(); + op.cancel_stream = true; + op_payload.cancel_stream.cancel_error = GRPC_ERROR_CANCELLED; + s.Op(f.exec_ctx(), &op); + s.DestroyThen(f.exec_ctx(), MakeOnceClosure([](grpc_exec_ctx *exec_ctx, + grpc_error *error) {})); f.FlushExecCtx(); track_counters.Finish(state); } BENCHMARK(BM_TransportEmptyOp); +std::vector<std::unique_ptr<gpr_event>> done_events; + static void BM_TransportStreamSend(benchmark::State &state) { TrackCounters track_counters; Fixture f(grpc::ChannelArguments(), true); - Stream s(&f); - s.Init(state); + auto s = std::unique_ptr<Stream>(new Stream(&f)); + s->Init(state); grpc_transport_stream_op_batch op; grpc_transport_stream_op_batch_payload op_payload; + memset(&op_payload, 0, sizeof(op_payload)); auto reset_op = [&]() { memset(&op, 0, sizeof(op)); op.payload = &op_payload; @@ -387,11 +420,17 @@ static void BM_TransportStreamSend(benchmark::State &state) { grpc_metadata_batch_add_tail(f.exec_ctx(), &b, &storage[i], elems[i]))); } + gpr_event *bm_done = new gpr_event; + gpr_event_init(bm_done); + std::unique_ptr<Closure> c = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { - if (!state.KeepRunning()) return; + if (!state.KeepRunning()) { + gpr_event_set(bm_done, (void *)1); + return; + } // force outgoing window to be yuge - s.chttp2_stream()->flow_control.remote_window_delta = + s->chttp2_stream()->flow_control.remote_window_delta = 1024 * 1024 * 1024; f.chttp2_transport()->flow_control.remote_window = 1024 * 1024 * 1024; grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0); @@ -399,23 +438,27 @@ static void BM_TransportStreamSend(benchmark::State &state) { op.on_complete = c.get(); op.send_message = true; op.payload->send_message.send_message = &send_stream.base; - s.Op(&op); + s->Op(exec_ctx, &op); }); reset_op(); op.send_initial_metadata = true; op.payload->send_initial_metadata.send_initial_metadata = &b; op.on_complete = c.get(); - s.Op(&op); + s->Op(f.exec_ctx(), &op); f.FlushExecCtx(); + gpr_event_wait(bm_done, gpr_inf_future(GPR_CLOCK_REALTIME)); + done_events.emplace_back(bm_done); + reset_op(); op.cancel_stream = true; op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED; - s.Op(&op); - s.DestroyThen( - MakeOnceClosure([](grpc_exec_ctx *exec_ctx, grpc_error *error) {})); + s->Op(f.exec_ctx(), &op); + s->DestroyThen(f.exec_ctx(), MakeOnceClosure([](grpc_exec_ctx *exec_ctx, + grpc_error *error) {})); f.FlushExecCtx(); + s.reset(); track_counters.Finish(state); grpc_metadata_batch_destroy(f.exec_ctx(), &b); grpc_slice_buffer_destroy(&send_buffer); @@ -485,6 +528,7 @@ static void BM_TransportStreamRecv(benchmark::State &state) { Stream s(&f); s.Init(state); grpc_transport_stream_op_batch_payload op_payload; + memset(&op_payload, 0, sizeof(op_payload)); grpc_transport_stream_op_batch op; grpc_byte_stream *recv_stream; grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384); @@ -531,7 +575,7 @@ static void BM_TransportStreamRecv(benchmark::State &state) { op.recv_message = true; op.payload->recv_message.recv_message = &recv_stream; op.payload->recv_message.recv_message_ready = drain_start.get(); - s.Op(&op); + s.Op(exec_ctx, &op); f.PushInput(grpc_slice_ref(incoming_data)); }); @@ -574,7 +618,7 @@ static void BM_TransportStreamRecv(benchmark::State &state) { op.payload->recv_initial_metadata.recv_initial_metadata_ready = do_nothing.get(); op.on_complete = c.get(); - s.Op(&op); + s.Op(f.exec_ctx(), &op); f.PushInput(SLICE_FROM_BUFFER( "\x00\x00\x00\x04\x00\x00\x00\x00\x00" // Generated using: @@ -592,9 +636,9 @@ static void BM_TransportStreamRecv(benchmark::State &state) { reset_op(); op.cancel_stream = true; op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED; - s.Op(&op); - s.DestroyThen( - MakeOnceClosure([](grpc_exec_ctx *exec_ctx, grpc_error *error) {})); + s.Op(f.exec_ctx(), &op); + s.DestroyThen(f.exec_ctx(), MakeOnceClosure([](grpc_exec_ctx *exec_ctx, + grpc_error *error) {})); f.FlushExecCtx(); track_counters.Finish(state); grpc_metadata_batch_destroy(f.exec_ctx(), &b); diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc index f109fe6251..9d71d3990d 100644 --- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc +++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc @@ -38,6 +38,8 @@ struct grpc_pollset { namespace grpc { namespace testing { +auto& force_library_initialization = Library::get(); + static void* g_tag = (void*)(intptr_t)10; // Some random number static grpc_completion_queue* g_cq; static grpc_event_engine_vtable g_vtable; diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc index 0712a40018..655e032faf 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc @@ -18,13 +18,7 @@ /* Benchmark gRPC end2end in various configurations */ -#include <benchmark/benchmark.h> -#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 "test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h" namespace grpc { namespace testing { @@ -33,365 +27,6 @@ namespace testing { auto& force_library_initialization = Library::get(); /******************************************************************************* - * BENCHMARKING KERNELS - */ - -static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); } - -// 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()) { - GPR_TIMER_SCOPE("BenchmarkCycle", 0); - 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); -} - -// Repeatedly makes Streaming Bidi calls (exchanging a configurable number of -// messages in each call) in a loop on a single channel. Different from -// BM_StreamingPingPong we are using stream coalescing api, e.g. WriteLast, -// WriteAndFinish, set_initial_metadata_corked. These apis aim at saving -// sendmsg syscalls for streaming by coalescing 1. initial metadata with first -// message; 2. final streaming message with trailing metadata. -// -// 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): -// Third parameter (i.e state.range(2)): Switch between using WriteAndFinish -// API and WriteLast API for server. -template <class Fixture, class ClientContextMutator, class ServerContextMutator> -static void BM_StreamingPingPongWithCoalescingApi(benchmark::State& state) { - const int msg_size = state.range(0); - const int max_ping_pongs = state.range(1); - // This options is used to test out server API: WriteLast and WriteAndFinish - // respectively, since we can not use both of them on server side at the same - // time. Value 1 means we are testing out the WriteAndFinish API, and - // otherwise we are testing out the WriteLast API. - const int write_and_finish = state.range(2); - - 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); - cli_ctx.set_initial_metadata_corked(true); - // tag:1 here will never comes up, since we are not performing any op due - // to initial metadata coalescing. - auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1)); - - void* t; - bool ok; - int need_tags; - - // Send 'max_ping_pongs' number of ping pong messages - int ping_pong_cnt = 0; - while (ping_pong_cnt < max_ping_pongs) { - if (ping_pong_cnt == max_ping_pongs - 1) { - request_rw->WriteLast(send_request, WriteOptions(), tag(2)); - } else { - request_rw->Write(send_request, tag(2)); // Start client send - } - - need_tags = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5); - - if (ping_pong_cnt == 0) { - // wait for the server call structure (call_hook, etc.) to be - // initialized (async stream between client side and server side - // established). It is necessary when client init metadata is - // coalesced - GPR_ASSERT(fixture->cq()->Next(&t, &ok)); - while ((int)(intptr_t)t != 0) { - // In some cases tag:2 comes before tag:0 (write tag comes out - // first), this while loop is to make sure get tag:0. - int i = (int)(intptr_t)t; - GPR_ASSERT(need_tags & (1 << i)); - need_tags &= ~(1 << i); - GPR_ASSERT(fixture->cq()->Next(&t, &ok)); - } - } - - response_rw.Read(&recv_request, tag(3)); // Start server recv - request_rw->Read(&recv_response, tag(4)); // Start client recv - - 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 == 3) { - if (ping_pong_cnt == max_ping_pongs - 1) { - if (write_and_finish == 1) { - response_rw.WriteAndFinish(send_response, WriteOptions(), - Status::OK, tag(5)); - } else { - response_rw.WriteLast(send_response, WriteOptions(), tag(5)); - // WriteLast buffers the write, so neither server write op nor - // client read op will finish inside the while loop. - need_tags &= ~(1 << 4); - need_tags &= ~(1 << 5); - } - } else { - response_rw.Write(send_response, tag(5)); - } - } - - GPR_ASSERT(need_tags & (1 << i)); - need_tags &= ~(1 << i); - } - - ping_pong_cnt++; - } - - if (max_ping_pongs == 0) { - need_tags = (1 << 6) | (1 << 7) | (1 << 8); - } else { - if (write_and_finish == 1) { - need_tags = (1 << 8); - } else { - // server's buffered write and the client's read of the buffered write - // tags should come up. - need_tags = (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8); - } - } - - // No message write or initial metadata write happened yet. - if (max_ping_pongs == 0) { - request_rw->WritesDone(tag(6)); - // wait for server call data structure(call_hook, etc.) to be - // initialized, since initial metadata is corked. - GPR_ASSERT(fixture->cq()->Next(&t, &ok)); - while ((int)(intptr_t)t != 0) { - int i = (int)(intptr_t)t; - GPR_ASSERT(need_tags & (1 << i)); - need_tags &= ~(1 << i); - GPR_ASSERT(fixture->cq()->Next(&t, &ok)); - } - response_rw.Finish(Status::OK, tag(7)); - } else { - if (write_and_finish != 1) { - response_rw.Finish(Status::OK, tag(7)); - } - } - - Status recv_status; - request_rw->Finish(&recv_status, tag(8)); - - 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); -} - -/******************************************************************************* * CONFIGURATIONS */ diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc index 6fbf9da0ad..c7ceacd320 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc @@ -18,157 +18,18 @@ /* Benchmark gRPC end2end in various configurations */ -#include <benchmark/benchmark.h> -#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 "test/cpp/microbenchmarks/fullstack_streaming_pump.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); - } - response_rw.Finish(Status::OK, tag(0)); - Status final_status; - request_rw->Finish(&final_status, 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); - } - GPR_ASSERT(final_status.ok()); - } - 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 */ +// force library initialization +auto& force_library_initialization = Library::get(); + BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, TCP) ->Range(0, 128 * 1024 * 1024); BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS) diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index 5c44b9751f..59fb29dd60 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -26,6 +26,7 @@ #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 "test/cpp/util/test_config.h" extern "C" { #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/internal.h" @@ -104,7 +105,7 @@ class TrickledCHTTP2 : public EndpointPairFixture { (double)state.iterations()); } - void Log(int64_t iteration) { + void Log(int64_t iteration) GPR_ATTRIBUTE_NO_TSAN { auto now = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), start_); grpc_chttp2_transport* client = reinterpret_cast<grpc_chttp2_transport*>(client_transport_); @@ -192,7 +193,8 @@ class TrickledCHTTP2 : public EndpointPairFixture { return p; } - void UpdateStats(grpc_chttp2_transport* t, Stats* s, size_t backlog) { + void UpdateStats(grpc_chttp2_transport* t, Stats* s, + size_t backlog) GPR_ATTRIBUTE_NO_TSAN { if (backlog == 0) { if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != NULL) { s->streams_stalled_due_to_stream_flow_control++; @@ -420,6 +422,6 @@ BENCHMARK(BM_PumpUnbalancedUnary_Trickle)->Apply(UnaryTrickleArgs); int main(int argc, char** argv) { ::benchmark::Initialize(&argc, argv); - ::google::ParseCommandLineFlags(&argc, &argv, false); + ::grpc::testing::InitTest(&argc, &argv, false); ::benchmark::RunSpecifiedBenchmarks(); } diff --git a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc index 9af751245f..fa41d114c0 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc @@ -18,13 +18,7 @@ /* Benchmark gRPC end2end in various configurations */ -#include <benchmark/benchmark.h> -#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 "test/cpp/microbenchmarks/fullstack_unary_ping_pong.h" namespace grpc { namespace testing { @@ -33,85 +27,6 @@ namespace testing { 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 */ diff --git a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h new file mode 100644 index 0000000000..ff1f966753 --- /dev/null +++ b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h @@ -0,0 +1,396 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* Benchmark gRPC end2end in various configurations */ + +#ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_STREAMING_PING_PONG_H +#define TEST_CPP_MICROBENCHMARKS_FULLSTACK_STREAMING_PING_PONG_H + +#include <benchmark/benchmark.h> +#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" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * BENCHMARKING KERNELS + */ + +static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); } + +// 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()) { + GPR_TIMER_SCOPE("BenchmarkCycle", 0); + 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); +} + +// Repeatedly makes Streaming Bidi calls (exchanging a configurable number of +// messages in each call) in a loop on a single channel. Different from +// BM_StreamingPingPong we are using stream coalescing api, e.g. WriteLast, +// WriteAndFinish, set_initial_metadata_corked. These apis aim at saving +// sendmsg syscalls for streaming by coalescing 1. initial metadata with first +// message; 2. final streaming message with trailing metadata. +// +// 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): +// Third parameter (i.e state.range(2)): Switch between using WriteAndFinish +// API and WriteLast API for server. +template <class Fixture, class ClientContextMutator, class ServerContextMutator> +static void BM_StreamingPingPongWithCoalescingApi(benchmark::State& state) { + const int msg_size = state.range(0); + const int max_ping_pongs = state.range(1); + // This options is used to test out server API: WriteLast and WriteAndFinish + // respectively, since we can not use both of them on server side at the same + // time. Value 1 means we are testing out the WriteAndFinish API, and + // otherwise we are testing out the WriteLast API. + const int write_and_finish = state.range(2); + + 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); + cli_ctx.set_initial_metadata_corked(true); + // tag:1 here will never comes up, since we are not performing any op due + // to initial metadata coalescing. + auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1)); + + void* t; + bool ok; + int need_tags; + + // Send 'max_ping_pongs' number of ping pong messages + int ping_pong_cnt = 0; + while (ping_pong_cnt < max_ping_pongs) { + if (ping_pong_cnt == max_ping_pongs - 1) { + request_rw->WriteLast(send_request, WriteOptions(), tag(2)); + } else { + request_rw->Write(send_request, tag(2)); // Start client send + } + + need_tags = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5); + + if (ping_pong_cnt == 0) { + // wait for the server call structure (call_hook, etc.) to be + // initialized (async stream between client side and server side + // established). It is necessary when client init metadata is + // coalesced + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + while ((int)(intptr_t)t != 0) { + // In some cases tag:2 comes before tag:0 (write tag comes out + // first), this while loop is to make sure get tag:0. + int i = (int)(intptr_t)t; + GPR_ASSERT(need_tags & (1 << i)); + need_tags &= ~(1 << i); + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + } + } + + response_rw.Read(&recv_request, tag(3)); // Start server recv + request_rw->Read(&recv_response, tag(4)); // Start client recv + + 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 == 3) { + if (ping_pong_cnt == max_ping_pongs - 1) { + if (write_and_finish == 1) { + response_rw.WriteAndFinish(send_response, WriteOptions(), + Status::OK, tag(5)); + } else { + response_rw.WriteLast(send_response, WriteOptions(), tag(5)); + // WriteLast buffers the write, so neither server write op nor + // client read op will finish inside the while loop. + need_tags &= ~(1 << 4); + need_tags &= ~(1 << 5); + } + } else { + response_rw.Write(send_response, tag(5)); + } + } + + GPR_ASSERT(need_tags & (1 << i)); + need_tags &= ~(1 << i); + } + + ping_pong_cnt++; + } + + if (max_ping_pongs == 0) { + need_tags = (1 << 6) | (1 << 7) | (1 << 8); + } else { + if (write_and_finish == 1) { + need_tags = (1 << 8); + } else { + // server's buffered write and the client's read of the buffered write + // tags should come up. + need_tags = (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8); + } + } + + // No message write or initial metadata write happened yet. + if (max_ping_pongs == 0) { + request_rw->WritesDone(tag(6)); + // wait for server call data structure(call_hook, etc.) to be + // initialized, since initial metadata is corked. + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + while ((int)(intptr_t)t != 0) { + int i = (int)(intptr_t)t; + GPR_ASSERT(need_tags & (1 << i)); + need_tags &= ~(1 << i); + GPR_ASSERT(fixture->cq()->Next(&t, &ok)); + } + response_rw.Finish(Status::OK, tag(7)); + } else { + if (write_and_finish != 1) { + response_rw.Finish(Status::OK, tag(7)); + } + } + + Status recv_status; + request_rw->Finish(&recv_status, tag(8)); + + 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); +} +} // namespace testing +} // namespace grpc + +#endif // TEST_CPP_MICROBENCHMARKS_FULLSTACK_STREAMING_PING_PONG_H diff --git a/test/cpp/microbenchmarks/fullstack_streaming_pump.h b/test/cpp/microbenchmarks/fullstack_streaming_pump.h new file mode 100644 index 0000000000..f9db212b02 --- /dev/null +++ b/test/cpp/microbenchmarks/fullstack_streaming_pump.h @@ -0,0 +1,170 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* Benchmark gRPC end2end in various configurations */ + +#ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_STREAMING_PUMP_H +#define TEST_CPP_MICROBENCHMARKS_FULLSTACK_STREAMING_PUMP_H + +#include <benchmark/benchmark.h> +#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" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * 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); + } + response_rw.Finish(Status::OK, tag(0)); + Status final_status; + request_rw->Finish(&final_status, 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); + } + GPR_ASSERT(final_status.ok()); + } + 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()); +} +} // namespace testing +} // namespace grpc + +#endif // TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H diff --git a/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h new file mode 100644 index 0000000000..76d278b2a0 --- /dev/null +++ b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h @@ -0,0 +1,116 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* Benchmark gRPC end2end in various configurations */ + +#ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_UNARY_PING_PONG_H +#define TEST_CPP_MICROBENCHMARKS_FULLSTACK_UNARY_PING_PONG_H + +#include <benchmark/benchmark.h> +#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" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * 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()); +} +} // namespace testing +} // namespace grpc + +#endif // TEST_CPP_MICROBENCHMARKS_FULLSTACK_UNARY_PING_PONG_H diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc index 0c10d6c4ce..b0caa48cd0 100644 --- a/test/cpp/microbenchmarks/helpers.cc +++ b/test/cpp/microbenchmarks/helpers.cc @@ -29,6 +29,20 @@ void TrackCounters::Finish(benchmark::State &state) { } void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) { + grpc_stats_data stats_end; + grpc_stats_collect(&stats_end); + grpc_stats_data stats; + grpc_stats_diff(&stats_end, &stats_begin_, &stats); + for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) { + out << " " << grpc_stats_counter_name[i] + << "/iter:" << ((double)stats.counters[i] / (double)state.iterations()); + } + for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) { + out << " " << grpc_stats_histogram_name[i] << "-median:" + << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 50.0) + << " " << grpc_stats_histogram_name[i] << "-99p:" + << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0); + } #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) - diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h index c81d95a4ea..07dd611709 100644 --- a/test/cpp/microbenchmarks/helpers.h +++ b/test/cpp/microbenchmarks/helpers.h @@ -23,6 +23,7 @@ extern "C" { #include <grpc/support/port_platform.h> +#include "src/core/lib/debug/stats.h" #include "test/core/util/memory_counters.h" } @@ -62,10 +63,12 @@ extern "C" gpr_atm gpr_now_call_count; class TrackCounters { public: + TrackCounters() { grpc_stats_collect(&stats_begin_); } virtual void Finish(benchmark::State& state); virtual void AddToLabel(std::ostream& out, benchmark::State& state); private: + grpc_stats_data stats_begin_; #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_ = diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD index b3348b76fa..3352269517 100644 --- a/test/cpp/qps/BUILD +++ b/test/cpp/qps/BUILD @@ -14,14 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary", "grpc_package") -package( - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/qps") grpc_cc_library( name = "parse_json", @@ -51,6 +46,7 @@ grpc_cc_library( ":usage_timer", "//:grpc", "//:grpc++", + "//:grpc++_core_stats", "//src/proto/grpc/testing:control_proto", "//src/proto/grpc/testing:payloads_proto", "//src/proto/grpc/testing:services_proto", diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index 6c4d92e859..7fbaf63492 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -31,10 +31,10 @@ #include <grpc/support/log.h> #include <grpc/support/time.h> -#include "src/core/lib/surface/completion_queue.h" #include "src/proto/grpc/testing/payloads.pb.h" #include "src/proto/grpc/testing/services.grpc.pb.h" +#include "src/cpp/util/core_stats.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/interarrival.h" #include "test/cpp/qps/usage_timer.h" @@ -173,6 +173,9 @@ class Client { timer_result = timer_->Mark(); } + grpc_stats_data core_stats; + grpc_stats_collect(&core_stats); + ClientStats stats; latencies.FillProto(stats.mutable_latencies()); for (StatusHistogram::const_iterator it = statuses.begin(); @@ -185,6 +188,7 @@ class Client { stats.set_time_system(timer_result.system); stats.set_time_user(timer_result.user); stats.set_cq_poll_count(poll_count); + CoreStatsToProto(core_stats, stats.mutable_core_stats()); return stats; } @@ -370,12 +374,11 @@ class ClientImpl : public Client { ClientImpl(const ClientConfig& config, std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> create_stub) - : cores_(gpr_cpu_num_cores()), - channels_(config.client_channels()), - create_stub_(create_stub) { + : cores_(gpr_cpu_num_cores()), create_stub_(create_stub) { for (int i = 0; i < config.client_channels(); i++) { - channels_[i].init(config.server_targets(i % config.server_targets_size()), - config, create_stub_, i); + channels_.emplace_back( + config.server_targets(i % config.server_targets_size()), config, + create_stub_, i); } ClientRequestCreator<RequestType> create_req(&request_, @@ -389,20 +392,11 @@ class ClientImpl : public Client { class ClientChannelInfo { public: - ClientChannelInfo() {} - ClientChannelInfo(const ClientChannelInfo& i) { - // The copy constructor is to satisfy old compilers - // that need it for using std::vector . It is only ever - // used for empty entries - GPR_ASSERT(!i.channel_ && !i.stub_); - } - void init(const grpc::string& target, const ClientConfig& config, - std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> - create_stub, - int shard) { - // We have to use a 2-phase init like this with a default - // constructor followed by an initializer function to make - // old compilers happy with using this in std::vector + ClientChannelInfo( + const grpc::string& target, const ClientConfig& config, + std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> + create_stub, + int shard) { ChannelArguments args; args.SetInt("shard_to_ensure_no_subchannel_merges", shard); set_channel_args(config, &args); diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index 265f174cc5..912c871482 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -34,6 +34,7 @@ #include <grpc/support/cpu.h> #include <grpc/support/log.h> +#include "src/core/lib/surface/completion_queue.h" #include "src/proto/grpc/testing/services.grpc.pb.h" #include "test/cpp/qps/client.h" #include "test/cpp/qps/usage_timer.h" @@ -140,7 +141,8 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext { if (!next_issue_) { // ready to issue RunNextState(true, nullptr); } else { // wait for the issue time - alarm_.reset(new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + alarm_.reset(new Alarm); + alarm_->Set(cq_, next_issue_(), ClientRpcContext::tag(this)); } } }; @@ -359,8 +361,8 @@ class ClientRpcContextStreamingPingPongImpl : public ClientRpcContext { break; // loop around, don't return case State::WAIT: next_state_ = State::READY_TO_WRITE; - alarm_.reset( - new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + alarm_.reset(new Alarm); + alarm_->Set(cq_, next_issue_(), ClientRpcContext::tag(this)); return true; case State::READY_TO_WRITE: if (!ok) { @@ -517,8 +519,8 @@ class ClientRpcContextStreamingFromClientImpl : public ClientRpcContext { } break; // loop around, don't return case State::WAIT: - alarm_.reset( - new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + alarm_.reset(new Alarm); + alarm_->Set(cq_, next_issue_(), ClientRpcContext::tag(this)); next_state_ = State::READY_TO_WRITE; return true; case State::READY_TO_WRITE: @@ -759,8 +761,8 @@ class ClientRpcContextGenericStreamingImpl : public ClientRpcContext { break; // loop around, don't return case State::WAIT: next_state_ = State::READY_TO_WRITE; - alarm_.reset( - new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this))); + alarm_.reset(new Alarm); + alarm_->Set(cq_, next_issue_(), ClientRpcContext::tag(this)); return true; case State::READY_TO_WRITE: if (!ok) { diff --git a/test/cpp/qps/interarrival.h b/test/cpp/qps/interarrival.h index c6e417985a..1fa310c209 100644 --- a/test/cpp/qps/interarrival.h +++ b/test/cpp/qps/interarrival.h @@ -21,7 +21,7 @@ #include <chrono> #include <cmath> -#include <cstdlib> +#include <random> #include <vector> #include <grpc++/support/config.h> @@ -75,13 +75,13 @@ class InterarrivalTimer { public: InterarrivalTimer() {} void init(const RandomDistInterface& r, int threads, int entries = 1000000) { + std::random_device devrand; + std::mt19937_64 generator(devrand()); + std::uniform_real_distribution<double> rando(0, 1); for (int i = 0; i < entries; i++) { - // rand is the only choice that is portable across POSIX and Windows - // and that supports new and old compilers - const double uniform_0_1 = - static_cast<double>(rand()) / static_cast<double>(RAND_MAX); random_table_.push_back( - static_cast<int64_t>(1e9 * r.transform(uniform_0_1))); + static_cast<int64_t>(1e9 * r.transform(rando(generator)))); + ; } // Now set up the thread positions for (int i = 0; i < threads; i++) { diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc index a45b10bcb8..3c99bda144 100644 --- a/test/cpp/qps/report.cc +++ b/test/cpp/qps/report.cc @@ -26,6 +26,7 @@ #include "test/cpp/qps/stats.h" #include <grpc++/client_context.h> +#include "src/cpp/util/core_stats.h" #include "src/proto/grpc/testing/services.grpc.pb.h" namespace grpc { @@ -85,6 +86,33 @@ void GprLogReporter::ReportQPS(const ScenarioResult& result) { gpr_log(GPR_INFO, "successful requests/second: %.1f", result.summary().successful_requests_per_second()); } + for (int i = 0; i < result.client_stats_size(); i++) { + if (result.client_stats(i).has_core_stats()) { + ReportCoreStats("CLIENT", i, result.client_stats(i).core_stats()); + } + } + for (int i = 0; i < result.server_stats_size(); i++) { + if (result.server_stats(i).has_core_stats()) { + ReportCoreStats("SERVER", i, result.server_stats(i).core_stats()); + } + } +} + +void GprLogReporter::ReportCoreStats(const char* name, int idx, + const grpc::core::Stats& stats) { + grpc_stats_data data; + ProtoToCoreStats(stats, &data); + for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) { + gpr_log(GPR_DEBUG, "%s[%d].%s = %" PRIdPTR, name, idx, + grpc_stats_counter_name[i], data.counters[i]); + } + for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) { + gpr_log(GPR_DEBUG, "%s[%d].%s = %lf/%lf/%lf (50/95/99%%-ile)", name, idx, + grpc_stats_histogram_name[i], + grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 50), + grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 95), + grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 99)); + } } void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) { diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h index 321be2a97f..1d7b2b54e7 100644 --- a/test/cpp/qps/report.h +++ b/test/cpp/qps/report.h @@ -104,6 +104,9 @@ class GprLogReporter : public Reporter { void ReportCpuUsage(const ScenarioResult& result) override; void ReportPollCount(const ScenarioResult& result) override; void ReportQueriesPerCpuSec(const ScenarioResult& result) override; + + void ReportCoreStats(const char* name, int idx, + const grpc::core::Stats& stats); }; /** Dumps the report to a JSON file. */ diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index df27a4368e..16d101d5e6 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -26,7 +26,7 @@ #include <grpc/support/log.h> #include <vector> -#include "src/core/lib/surface/completion_queue.h" +#include "src/cpp/util/core_stats.h" #include "src/proto/grpc/testing/control.pb.h" #include "src/proto/grpc/testing/messages.pb.h" #include "test/core/end2end/data/ssl_test_data.h" @@ -64,6 +64,9 @@ class Server { timer_result = timer_->Mark(); } + grpc_stats_data core_stats; + grpc_stats_collect(&core_stats); + ServerStats stats; stats.set_time_elapsed(timer_result.wall); stats.set_time_system(timer_result.system); @@ -71,6 +74,7 @@ class Server { stats.set_total_cpu_time(timer_result.total_cpu_time); stats.set_idle_cpu_time(timer_result.idle_cpu_time); stats.set_cq_poll_count(poll_count); + CoreStatsToProto(core_stats, stats.mutable_core_stats()); return stats; } diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 8b00bcfeaf..4a82f98199 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -35,6 +35,7 @@ #include <grpc/support/host_port.h> #include <grpc/support/log.h> +#include "src/core/lib/surface/completion_queue.h" #include "src/proto/grpc/testing/services.grpc.pb.h" #include "test/core/util/test_config.h" #include "test/cpp/qps/server.h" diff --git a/test/cpp/server/BUILD b/test/cpp/server/BUILD index 3f63be2aa3..7538845803 100644 --- a/test/cpp/server/BUILD +++ b/test/cpp/server/BUILD @@ -14,7 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary") +load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary", "grpc_package") + +grpc_package(name = "test/cpp/server") grpc_cc_test( name = "server_builder_test", diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD index fbdec05698..2559c18c32 100644 --- a/test/cpp/util/BUILD +++ b/test/cpp/util/BUILD @@ -14,15 +14,9 @@ licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_binary", "grpc_cc_test") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_binary", "grpc_cc_test", "grpc_package") -package( - default_visibility = ["//visibility:public"], - features = [ - "-layering_check", - "-parse_headers", - ], -) +grpc_package(name = "test/cpp/util", visibility = "public") grpc_cc_library( name = "test_config", |