diff options
Diffstat (limited to 'test/core')
41 files changed, 1904 insertions, 164 deletions
diff --git a/test/core/census/data/context_empty.pb b/test/core/census/data/context_empty.pb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/core/census/data/context_empty.pb diff --git a/test/core/census/data/context_empty.txt b/test/core/census/data/context_empty.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/core/census/data/context_empty.txt diff --git a/test/core/census/data/context_full.pb b/test/core/census/data/context_full.pb Binary files differnew file mode 100644 index 0000000000..80ebcf280b --- /dev/null +++ b/test/core/census/data/context_full.pb diff --git a/test/core/census/data/context_full.txt b/test/core/census/data/context_full.txt new file mode 100644 index 0000000000..7901a10c33 --- /dev/null +++ b/test/core/census/data/context_full.txt @@ -0,0 +1,3 @@ +trace_id { hi : 5; lo : 1 } +span_id : 7 +is_sampled : true diff --git a/test/core/census/data/context_no_sample.pb b/test/core/census/data/context_no_sample.pb Binary files differnew file mode 100644 index 0000000000..ab7ad7d109 --- /dev/null +++ b/test/core/census/data/context_no_sample.pb diff --git a/test/core/census/data/context_no_sample.txt b/test/core/census/data/context_no_sample.txt new file mode 100644 index 0000000000..150298002f --- /dev/null +++ b/test/core/census/data/context_no_sample.txt @@ -0,0 +1,2 @@ +trace_id { hi : 5; lo : 1 } +span_id : 7 diff --git a/test/core/census/data/context_span_only.pb b/test/core/census/data/context_span_only.pb Binary files differnew file mode 100644 index 0000000000..2a9527a75a --- /dev/null +++ b/test/core/census/data/context_span_only.pb diff --git a/test/core/census/data/context_span_only.txt b/test/core/census/data/context_span_only.txt new file mode 100644 index 0000000000..d90de2e614 --- /dev/null +++ b/test/core/census/data/context_span_only.txt @@ -0,0 +1,2 @@ +span_id : 7 +is_sampled : true diff --git a/test/core/census/data/context_trace_only.pb b/test/core/census/data/context_trace_only.pb Binary files differnew file mode 100644 index 0000000000..7fdf6f61a3 --- /dev/null +++ b/test/core/census/data/context_trace_only.pb diff --git a/test/core/census/data/context_trace_only.txt b/test/core/census/data/context_trace_only.txt new file mode 100644 index 0000000000..9b68a6aa92 --- /dev/null +++ b/test/core/census/data/context_trace_only.txt @@ -0,0 +1,2 @@ +trace_id { hi : 5; lo : 1 } +is_sampled : true diff --git a/test/core/census/trace_context_test.c b/test/core/census/trace_context_test.c new file mode 100644 index 0000000000..ee409e8d1a --- /dev/null +++ b/test/core/census/trace_context_test.c @@ -0,0 +1,231 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/census.h> +#include <grpc/support/log.h> +#include <grpc/support/port_platform.h> +#include <grpc/support/useful.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include "src/core/ext/census/base_resources.h" +#include "src/core/ext/census/resource.h" +#include "test/core/util/test_config.h" + +#include "src/core/ext/census/gen/trace_context.pb.h" +#include "src/core/ext/census/trace_context.h" +#include "third_party/nanopb/pb_decode.h" +#include "third_party/nanopb/pb_encode.h" + +#define BUF_SIZE 256 + +/* Encodes a TraceContext structure (ctxt1) to a buffer, and then decodes it +to a second TraceContext (ctxt2). Validates that the resulting TraceContext +has a span_id, trace_id, and that the values are equal to those in initial +TraceContext. On success, returns true. If encode_trace_context returns 0, +decode_trace_context fails, or the resulting TraceContext is missing a trace_id +or span_id, it will return false. */ +bool validate_encode_decode_context(google_trace_TraceContext *ctxt1, + uint8_t *buffer, size_t buf_size) { + google_trace_TraceContext ctxt2 = google_trace_TraceContext_init_zero; + size_t msg_length; + GPR_ASSERT(ctxt1->has_trace_id && ctxt1->has_span_id); + + msg_length = encode_trace_context(ctxt1, buffer, buf_size); + if (msg_length == 0) { + return false; + } + + if (!decode_trace_context(&ctxt2, buffer, msg_length)) { + return false; + } + + if (!ctxt2.has_trace_id || !ctxt2.has_span_id) { + return false; + } + + GPR_ASSERT( + ctxt1->trace_id.hi == ctxt2.trace_id.hi && + ctxt1->trace_id.lo == ctxt2.trace_id.lo && + ctxt1->span_id == ctxt2.span_id && + ctxt1->has_is_sampled == ctxt2.has_is_sampled && + (ctxt1->has_is_sampled ? ctxt1->is_sampled == ctxt2.is_sampled : true)); + + return true; +} + +/* Decodes a proto-encoded TraceContext from a buffer. If decode_trace_context +fails or the resulting TraceContext is missing a trace_id or span_id it will +return false, otherwise returns true. */ +bool validate_decode_context(google_trace_TraceContext *ctxt, uint8_t *buffer, + size_t msg_length) { + // Validate the decoding of a context written to buffer. + if (!decode_trace_context(ctxt, buffer, msg_length)) { + return false; + } + + if (!ctxt->has_trace_id || !ctxt->has_span_id) { + return false; + } + + return true; +} + +/* Read an encoded trace context from a file. Validates that the decoding +gives the expected result (succeed). */ +static void read_and_validate_context_from_file(google_trace_TraceContext *ctxt, + const char *file, + const bool succeed) { + uint8_t buffer[BUF_SIZE]; + FILE *input = fopen(file, "rb"); + GPR_ASSERT(input != NULL); + size_t nbytes = fread(buffer, 1, BUF_SIZE, input); + GPR_ASSERT(nbytes <= BUF_SIZE && feof(input) && !ferror(input)); + bool res = validate_decode_context(ctxt, buffer, nbytes); + GPR_ASSERT(res == succeed); + GPR_ASSERT(fclose(input) == 0); +} + +// Test full proto-buffer. +static void test_full() { + google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero; + read_and_validate_context_from_file( + &ctxt, "test/core/census/data/context_full.pb", true); +} + +// Test empty proto-buffer. +static void test_empty() { + google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero; + read_and_validate_context_from_file( + &ctxt, "test/core/census/data/context_empty.pb", false); +} + +// Test proto-buffer with only trace_id. +static void test_trace_only() { + google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero; + read_and_validate_context_from_file( + &ctxt, "test/core/census/data/context_trace_only.pb", false); +} + +// Test proto-buffer with only span_id. +static void test_span_only() { + google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero; + read_and_validate_context_from_file( + &ctxt, "test/core/census/data/context_span_only.pb", false); +} + +// Test proto-buffer without is_sampled value. +static void test_no_sample() { + google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero; + read_and_validate_context_from_file( + &ctxt, "test/core/census/data/context_no_sample.pb", true); + GPR_ASSERT(ctxt.has_is_sampled == false && ctxt.is_sampled == false); +} + +static void test_encode_decode() { + uint8_t buffer[BUF_SIZE] = {0}; + + google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero; + ctxt1.has_trace_id = true; + ctxt1.trace_id.has_hi = true; + ctxt1.trace_id.has_lo = true; + ctxt1.trace_id.lo = 1; + ctxt1.trace_id.hi = 2; + ctxt1.has_span_id = true; + ctxt1.span_id = 3; + validate_encode_decode_context(&ctxt1, buffer, sizeof(buffer)); + + google_trace_TraceContext ctxt2 = google_trace_TraceContext_init_zero; + ctxt2.has_trace_id = true; + ctxt2.trace_id.has_hi = false; + ctxt2.trace_id.has_lo = false; + ctxt2.has_span_id = true; + validate_encode_decode_context(&ctxt2, buffer, sizeof(buffer)); +} + +// Test a corrupted proto-buffer. +static void test_corrupt() { + uint8_t buffer[BUF_SIZE] = {0}; + google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero; + size_t msg_length; + + ctxt1.has_trace_id = true; + ctxt1.trace_id.has_hi = true; + ctxt1.trace_id.has_lo = true; + ctxt1.trace_id.lo = 1; + ctxt1.trace_id.hi = 2; + ctxt1.has_span_id = true; + ctxt1.span_id = 3; + ctxt1.is_sampled = true; + msg_length = encode_trace_context(&ctxt1, buffer, sizeof(buffer)); + + /* Corrupt some bytes. 255 (0xFF) should be illegal for the first byte of the + proto encoded object. */ + buffer[0] = 255; + + bool res = validate_decode_context(&ctxt1, buffer, msg_length); + GPR_ASSERT(res == false); +} + +static void test_buffer_size() { + // This buffer is too small, so the encode should fail. + uint8_t buffer[16] = {0}; + google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero; + size_t msg_length; + + ctxt1.has_trace_id = true; + ctxt1.trace_id.has_hi = true; + ctxt1.trace_id.has_lo = true; + ctxt1.trace_id.lo = 1; + ctxt1.trace_id.hi = 2; + ctxt1.has_span_id = true; + ctxt1.span_id = 3; + ctxt1.is_sampled = true; + msg_length = encode_trace_context(&ctxt1, buffer, sizeof(buffer)); + + GPR_ASSERT(msg_length == 0); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + test_full(); + test_empty(); + test_trace_only(); + test_span_only(); + test_encode_decode(); + test_corrupt(); + test_no_sample(); + test_buffer_size(); + + return 0; +} diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index 569b3f7cd2..b1c1ed9039 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -135,9 +135,9 @@ static void test_create_channel_stack(void) { GPR_ASSERT(*channel_data == 0); call_stack = gpr_malloc(channel_stack->call_stack_size); - grpc_error *error = - grpc_call_stack_init(&exec_ctx, channel_stack, 1, free_call, call_stack, - NULL, NULL, call_stack); + grpc_error *error = grpc_call_stack_init( + &exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL, + gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack); GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(call_stack->count == 1); call_elem = grpc_call_stack_element(call_stack, 0); diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c index 76254d3955..844db5e6cb 100644 --- a/test/core/client_channel/lb_policies_test.c +++ b/test/core/client_channel/lb_policies_test.c @@ -48,6 +48,7 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/server.h" #include "test/core/end2end/cq_verifier.h" +#include "test/core/end2end/fake_resolver.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -508,7 +509,7 @@ void run_spec(const test_spec *spec) { /* Create client. */ servers_hostports_str = gpr_strjoin_sep((const char **)f->servers_hostports, f->num_servers, ",", NULL); - gpr_asprintf(&client_hostport, "ipv4:%s?lb_policy=round_robin", + gpr_asprintf(&client_hostport, "test:%s?lb_policy=round_robin", servers_hostports_str); arg.type = GRPC_ARG_INTEGER; @@ -544,7 +545,7 @@ static grpc_channel *create_client(const servers_fixture *f) { servers_hostports_str = gpr_strjoin_sep((const char **)f->servers_hostports, f->num_servers, ",", NULL); - gpr_asprintf(&client_hostport, "ipv4:%s?lb_policy=round_robin", + gpr_asprintf(&client_hostport, "test:%s?lb_policy=round_robin", servers_hostports_str); arg.type = GRPC_ARG_INTEGER; @@ -874,6 +875,7 @@ int main(int argc, char **argv) { const size_t NUM_SERVERS = 4; grpc_test_init(argc, argv); + grpc_fake_resolver_init(); grpc_init(); grpc_tracer_set_enabled("round_robin", 1); diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c index c24a03b0a4..07723c229d 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c @@ -41,29 +41,6 @@ #include "src/core/lib/iomgr/timer.h" #include "test/core/util/test_config.h" -static void client_channel_factory_ref(grpc_client_channel_factory *scv) {} -static void client_channel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_client_channel_factory *scv) {} -static grpc_subchannel *client_channel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *factory, - grpc_subchannel_args *args) { - return NULL; -} - -static grpc_channel *client_channel_factory_create_channel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, - const char *target, grpc_client_channel_type type, - grpc_channel_args *args) { - GPR_UNREACHABLE_CODE(return NULL); -} - -static const grpc_client_channel_factory_vtable sc_vtable = { - client_channel_factory_ref, client_channel_factory_unref, - client_channel_factory_create_subchannel, - client_channel_factory_create_channel}; - -static grpc_client_channel_factory cc_factory = {&sc_vtable}; - static gpr_mu g_mu; static bool g_fail_resolution = true; @@ -92,7 +69,6 @@ static grpc_resolver *create_resolver(const char *name) { grpc_resolver_args args; memset(&args, 0, sizeof(args)); args.uri = uri; - args.client_channel_factory = &cc_factory; grpc_resolver *resolver = grpc_resolver_factory_create_resolver(factory, &args); grpc_resolver_factory_unref(factory); diff --git a/test/core/client_channel/resolvers/dns_resolver_test.c b/test/core/client_channel/resolvers/dns_resolver_test.c index ae3b3df950..41a9125431 100644 --- a/test/core/client_channel/resolvers/dns_resolver_test.c +++ b/test/core/client_channel/resolvers/dns_resolver_test.c @@ -38,29 +38,6 @@ #include "src/core/ext/client_channel/resolver_registry.h" #include "test/core/util/test_config.h" -static void client_channel_factory_ref(grpc_client_channel_factory *scv) {} -static void client_channel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_client_channel_factory *scv) {} -static grpc_subchannel *client_channel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *factory, - grpc_subchannel_args *args) { - GPR_UNREACHABLE_CODE(return NULL); -} - -static grpc_channel *client_channel_factory_create_channel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, - const char *target, grpc_client_channel_type type, - grpc_channel_args *args) { - GPR_UNREACHABLE_CODE(return NULL); -} - -static const grpc_client_channel_factory_vtable sc_vtable = { - client_channel_factory_ref, client_channel_factory_unref, - client_channel_factory_create_subchannel, - client_channel_factory_create_channel}; - -static grpc_client_channel_factory cc_factory = {&sc_vtable}; - static void test_succeeds(grpc_resolver_factory *factory, const char *string) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_uri *uri = grpc_uri_parse(string, 0); @@ -71,7 +48,6 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) { GPR_ASSERT(uri); memset(&args, 0, sizeof(args)); args.uri = uri; - args.client_channel_factory = &cc_factory; resolver = grpc_resolver_factory_create_resolver(factory, &args); GPR_ASSERT(resolver != NULL); GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.c b/test/core/client_channel/resolvers/sockaddr_resolver_test.c index 781d730855..c39052cd9d 100644 --- a/test/core/client_channel/resolvers/sockaddr_resolver_test.c +++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.c @@ -33,34 +33,28 @@ #include <string.h> +#include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include "src/core/ext/client_channel/resolver_registry.h" +#include "src/core/ext/client_channel/resolver_result.h" + #include "test/core/util/test_config.h" -static void client_channel_factory_ref(grpc_client_channel_factory *scv) {} -static void client_channel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_client_channel_factory *scv) {} -static grpc_subchannel *client_channel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *factory, - grpc_subchannel_args *args) { - GPR_UNREACHABLE_CODE(return NULL); -} +typedef struct on_resolution_arg { + char *expected_server_name; + grpc_resolver_result *resolver_result; +} on_resolution_arg; -static grpc_channel *client_channel_factory_create_channel( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, - const char *target, grpc_client_channel_type type, - grpc_channel_args *args) { - GPR_UNREACHABLE_CODE(return NULL); +void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + on_resolution_arg *res = arg; + const char *server_name = + grpc_resolver_result_get_server_name(res->resolver_result); + GPR_ASSERT(strcmp(res->expected_server_name, server_name) == 0); + grpc_resolver_result_unref(exec_ctx, res->resolver_result); } -static const grpc_client_channel_factory_vtable sc_vtable = { - client_channel_factory_ref, client_channel_factory_unref, - client_channel_factory_create_subchannel, - client_channel_factory_create_channel}; - -static grpc_client_channel_factory cc_factory = {&sc_vtable}; - static void test_succeeds(grpc_resolver_factory *factory, const char *string) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_uri *uri = grpc_uri_parse(string, 0); @@ -71,12 +65,20 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) { GPR_ASSERT(uri); memset(&args, 0, sizeof(args)); args.uri = uri; - args.client_channel_factory = &cc_factory; resolver = grpc_resolver_factory_create_resolver(factory, &args); GPR_ASSERT(resolver != NULL); + + on_resolution_arg on_res_arg; + memset(&on_res_arg, 0, sizeof(on_res_arg)); + on_res_arg.expected_server_name = uri->path; + grpc_closure *on_resolution = + grpc_closure_create(on_resolution_cb, &on_res_arg); + + grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result, + on_resolution); GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); - grpc_uri_destroy(uri); grpc_exec_ctx_finish(&exec_ctx); + grpc_uri_destroy(uri); } static void test_fails(grpc_resolver_factory *factory, const char *string) { diff --git a/test/core/end2end/connection_refused_test.c b/test/core/end2end/connection_refused_test.c new file mode 100644 index 0000000000..4149159a37 --- /dev/null +++ b/test/core/end2end/connection_refused_test.c @@ -0,0 +1,128 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <string.h> + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> + +#include "test/core/end2end/cq_verifier.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +static void *tag(intptr_t i) { return (void *)i; } + +static void run_test(bool fail_fast) { + grpc_channel *chan; + grpc_call *call; + gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2); + grpc_completion_queue *cq; + cq_verifier *cqv; + grpc_op ops[6]; + grpc_op *op; + grpc_metadata_array trailing_metadata_recv; + grpc_status_code status; + char *details = NULL; + size_t details_capacity = 0; + + gpr_log(GPR_INFO, "TEST: fail_fast=%d", fail_fast); + + grpc_init(); + + grpc_metadata_array_init(&trailing_metadata_recv); + + cq = grpc_completion_queue_create(NULL); + cqv = cq_verifier_create(cq); + + /* create a call, channel to a port which will refuse connection */ + int port = grpc_pick_unused_port_or_die(); + char *addr; + gpr_join_host_port(&addr, "localhost", port); + + chan = grpc_insecure_channel_create(addr, NULL, NULL); + call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq, + "/Foo", "nonexistant", deadline, NULL); + + gpr_free(addr); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = fail_fast ? 0 : GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY; + 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->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->flags = 0; + op->reserved = NULL; + op++; + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch( + call, ops, (size_t)(op - ops), tag(1), NULL)); + /* verify that all tags get completed */ + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + if (fail_fast) { + GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); + } else { + GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED); + } + + grpc_completion_queue_shutdown(cq); + while ( + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL) + .type != GRPC_QUEUE_SHUTDOWN) + ; + grpc_completion_queue_destroy(cq); + grpc_call_destroy(call); + grpc_channel_destroy(chan); + cq_verifier_destroy(cqv); + + gpr_free(details); + grpc_metadata_array_destroy(&trailing_metadata_recv); + + grpc_shutdown(); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + run_test(true); + run_test(false); + return 0; +} diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c new file mode 100644 index 0000000000..8a6624a49a --- /dev/null +++ b/test/core/end2end/fake_resolver.c @@ -0,0 +1,212 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +// This is similar to the sockaddr resolver, except that it supports a +// bunch of query args that are useful for dependency injection in tests. + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/port_platform.h> +#include <grpc/support/string_util.h> + +#include "src/core/ext/client_config/parse_address.h" +#include "src/core/ext/client_config/resolver_registry.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/unix_sockets_posix.h" +#include "src/core/lib/support/string.h" + +// +// fake_resolver +// + +typedef struct { + // base class -- must be first + grpc_resolver base; + + // passed-in parameters + char* target_name; // the path component of the uri passed in + grpc_lb_addresses* addresses; + char* lb_policy_name; + + // mutex guarding the rest of the state + gpr_mu mu; + // have we published? + bool published; + // pending next completion, or NULL + grpc_closure* next_completion; + // target result address for next completion + grpc_resolver_result** target_result; +} fake_resolver; + +static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) { + fake_resolver* r = (fake_resolver*)gr; + gpr_mu_destroy(&r->mu); + gpr_free(r->target_name); + grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */); + gpr_free(r->lb_policy_name); + gpr_free(r); +} + +static void fake_resolver_shutdown(grpc_exec_ctx* exec_ctx, + grpc_resolver* resolver) { + fake_resolver* r = (fake_resolver*)resolver; + gpr_mu_lock(&r->mu); + if (r->next_completion != NULL) { + *r->target_result = NULL; + grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); + r->next_completion = NULL; + } + gpr_mu_unlock(&r->mu); +} + +static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx, + fake_resolver* r) { + if (r->next_completion != NULL && !r->published) { + r->published = true; + *r->target_result = grpc_resolver_result_create( + r->target_name, + grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */), + r->lb_policy_name, NULL /* lb_policy_args */); + grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); + r->next_completion = NULL; + } +} + +static void fake_resolver_channel_saw_error(grpc_exec_ctx* exec_ctx, + grpc_resolver* resolver) { + fake_resolver* r = (fake_resolver*)resolver; + gpr_mu_lock(&r->mu); + r->published = false; + fake_resolver_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); +} + +static void fake_resolver_next(grpc_exec_ctx* exec_ctx, grpc_resolver* resolver, + grpc_resolver_result** target_result, + grpc_closure* on_complete) { + fake_resolver* r = (fake_resolver*)resolver; + gpr_mu_lock(&r->mu); + GPR_ASSERT(!r->next_completion); + r->next_completion = on_complete; + r->target_result = target_result; + fake_resolver_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); +} + +static const grpc_resolver_vtable fake_resolver_vtable = { + fake_resolver_destroy, fake_resolver_shutdown, + fake_resolver_channel_saw_error, fake_resolver_next}; + +// +// fake_resolver_factory +// + +static void fake_resolver_factory_ref(grpc_resolver_factory* factory) {} + +static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {} + +static void do_nothing(void* ignored) {} + +static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory, + grpc_resolver_args* args) { + if (0 != strcmp(args->uri->authority, "")) { + gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", + args->uri->scheme); + return NULL; + } + // Get lb_enabled arg. Anything other than "0" is interpreted as true. + const char* lb_enabled_qpart = + grpc_uri_get_query_arg(args->uri, "lb_enabled"); + const bool lb_enabled = + lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0; + // Construct addresses. + gpr_slice path_slice = + gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); + gpr_slice_buffer path_parts; + gpr_slice_buffer_init(&path_parts); + gpr_slice_split(path_slice, ",", &path_parts); + grpc_lb_addresses* addresses = grpc_lb_addresses_create(path_parts.count); + bool errors_found = false; + for (size_t i = 0; i < addresses->num_addresses; i++) { + grpc_uri ith_uri = *args->uri; + char* part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); + ith_uri.path = part_str; + if (!parse_ipv4( + &ith_uri, + (struct sockaddr_storage*)(&addresses->addresses[i].address.addr), + &addresses->addresses[i].address.len)) { + errors_found = true; + } + gpr_free(part_str); + addresses->addresses[i].is_balancer = lb_enabled; + if (errors_found) break; + } + gpr_slice_buffer_destroy(&path_parts); + gpr_slice_unref(path_slice); + if (errors_found) { + grpc_lb_addresses_destroy(addresses, NULL /* user_data_destroy */); + return NULL; + } + // Instantiate resolver. + fake_resolver* r = gpr_malloc(sizeof(fake_resolver)); + memset(r, 0, sizeof(*r)); + r->target_name = gpr_strdup(args->uri->path); + r->addresses = addresses; + r->lb_policy_name = + gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy")); + gpr_mu_init(&r->mu); + grpc_resolver_init(&r->base, &fake_resolver_vtable); + return &r->base; +} + +static char* fake_resolver_get_default_authority(grpc_resolver_factory* factory, + grpc_uri* uri) { + const char* path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static const grpc_resolver_factory_vtable fake_resolver_factory_vtable = { + fake_resolver_factory_ref, fake_resolver_factory_unref, + fake_resolver_create, fake_resolver_get_default_authority, "test"}; + +static grpc_resolver_factory fake_resolver_factory = { + &fake_resolver_factory_vtable}; + +void grpc_fake_resolver_init(void) { + grpc_register_resolver_type(&fake_resolver_factory); +} diff --git a/test/core/end2end/fake_resolver.h b/test/core/end2end/fake_resolver.h new file mode 100644 index 0000000000..7a30347f30 --- /dev/null +++ b/test/core/end2end/fake_resolver.h @@ -0,0 +1,39 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H +#define GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H + +#include "test/core/util/test_config.h" + +void grpc_fake_resolver_init(); + +#endif /* GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H */ diff --git a/test/core/end2end/fixtures/h2_fd.c b/test/core/end2end/fixtures/h2_fd.c index 89fa02517d..8561feed70 100644 --- a/test/core/end2end/fixtures/h2_fd.c +++ b/test/core/end2end/fixtures/h2_fd.c @@ -95,7 +95,7 @@ static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f, grpc_server_register_completion_queue(f->server, f->cq, NULL); grpc_server_start(f->server); - grpc_server_add_insecure_channel_from_fd(f->server, f->cq, sfd->fd_pair[1]); + grpc_server_add_insecure_channel_from_fd(f->server, NULL, sfd->fd_pair[1]); grpc_exec_ctx_finish(&exec_ctx); } diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c new file mode 100644 index 0000000000..a675a11f66 --- /dev/null +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -0,0 +1,129 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/core/end2end/end2end_tests.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/useful.h> +#include "src/core/ext/client_config/client_channel.h" +#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" +#include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/channel/http_server_filter.h" +#include "src/core/lib/support/env.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/server.h" +#include "test/core/end2end/fixtures/http_proxy.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +typedef struct fullstack_fixture_data { + char *server_addr; + grpc_end2end_http_proxy *proxy; +} fullstack_fixture_data; + +static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( + grpc_channel_args *client_args, grpc_channel_args *server_args) { + grpc_end2end_test_fixture f; + memset(&f, 0, sizeof(f)); + + fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data)); + const int server_port = grpc_pick_unused_port_or_die(); + gpr_join_host_port(&ffd->server_addr, "localhost", server_port); + ffd->proxy = grpc_end2end_http_proxy_create(); + + f.fixture_data = ffd; + f.cq = grpc_completion_queue_create(NULL); + + return f; +} + +void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *client_args) { + fullstack_fixture_data *ffd = f->fixture_data; + char *proxy_uri; + gpr_asprintf(&proxy_uri, "http://%s", + grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); + gpr_setenv("http_proxy", proxy_uri); + gpr_free(proxy_uri); + f->client = grpc_insecure_channel_create(ffd->server_addr, client_args, NULL); + GPR_ASSERT(f->client); +} + +void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *server_args) { + fullstack_fixture_data *ffd = f->fixture_data; + if (f->server) { + grpc_server_destroy(f->server); + } + f->server = grpc_server_create(server_args, NULL); + grpc_server_register_completion_queue(f->server, f->cq, NULL); + GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->server_addr)); + grpc_server_start(f->server); +} + +void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) { + fullstack_fixture_data *ffd = f->fixture_data; + gpr_free(ffd->server_addr); + grpc_end2end_http_proxy_destroy(ffd->proxy); + gpr_free(ffd); +} + +/* All test configurations */ +static grpc_end2end_test_config configs[] = { + {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION, + chttp2_create_fixture_fullstack, chttp2_init_client_fullstack, + chttp2_init_server_fullstack, chttp2_tear_down_fullstack}, +}; + +int main(int argc, char **argv) { + size_t i; + + grpc_test_init(argc, argv); + grpc_end2end_tests_pre_init(); + grpc_init(); + + for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) { + grpc_end2end_tests(argc, argv, configs[i]); + } + + grpc_shutdown(); + + return 0; +} diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy.c new file mode 100644 index 0000000000..22533b9694 --- /dev/null +++ b/test/core/end2end/fixtures/http_proxy.c @@ -0,0 +1,481 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/core/end2end/fixtures/http_proxy.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/atm.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> +#include <grpc/support/slice_buffer.h> +#include <grpc/support/string_util.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/useful.h> + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/http/parser.h" +#include "src/core/lib/iomgr/closure.h" +#include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/pollset.h" +#include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/tcp_client.h" +#include "src/core/lib/iomgr/tcp_server.h" +#include "test/core/util/port.h" + +struct grpc_end2end_http_proxy { + char* proxy_name; + gpr_thd_id thd; + grpc_tcp_server* server; + grpc_channel_args* channel_args; + gpr_mu* mu; + grpc_pollset* pollset; + gpr_atm shutdown; +}; + +// +// Connection handling +// + +typedef struct proxy_connection { + grpc_endpoint* client_endpoint; + grpc_endpoint* server_endpoint; + + gpr_refcount refcount; + + grpc_pollset_set* pollset_set; + + grpc_closure on_read_request_done; + grpc_closure on_server_connect_done; + grpc_closure on_write_response_done; + grpc_closure on_client_read_done; + grpc_closure on_client_write_done; + grpc_closure on_server_read_done; + grpc_closure on_server_write_done; + + gpr_slice_buffer client_read_buffer; + gpr_slice_buffer client_deferred_write_buffer; + gpr_slice_buffer client_write_buffer; + gpr_slice_buffer server_read_buffer; + gpr_slice_buffer server_deferred_write_buffer; + gpr_slice_buffer server_write_buffer; + + grpc_http_parser http_parser; + grpc_http_request http_request; +} proxy_connection; + +// Helper function to destroy the proxy connection. +static void proxy_connection_unref(grpc_exec_ctx* exec_ctx, + proxy_connection* conn) { + if (gpr_unref(&conn->refcount)) { + grpc_endpoint_destroy(exec_ctx, conn->client_endpoint); + if (conn->server_endpoint != NULL) + grpc_endpoint_destroy(exec_ctx, conn->server_endpoint); + grpc_pollset_set_destroy(conn->pollset_set); + gpr_slice_buffer_destroy(&conn->client_read_buffer); + gpr_slice_buffer_destroy(&conn->client_deferred_write_buffer); + gpr_slice_buffer_destroy(&conn->client_write_buffer); + gpr_slice_buffer_destroy(&conn->server_read_buffer); + gpr_slice_buffer_destroy(&conn->server_deferred_write_buffer); + gpr_slice_buffer_destroy(&conn->server_write_buffer); + grpc_http_parser_destroy(&conn->http_parser); + grpc_http_request_destroy(&conn->http_request); + gpr_free(conn); + } +} + +// Helper function to shut down the proxy connection. +// Does NOT take ownership of a reference to error. +static void proxy_connection_failed(grpc_exec_ctx* exec_ctx, + proxy_connection* conn, bool is_client, + const char* prefix, grpc_error* error) { + const char* msg = grpc_error_string(error); + gpr_log(GPR_INFO, "%s: %s", prefix, msg); + grpc_error_free_string(msg); + grpc_endpoint_shutdown(exec_ctx, conn->client_endpoint); + if (conn->server_endpoint != NULL) + grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint); + proxy_connection_unref(exec_ctx, conn); +} + +// Callback for writing proxy data to the client. +static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy client write", error); + return; + } + // Clear write buffer (the data we just wrote). + gpr_slice_buffer_reset_and_unref(&conn->client_write_buffer); + // If more data was read from the server since we started this write, + // write that data now. + if (conn->client_deferred_write_buffer.length > 0) { + gpr_slice_buffer_move_into(&conn->client_deferred_write_buffer, + &conn->client_write_buffer); + grpc_endpoint_write(exec_ctx, conn->client_endpoint, + &conn->client_write_buffer, + &conn->on_client_write_done); + } else { + // No more writes. Unref the connection. + proxy_connection_unref(exec_ctx, conn); + } +} + +// Callback for writing proxy data to the backend server. +static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, false /* is_client */, + "HTTP proxy server write", error); + return; + } + // Clear write buffer (the data we just wrote). + gpr_slice_buffer_reset_and_unref(&conn->server_write_buffer); + // If more data was read from the client since we started this write, + // write that data now. + if (conn->server_deferred_write_buffer.length > 0) { + gpr_slice_buffer_move_into(&conn->server_deferred_write_buffer, + &conn->server_write_buffer); + grpc_endpoint_write(exec_ctx, conn->server_endpoint, + &conn->server_write_buffer, + &conn->on_server_write_done); + } else { + // No more writes. Unref the connection. + proxy_connection_unref(exec_ctx, conn); + } +} + +// Callback for reading data from the client, which will be proxied to +// the backend server. +static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy client read", error); + return; + } + // If there is already a pending write (i.e., server_write_buffer is + // not empty), then move the read data into server_deferred_write_buffer, + // and the next write will be requested in on_server_write_done(), when + // the current write is finished. + // + // Otherwise, move the read data into the write buffer and write it. + if (conn->server_write_buffer.length > 0) { + gpr_slice_buffer_move_into(&conn->client_read_buffer, + &conn->server_deferred_write_buffer); + } else { + gpr_slice_buffer_move_into(&conn->client_read_buffer, + &conn->server_write_buffer); + gpr_ref(&conn->refcount); + grpc_endpoint_write(exec_ctx, conn->server_endpoint, + &conn->server_write_buffer, + &conn->on_server_write_done); + } + // Read more data. + grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, + &conn->on_client_read_done); +} + +// Callback for reading data from the backend server, which will be +// proxied to the client. +static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, false /* is_client */, + "HTTP proxy server read", error); + return; + } + // If there is already a pending write (i.e., client_write_buffer is + // not empty), then move the read data into client_deferred_write_buffer, + // and the next write will be requested in on_client_write_done(), when + // the current write is finished. + // + // Otherwise, move the read data into the write buffer and write it. + if (conn->client_write_buffer.length > 0) { + gpr_slice_buffer_move_into(&conn->server_read_buffer, + &conn->client_deferred_write_buffer); + } else { + gpr_slice_buffer_move_into(&conn->server_read_buffer, + &conn->client_write_buffer); + gpr_ref(&conn->refcount); + grpc_endpoint_write(exec_ctx, conn->client_endpoint, + &conn->client_write_buffer, + &conn->on_client_write_done); + } + // Read more data. + grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, + &conn->on_server_read_done); +} + +// Callback to write the HTTP response for the CONNECT request. +static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy write response", error); + return; + } + // Clear write buffer. + gpr_slice_buffer_reset_and_unref(&conn->client_write_buffer); + // Start reading from both client and server. One of the read + // requests inherits our ref to conn, but we need to take a new ref + // for the other one. + gpr_ref(&conn->refcount); + grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, + &conn->on_client_read_done); + grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, + &conn->on_server_read_done); +} + +// Callback to connect to the backend server specified by the HTTP +// CONNECT request. +static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + // TODO(roth): Technically, in this case, we should handle the error + // by returning an HTTP response to the client indicating that the + // connection failed. However, for the purposes of this test code, + // it's fine to pretend this is a client-side error, which will + // cause the client connection to be dropped. + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy server connect", error); + return; + } + // We've established a connection, so send back a 200 response code to + // the client. + // The write callback inherits our reference to conn. + gpr_slice slice = + gpr_slice_from_copied_string("HTTP/1.0 200 connected\r\n\r\n"); + gpr_slice_buffer_add(&conn->client_write_buffer, slice); + grpc_endpoint_write(exec_ctx, conn->client_endpoint, + &conn->client_write_buffer, + &conn->on_write_response_done); +} + +// Callback to read the HTTP CONNECT request. +// TODO(roth): Technically, for any of the failure modes handled by this +// function, we should handle the error by returning an HTTP response to +// the client indicating that the request failed. However, for the purposes +// of this test code, it's fine to pretend this is a client-side error, +// which will cause the client connection to be dropped. +static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + proxy_connection* conn = arg; + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy read request", error); + return; + } + // Read request and feed it to the parser. + for (size_t i = 0; i < conn->client_read_buffer.count; ++i) { + if (GPR_SLICE_LENGTH(conn->client_read_buffer.slices[i]) > 0) { + error = grpc_http_parser_parse(&conn->http_parser, + conn->client_read_buffer.slices[i], NULL); + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy request parse", error); + GRPC_ERROR_UNREF(error); + return; + } + } + } + gpr_slice_buffer_reset_and_unref(&conn->client_read_buffer); + // If we're not done reading the request, read more data. + if (conn->http_parser.state != GRPC_HTTP_BODY) { + grpc_endpoint_read(exec_ctx, conn->client_endpoint, + &conn->client_read_buffer, &conn->on_read_request_done); + return; + } + // Make sure we got a CONNECT request. + if (strcmp(conn->http_request.method, "CONNECT") != 0) { + char* msg; + gpr_asprintf(&msg, "HTTP proxy got request method %s", + conn->http_request.method); + error = GRPC_ERROR_CREATE(msg); + gpr_free(msg); + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy read request", error); + GRPC_ERROR_UNREF(error); + return; + } + // Resolve address. + grpc_resolved_addresses* resolved_addresses = NULL; + error = grpc_blocking_resolve_address(conn->http_request.path, "80", + &resolved_addresses); + if (error != GRPC_ERROR_NONE) { + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy DNS lookup", error); + GRPC_ERROR_UNREF(error); + return; + } + GPR_ASSERT(resolved_addresses->naddrs >= 1); + // Connect to requested address. + // The connection callback inherits our reference to conn. + const gpr_timespec deadline = gpr_time_add( + gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN)); + grpc_tcp_client_connect(exec_ctx, &conn->on_server_connect_done, + &conn->server_endpoint, conn->pollset_set, + (struct sockaddr*)&resolved_addresses->addrs[0].addr, + resolved_addresses->addrs[0].len, deadline); + grpc_resolved_addresses_destroy(resolved_addresses); +} + +static void on_accept(grpc_exec_ctx* exec_ctx, void* arg, + grpc_endpoint* endpoint, grpc_pollset* accepting_pollset, + grpc_tcp_server_acceptor* acceptor) { + grpc_end2end_http_proxy* proxy = arg; + // Instantiate proxy_connection. + proxy_connection* conn = gpr_malloc(sizeof(*conn)); + memset(conn, 0, sizeof(*conn)); + conn->client_endpoint = endpoint; + gpr_ref_init(&conn->refcount, 1); + conn->pollset_set = grpc_pollset_set_create(); + grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset); + grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn); + grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, + conn); + grpc_closure_init(&conn->on_write_response_done, on_write_response_done, + conn); + grpc_closure_init(&conn->on_client_read_done, on_client_read_done, conn); + grpc_closure_init(&conn->on_client_write_done, on_client_write_done, conn); + grpc_closure_init(&conn->on_server_read_done, on_server_read_done, conn); + grpc_closure_init(&conn->on_server_write_done, on_server_write_done, conn); + gpr_slice_buffer_init(&conn->client_read_buffer); + gpr_slice_buffer_init(&conn->client_deferred_write_buffer); + gpr_slice_buffer_init(&conn->client_write_buffer); + gpr_slice_buffer_init(&conn->server_read_buffer); + gpr_slice_buffer_init(&conn->server_deferred_write_buffer); + gpr_slice_buffer_init(&conn->server_write_buffer); + grpc_http_parser_init(&conn->http_parser, GRPC_HTTP_REQUEST, + &conn->http_request); + grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, + &conn->on_read_request_done); +} + +// +// Proxy class +// + +static void thread_main(void* arg) { + grpc_end2end_http_proxy* proxy = arg; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + do { + const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + const gpr_timespec deadline = + gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN)); + grpc_pollset_worker* worker = NULL; + gpr_mu_lock(proxy->mu); + GRPC_LOG_IF_ERROR( + "grpc_pollset_work", + grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline)); + gpr_mu_unlock(proxy->mu); + grpc_exec_ctx_flush(&exec_ctx); + } while (!gpr_atm_acq_load(&proxy->shutdown)); + grpc_exec_ctx_finish(&exec_ctx); +} + +grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() { + grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy)); + memset(proxy, 0, sizeof(*proxy)); + // Construct proxy address. + const int proxy_port = grpc_pick_unused_port_or_die(); + gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port); + gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name); + // Create TCP server. + proxy->channel_args = grpc_channel_args_copy(NULL); + grpc_error* error = + grpc_tcp_server_create(NULL, proxy->channel_args, &proxy->server); + GPR_ASSERT(error == GRPC_ERROR_NONE); + // Bind to port. + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + grpc_sockaddr_set_port((struct sockaddr*)&addr, proxy_port); + int port; + error = grpc_tcp_server_add_port(proxy->server, (struct sockaddr*)&addr, + sizeof(addr), &port); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(port == proxy_port); + // Start server. + proxy->pollset = gpr_malloc(grpc_pollset_size()); + grpc_pollset_init(proxy->pollset, &proxy->mu); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1, on_accept, + proxy); + grpc_exec_ctx_finish(&exec_ctx); + // Start proxy thread. + gpr_thd_options opt = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&opt); + GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt)); + return proxy; +} + +static void destroy_pollset(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + grpc_pollset* pollset = arg; + grpc_pollset_destroy(pollset); + gpr_free(pollset); +} + +void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) { + gpr_atm_rel_store(&proxy->shutdown, 1); // Signal proxy thread to shutdown. + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_thd_join(proxy->thd); + grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server); + grpc_tcp_server_unref(&exec_ctx, proxy->server); + gpr_free(proxy->proxy_name); + grpc_channel_args_destroy(proxy->channel_args); + grpc_closure destroyed; + grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset); + grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed); + gpr_free(proxy); + grpc_exec_ctx_finish(&exec_ctx); +} + +const char* grpc_end2end_http_proxy_get_proxy_name( + grpc_end2end_http_proxy* proxy) { + return proxy->proxy_name; +} diff --git a/test/core/end2end/fixtures/http_proxy.h b/test/core/end2end/fixtures/http_proxy.h new file mode 100644 index 0000000000..cd47b432af --- /dev/null +++ b/test/core/end2end/fixtures/http_proxy.h @@ -0,0 +1,41 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +typedef struct grpc_end2end_http_proxy grpc_end2end_http_proxy; + +grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(); + +void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy); + +const char* grpc_end2end_http_proxy_get_proxy_name( + grpc_end2end_http_proxy* proxy); diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary index e5a73d523f..a93bccfa0d 100644 --- a/test/core/end2end/fuzzers/hpack.dictionary +++ b/test/core/end2end/fuzzers/hpack.dictionary @@ -40,11 +40,11 @@ "\x03GET" "\x04grpc" "\x14grpc-accept-encoding" -"\x0Fgrpc-census-bin" "\x0Dgrpc-encoding" "\x1Egrpc-internal-encoding-request" "\x0Cgrpc-message" "\x10grpc-payload-bin" +"\x0Egrpc-stats-bin" "\x0Bgrpc-status" "\x0Cgrpc-timeout" "\x10grpc-tracing-bin" diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index fe0f7baf2c..78b37efd37 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -60,6 +60,7 @@ END2END_FIXTURES = { 'h2_full+pipe': default_unsecure_fixture_options._replace( platforms=['linux']), 'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True), + 'h2_http_proxy': default_unsecure_fixture_options._replace(ci_mac=False), 'h2_oauth2': default_secure_fixture_options._replace(ci_mac=False), 'h2_proxy': default_unsecure_fixture_options._replace(includes_proxy=True, ci_mac=False), diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c index 43f71f51d1..d27ccedb4e 100644 --- a/test/core/end2end/tests/max_message_length.c +++ b/test/core/end2end/tests/max_message_length.c @@ -98,19 +98,25 @@ static void end_test(grpc_end2end_test_fixture *f) { grpc_completion_queue_destroy(f->cq); } -static void test_max_message_length(grpc_end2end_test_config config) { +// Test with request larger than the limit. +// If send_limit is true, applies send limit on client; otherwise, applies +// recv limit on server. +static void test_max_message_length_on_request(grpc_end2end_test_config config, + bool send_limit) { + gpr_log(GPR_INFO, "testing request with send_limit=%d", send_limit); + grpc_end2end_test_fixture f; - grpc_arg server_arg; - grpc_channel_args server_args; - grpc_call *c; - grpc_call *s; + grpc_arg channel_arg; + grpc_channel_args channel_args; + grpc_call *c = NULL; + grpc_call *s = NULL; cq_verifier *cqv; grpc_op ops[6]; grpc_op *op; gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); - grpc_byte_buffer *recv_payload; + grpc_byte_buffer *recv_payload = NULL; grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; @@ -121,14 +127,17 @@ static void test_max_message_length(grpc_end2end_test_config config) { size_t details_capacity = 0; int was_cancelled = 2; - server_arg.key = GRPC_ARG_MAX_MESSAGE_LENGTH; - server_arg.type = GRPC_ARG_INTEGER; - server_arg.value.integer = 5; + channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH + : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; + channel_arg.type = GRPC_ARG_INTEGER; + channel_arg.value.integer = 5; - server_args.num_args = 1; - server_args.args = &server_arg; + channel_args.num_args = 1; + channel_args.args = &channel_arg; - f = begin_test(config, "test_max_message_length", NULL, &server_args); + f = begin_test(config, "test_max_message_length", + send_limit ? &channel_args : NULL, + send_limit ? NULL : &channel_args); cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, @@ -173,6 +182,12 @@ static void test_max_message_length(grpc_end2end_test_config config) { error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); GPR_ASSERT(GRPC_CALL_OK == error); + if (send_limit) { + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + goto done; + } + error = grpc_server_request_call(f.server, &s, &call_details, &request_metadata_recv, f.cq, f.cq, tag(101)); @@ -199,11 +214,16 @@ static void test_max_message_length(grpc_end2end_test_config config) { CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status != GRPC_STATUS_OK); GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234")); GPR_ASSERT(was_cancelled == 1); - GPR_ASSERT(recv_payload == NULL); + +done: + GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT); + GPR_ASSERT(strcmp(details, + send_limit + ? "Sent message larger than max (11 vs. 5)" + : "Received message larger than max (11 vs. 5)") == 0); gpr_free(details); grpc_metadata_array_destroy(&initial_metadata_recv); @@ -211,9 +231,160 @@ static void test_max_message_length(grpc_end2end_test_config config) { grpc_metadata_array_destroy(&request_metadata_recv); grpc_call_details_destroy(&call_details); grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(recv_payload); + + grpc_call_destroy(c); + if (s != NULL) grpc_call_destroy(s); + + cq_verifier_destroy(cqv); + + end_test(&f); + config.tear_down_data(&f); +} + +// Test with response larger than the limit. +// If send_limit is true, applies send limit on server; otherwise, applies +// recv limit on client. +static void test_max_message_length_on_response(grpc_end2end_test_config config, + bool send_limit) { + gpr_log(GPR_INFO, "testing response with send_limit=%d", send_limit); + + grpc_end2end_test_fixture f; + grpc_arg channel_arg; + grpc_channel_args channel_args; + grpc_call *c = NULL; + grpc_call *s = NULL; + cq_verifier *cqv; + grpc_op ops[6]; + grpc_op *op; + gpr_slice response_payload_slice = + gpr_slice_from_copied_string("hello world"); + grpc_byte_buffer *response_payload = + grpc_raw_byte_buffer_create(&response_payload_slice, 1); + grpc_byte_buffer *recv_payload = NULL; + 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; + char *details = NULL; + size_t details_capacity = 0; + int was_cancelled = 2; + + channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH + : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; + channel_arg.type = GRPC_ARG_INTEGER; + channel_arg.value.integer = 5; + + channel_args.num_args = 1; + channel_args.args = &channel_arg; + + f = begin_test(config, "test_max_message_length", + send_limit ? NULL : &channel_args, + send_limit ? &channel_args : NULL); + cqv = cq_verifier_create(f.cq); + + c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, + "/foo", "foo.test.google.fr:1234", + gpr_inf_future(GPR_CLOCK_REALTIME), 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_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message = &recv_payload; + 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->data.recv_status_on_client.status_details_capacity = &details_capacity; + 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_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 = 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; + op->data.send_status_from_server.status_details = "xyz"; + 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_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); + GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234")); + GPR_ASSERT(was_cancelled == 0); + + GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT); + GPR_ASSERT(strcmp(details, + send_limit + ? "Sent message larger than max (11 vs. 5)" + : "Received message larger than max (11 vs. 5)") == 0); + + gpr_free(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_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(recv_payload); grpc_call_destroy(c); - grpc_call_destroy(s); + if (s != NULL) grpc_call_destroy(s); cq_verifier_destroy(cqv); @@ -222,7 +393,10 @@ static void test_max_message_length(grpc_end2end_test_config config) { } void max_message_length(grpc_end2end_test_config config) { - test_max_message_length(config); + test_max_message_length_on_request(config, false /* send_limit */); + test_max_message_length_on_request(config, true /* send_limit */); + test_max_message_length_on_response(config, false /* send_limit */); + test_max_message_length_on_response(config, true /* send_limit */); } void max_message_length_pre_init(void) {} diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c index 3c40e5dbac..430bfdc797 100644 --- a/test/core/end2end/tests/no_logging.c +++ b/test/core/end2end/tests/no_logging.c @@ -68,6 +68,13 @@ static void test_no_error_log(gpr_log_func_args *args) { } } +static gpr_atm g_log_func = (gpr_atm)gpr_default_log; + +static void log_dispatcher_func(gpr_log_func_args *args) { + gpr_log_func log_func = (gpr_log_func)gpr_atm_no_barrier_load(&g_log_func); + log_func(args); +} + static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, const char *test_name, grpc_channel_args *client_args, @@ -263,12 +270,12 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { static void test_no_error_logging_in_entire_process( grpc_end2end_test_config config) { int i; - gpr_set_log_function(test_no_error_log); + gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)test_no_error_log); for (i = 0; i < 10; i++) { test_invoke_simple_request(config); } test_invoke_10_simple_requests(config); - gpr_set_log_function(gpr_default_log); + gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)gpr_default_log); } static void test_no_logging_in_one_request(grpc_end2end_test_config config) { @@ -278,16 +285,18 @@ static void test_no_logging_in_one_request(grpc_end2end_test_config config) { for (i = 0; i < 10; i++) { simple_request_body(f); } - gpr_set_log_function(test_no_log); + gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)test_no_log); simple_request_body(f); - gpr_set_log_function(gpr_default_log); + gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)gpr_default_log); end_test(&f); config.tear_down_data(&f); } void no_logging(grpc_end2end_test_config config) { + gpr_set_log_function(log_dispatcher_func); test_no_logging_in_one_request(config); test_no_error_logging_in_entire_process(config); + gpr_set_log_function(gpr_default_log); } void no_logging_pre_init(void) {} diff --git a/test/core/http/parser_test.c b/test/core/http/parser_test.c index d645d2879c..2fc354d9ee 100644 --- a/test/core/http/parser_test.c +++ b/test/core/http/parser_test.c @@ -62,7 +62,8 @@ static void test_request_succeeds(grpc_slice_split_mode split_mode, grpc_http_parser_init(&parser, GRPC_HTTP_REQUEST, &request); for (i = 0; i < num_slices; i++) { - GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]) == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i], NULL) == + GRPC_ERROR_NONE); gpr_slice_unref(slices[i]); } GPR_ASSERT(grpc_http_parser_eof(&parser) == GRPC_ERROR_NONE); @@ -118,7 +119,8 @@ static void test_succeeds(grpc_slice_split_mode split_mode, char *response_text, grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response); for (i = 0; i < num_slices; i++) { - GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]) == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i], NULL) == + GRPC_ERROR_NONE); gpr_slice_unref(slices[i]); } GPR_ASSERT(grpc_http_parser_eof(&parser) == GRPC_ERROR_NONE); @@ -171,7 +173,7 @@ static void test_fails(grpc_slice_split_mode split_mode, char *response_text) { for (i = 0; i < num_slices; i++) { if (GRPC_ERROR_NONE == error) { - error = grpc_http_parser_parse(&parser, slices[i]); + error = grpc_http_parser_parse(&parser, slices[i], NULL); } gpr_slice_unref(slices[i]); } @@ -204,7 +206,7 @@ static void test_request_fails(grpc_slice_split_mode split_mode, for (i = 0; i < num_slices; i++) { if (error == GRPC_ERROR_NONE) { - error = grpc_http_parser_parse(&parser, slices[i]); + error = grpc_http_parser_parse(&parser, slices[i], NULL); } gpr_slice_unref(slices[i]); } diff --git a/test/core/http/request_fuzzer.c b/test/core/http/request_fuzzer.c index 5941401867..bb6cb92c0c 100644 --- a/test/core/http/request_fuzzer.c +++ b/test/core/http/request_fuzzer.c @@ -48,7 +48,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { memset(&request, 0, sizeof(request)); grpc_http_parser_init(&parser, GRPC_HTTP_REQUEST, &request); gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size); - GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice)); + GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice, NULL)); GRPC_ERROR_UNREF(grpc_http_parser_eof(&parser)); gpr_slice_unref(slice); grpc_http_parser_destroy(&parser); diff --git a/test/core/http/response_fuzzer.c b/test/core/http/response_fuzzer.c index acde7c80a4..4393840484 100644 --- a/test/core/http/response_fuzzer.c +++ b/test/core/http/response_fuzzer.c @@ -47,7 +47,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { memset(&response, 0, sizeof(response)); grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response); gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size); - GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice)); + GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice, NULL)); GRPC_ERROR_UNREF(grpc_http_parser_eof(&parser)); gpr_slice_unref(slice); grpc_http_parser_destroy(&parser); diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c new file mode 100644 index 0000000000..197998c1e5 --- /dev/null +++ b/test/core/iomgr/combiner_test.c @@ -0,0 +1,164 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/iomgr/combiner.h" + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/thd.h> +#include <grpc/support/useful.h> + +#include "test/core/util/test_config.h" + +static void test_no_op(void) { + gpr_log(GPR_DEBUG, "test_no_op"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_destroy(&exec_ctx, grpc_combiner_create(NULL)); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value, + grpc_error *error) { + *(bool *)value = true; +} + +static void test_execute_one(void) { + gpr_log(GPR_DEBUG, "test_execute_one"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + bool done = false; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_execute(&exec_ctx, lock, + grpc_closure_create(set_bool_to_true, &done), + GRPC_ERROR_NONE); + grpc_exec_ctx_flush(&exec_ctx); + GPR_ASSERT(done); + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); +} + +typedef struct { + size_t ctr; + grpc_combiner *lock; +} thd_args; + +typedef struct { + size_t *ctr; + size_t value; +} ex_args; + +static void check_one(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) { + ex_args *args = a; + GPR_ASSERT(*args->ctr == args->value - 1); + *args->ctr = args->value; + gpr_free(a); +} + +static void execute_many_loop(void *a) { + thd_args *args = a; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + size_t n = 1; + for (size_t i = 0; i < 10; i++) { + for (size_t j = 0; j < 10000; j++) { + ex_args *c = gpr_malloc(sizeof(*c)); + c->ctr = &args->ctr; + c->value = n++; + grpc_combiner_execute(&exec_ctx, args->lock, + grpc_closure_create(check_one, c), GRPC_ERROR_NONE); + grpc_exec_ctx_flush(&exec_ctx); + } + // sleep for a little bit, to test a combiner draining and another thread + // picking it up + gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); + } + grpc_exec_ctx_finish(&exec_ctx); +} + +static void test_execute_many(void) { + gpr_log(GPR_DEBUG, "test_execute_many"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + gpr_thd_id thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + ta[i].ctr = 0; + ta[i].lock = lock; + GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options)); + } + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); +} + +static bool got_in_finally = false; + +static void in_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + got_in_finally = true; +} + +static void add_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_combiner_execute_finally(exec_ctx, arg, + grpc_closure_create(in_finally, NULL), + GRPC_ERROR_NONE, false); +} + +static void test_execute_finally(void) { + gpr_log(GPR_DEBUG, "test_execute_finally"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock), + GRPC_ERROR_NONE); + grpc_exec_ctx_flush(&exec_ctx); + GPR_ASSERT(got_in_finally); + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_init(); + test_no_op(); + test_execute_one(); + test_execute_finally(); + test_execute_many(); + grpc_shutdown(); + + return 0; +} diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c index a959a7e07f..2a30427504 100644 --- a/test/core/iomgr/udp_server_test.c +++ b/test/core/iomgr/udp_server_test.c @@ -48,8 +48,6 @@ #include "src/core/lib/iomgr/iomgr.h" #include "test/core/util/test_config.h" -#ifdef GRPC_NEED_UDP - #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x) static grpc_pollset *g_pollset; @@ -229,9 +227,3 @@ int main(int argc, char **argv) { grpc_iomgr_shutdown(); return 0; } - -#else - -int main(int argc, char **argv) { return 0; } - -#endif diff --git a/test/core/nanopb/fuzzer_response.c b/test/core/nanopb/fuzzer_response.c index 75a99faf3f..a82f20df83 100644 --- a/test/core/nanopb/fuzzer_response.c +++ b/test/core/nanopb/fuzzer_response.c @@ -41,7 +41,10 @@ bool squelch = true; bool leak_check = true; +static void dont_log(gpr_log_func_args *args) {} + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (squelch) gpr_set_log_function(dont_log); gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size); grpc_grpclb_initial_response *response; if ((response = grpc_grpclb_initial_response_parse(slice))) { diff --git a/test/core/nanopb/fuzzer_serverlist.c b/test/core/nanopb/fuzzer_serverlist.c index df2044d907..9700bf1cda 100644 --- a/test/core/nanopb/fuzzer_serverlist.c +++ b/test/core/nanopb/fuzzer_serverlist.c @@ -41,7 +41,10 @@ bool squelch = true; bool leak_check = true; +static void dont_log(gpr_log_func_args *args) {} + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (squelch) gpr_set_log_function(dont_log); gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size); grpc_grpclb_serverlist *serverlist; if ((serverlist = grpc_grpclb_response_parse_serverlist(slice))) { diff --git a/test/core/support/mpscq_test.c b/test/core/support/mpscq_test.c new file mode 100644 index 0000000000..491eb9148b --- /dev/null +++ b/test/core/support/mpscq_test.c @@ -0,0 +1,206 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/support/mpscq.h" + +#include <stdlib.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/useful.h> +#include "test/core/util/test_config.h" + +typedef struct test_node { + gpr_mpscq_node node; + size_t i; + size_t *ctr; +} test_node; + +static test_node *new_node(size_t i, size_t *ctr) { + test_node *n = gpr_malloc(sizeof(test_node)); + n->i = i; + n->ctr = ctr; + return n; +} + +static void test_serial(void) { + gpr_log(GPR_DEBUG, "test_serial"); + gpr_mpscq q; + gpr_mpscq_init(&q); + for (size_t i = 0; i < 10000000; i++) { + gpr_mpscq_push(&q, &new_node(i, NULL)->node); + } + for (size_t i = 0; i < 10000000; i++) { + test_node *n = (test_node *)gpr_mpscq_pop(&q); + GPR_ASSERT(n); + GPR_ASSERT(n->i == i); + gpr_free(n); + } +} + +typedef struct { + size_t ctr; + gpr_mpscq *q; + gpr_event *start; +} thd_args; + +#define THREAD_ITERATIONS 100000 + +static void test_thread(void *args) { + thd_args *a = args; + gpr_event_wait(a->start, gpr_inf_future(GPR_CLOCK_REALTIME)); + for (size_t i = 1; i <= THREAD_ITERATIONS; i++) { + gpr_mpscq_push(a->q, &new_node(i, &a->ctr)->node); + } +} + +static void test_mt(void) { + gpr_log(GPR_DEBUG, "test_mt"); + gpr_event start; + gpr_event_init(&start); + gpr_thd_id thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; + gpr_mpscq q; + gpr_mpscq_init(&q); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + ta[i].ctr = 0; + ta[i].q = &q; + ta[i].start = &start; + GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options)); + } + size_t num_done = 0; + size_t spins = 0; + gpr_event_set(&start, (void *)1); + while (num_done != GPR_ARRAY_SIZE(thds)) { + gpr_mpscq_node *n; + while ((n = gpr_mpscq_pop(&q)) == NULL) { + spins++; + } + test_node *tn = (test_node *)n; + GPR_ASSERT(*tn->ctr == tn->i - 1); + *tn->ctr = tn->i; + if (tn->i == THREAD_ITERATIONS) num_done++; + gpr_free(tn); + } + gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + gpr_mpscq_destroy(&q); +} + +typedef struct { + thd_args *ta; + size_t num_thds; + gpr_mu mu; + size_t num_done; + size_t spins; + gpr_mpscq *q; + gpr_event *start; +} pull_args; + +static void pull_thread(void *arg) { + pull_args *pa = arg; + gpr_event_wait(pa->start, gpr_inf_future(GPR_CLOCK_REALTIME)); + + for (;;) { + gpr_mu_lock(&pa->mu); + if (pa->num_done == pa->num_thds) { + gpr_mu_unlock(&pa->mu); + return; + } + gpr_mpscq_node *n; + while ((n = gpr_mpscq_pop(pa->q)) == NULL) { + pa->spins++; + } + test_node *tn = (test_node *)n; + GPR_ASSERT(*tn->ctr == tn->i - 1); + *tn->ctr = tn->i; + if (tn->i == THREAD_ITERATIONS) pa->num_done++; + gpr_free(tn); + gpr_mu_unlock(&pa->mu); + } +} + +static void test_mt_multipop(void) { + gpr_log(GPR_DEBUG, "test_mt_multipop"); + gpr_event start; + gpr_event_init(&start); + gpr_thd_id thds[100]; + gpr_thd_id pull_thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; + gpr_mpscq q; + gpr_mpscq_init(&q); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + ta[i].ctr = 0; + ta[i].q = &q; + ta[i].start = &start; + GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options)); + } + pull_args pa; + pa.ta = ta; + pa.num_thds = GPR_ARRAY_SIZE(thds); + pa.spins = 0; + pa.num_done = 0; + pa.q = &q; + pa.start = &start; + gpr_mu_init(&pa.mu); + for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + GPR_ASSERT(gpr_thd_new(&pull_thds[i], pull_thread, &pa, &options)); + } + gpr_event_set(&start, (void *)1); + for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) { + gpr_thd_join(pull_thds[i]); + } + gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, pa.spins); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + gpr_mpscq_destroy(&q); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + test_serial(); + test_mt(); + test_mt_multipop(); + return 0; +} diff --git a/test/core/surface/channel_create_test.c b/test/core/surface/channel_create_test.c index eada82d949..ad7970aab9 100644 --- a/test/core/surface/channel_create_test.c +++ b/test/core/surface/channel_create_test.c @@ -40,7 +40,7 @@ void test_unknown_scheme_target(void) { grpc_channel *chan; /* avoid default prefix */ grpc_resolver_registry_shutdown(); - grpc_resolver_registry_init(""); + grpc_resolver_registry_init(); chan = grpc_insecure_channel_create("blah://blah", NULL, NULL); GPR_ASSERT(chan != NULL); diff --git a/test/core/surface/invalid_channel_args_test.c b/test/core/surface/invalid_channel_args_test.c index 1b1b8b8f92..0640879866 100644 --- a/test/core/surface/invalid_channel_args_test.c +++ b/test/core/surface/invalid_channel_args_test.c @@ -84,38 +84,6 @@ static void one_test(grpc_channel_args *args, char *expected_error_message) { static void test_no_error_message(void) { one_test(NULL, NULL); } -static void test_max_message_length_type(void) { - grpc_arg client_arg; - grpc_channel_args client_args; - char *expected_error_message; - - client_arg.type = GRPC_ARG_STRING; - client_arg.key = GRPC_ARG_MAX_MESSAGE_LENGTH; - client_arg.value.string = NULL; - - client_args.num_args = 1; - client_args.args = &client_arg; - expected_error_message = compose_error_string( - GRPC_ARG_MAX_MESSAGE_LENGTH, " ignored: it must be an integer"); - one_test(&client_args, expected_error_message); -} - -static void test_max_message_length_negative(void) { - grpc_arg client_arg; - grpc_channel_args client_args; - char *expected_error_message; - - client_arg.type = GRPC_ARG_INTEGER; - client_arg.key = GRPC_ARG_MAX_MESSAGE_LENGTH; - client_arg.value.integer = -1; - - client_args.num_args = 1; - client_args.args = &client_arg; - expected_error_message = compose_error_string(GRPC_ARG_MAX_MESSAGE_LENGTH, - " ignored: it must be >= 0"); - one_test(&client_args, expected_error_message); -} - static void test_default_authority_type(void) { grpc_arg client_arg; grpc_channel_args client_args; @@ -174,8 +142,6 @@ int main(int argc, char **argv) { gpr_set_log_function(log_error_sink); test_no_error_message(); - test_max_message_length_type(); - test_max_message_length_negative(); test_default_authority_type(); test_ssl_name_override_type(); test_ssl_name_override_failed(); diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c index 2894b0c66f..6afcefca92 100644 --- a/test/core/surface/lame_client_test.c +++ b/test/core/surface/lame_client_test.c @@ -49,32 +49,31 @@ static void *tag(intptr_t x) { return (void *)x; } void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_transport_op *op = arg; - GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *op->connectivity_state); + grpc_connectivity_state *state = arg; + GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *state); GPR_ASSERT(error == GRPC_ERROR_NONE); } void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} void test_transport_op(grpc_channel *channel) { - grpc_transport_op op; + grpc_transport_op *op; grpc_channel_element *elem; grpc_connectivity_state state = GRPC_CHANNEL_IDLE; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - memset(&op, 0, sizeof(op)); - grpc_closure_init(&transport_op_cb, verify_connectivity, &op); + grpc_closure_init(&transport_op_cb, verify_connectivity, &state); - op.on_connectivity_state_change = &transport_op_cb; - op.connectivity_state = &state; + op = grpc_make_transport_op(NULL); + op->on_connectivity_state_change = &transport_op_cb; + op->connectivity_state = &state; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - elem->filter->start_transport_op(&exec_ctx, elem, &op); + elem->filter->start_transport_op(&exec_ctx, elem, op); grpc_exec_ctx_finish(&exec_ctx); - memset(&op, 0, sizeof(op)); grpc_closure_init(&transport_op_cb, do_nothing, NULL); - op.on_consumed = &transport_op_cb; - elem->filter->start_transport_op(&exec_ctx, elem, &op); + op = grpc_make_transport_op(&transport_op_cb); + elem->filter->start_transport_op(&exec_ctx, elem, op); grpc_exec_ctx_finish(&exec_ctx); } diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 3eeb55d033..53bdf612fc 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -38,22 +38,18 @@ #include <grpc/grpc.h> #include <grpc/grpc_security.h> #include <grpc/grpc_security_constants.h> -#include <grpc/impl/codegen/alloc.h> #include <grpc/impl/codegen/atm.h> -#include <grpc/impl/codegen/byte_buffer.h> #include <grpc/impl/codegen/byte_buffer_reader.h> #include <grpc/impl/codegen/compression_types.h> #include <grpc/impl/codegen/connectivity_state.h> +#include <grpc/impl/codegen/gpr_types.h> #include <grpc/impl/codegen/grpc_types.h> -#include <grpc/impl/codegen/log.h> #include <grpc/impl/codegen/port_platform.h> #include <grpc/impl/codegen/propagation_bits.h> #include <grpc/impl/codegen/slice.h> -#include <grpc/impl/codegen/slice_buffer.h> #include <grpc/impl/codegen/status.h> #include <grpc/impl/codegen/sync.h> #include <grpc/impl/codegen/sync_generic.h> -#include <grpc/impl/codegen/time.h> #include <grpc/status.h> #include <grpc/support/alloc.h> #include <grpc/support/atm.h> diff --git a/test/core/surface/secure_channel_create_test.c b/test/core/surface/secure_channel_create_test.c index 42fca8cff7..444ebdc093 100644 --- a/test/core/surface/secure_channel_create_test.c +++ b/test/core/surface/secure_channel_create_test.c @@ -46,7 +46,7 @@ void test_unknown_scheme_target(void) { grpc_channel *chan; grpc_channel_credentials *creds; grpc_resolver_registry_shutdown(); - grpc_resolver_registry_init(""); + grpc_resolver_registry_init(); creds = grpc_fake_transport_security_credentials_create(); chan = grpc_secure_channel_create(creds, "blah://blah", NULL, NULL); diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c index 270d16600d..479aeda898 100644 --- a/test/core/util/test_config.c +++ b/test/core/util/test_config.c @@ -34,7 +34,6 @@ #include "test/core/util/test_config.h" #include <grpc/support/log.h> -#include <grpc/support/port_platform.h> #include <signal.h> #include <stdbool.h> #include <stdio.h> |