aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/core
diff options
context:
space:
mode:
Diffstat (limited to 'test/core')
-rw-r--r--test/core/census/data/context_empty.pb0
-rw-r--r--test/core/census/data/context_empty.txt0
-rw-r--r--test/core/census/data/context_full.pbbin0 -> 31 bytes
-rw-r--r--test/core/census/data/context_full.txt3
-rw-r--r--test/core/census/data/context_no_sample.pbbin0 -> 29 bytes
-rw-r--r--test/core/census/data/context_no_sample.txt2
-rw-r--r--test/core/census/data/context_span_only.pbbin0 -> 11 bytes
-rw-r--r--test/core/census/data/context_span_only.txt2
-rw-r--r--test/core/census/data/context_trace_only.pbbin0 -> 22 bytes
-rw-r--r--test/core/census/data/context_trace_only.txt2
-rw-r--r--test/core/census/trace_context_test.c231
-rw-r--r--test/core/channel/channel_stack_test.c6
-rw-r--r--test/core/client_channel/lb_policies_test.c6
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_connectivity_test.c24
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_test.c24
-rw-r--r--test/core/client_channel/resolvers/sockaddr_resolver_test.c46
-rw-r--r--test/core/end2end/connection_refused_test.c128
-rw-r--r--test/core/end2end/fake_resolver.c212
-rw-r--r--test/core/end2end/fake_resolver.h39
-rw-r--r--test/core/end2end/fixtures/h2_fd.c2
-rw-r--r--test/core/end2end/fixtures/h2_http_proxy.c129
-rw-r--r--test/core/end2end/fixtures/http_proxy.c481
-rw-r--r--test/core/end2end/fixtures/http_proxy.h41
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary2
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py1
-rw-r--r--test/core/end2end/tests/max_message_length.c206
-rw-r--r--test/core/end2end/tests/no_logging.c17
-rw-r--r--test/core/http/parser_test.c10
-rw-r--r--test/core/http/request_fuzzer.c2
-rw-r--r--test/core/http/response_fuzzer.c2
-rw-r--r--test/core/iomgr/combiner_test.c164
-rw-r--r--test/core/iomgr/udp_server_test.c8
-rw-r--r--test/core/nanopb/fuzzer_response.c3
-rw-r--r--test/core/nanopb/fuzzer_serverlist.c3
-rw-r--r--test/core/support/mpscq_test.c206
-rw-r--r--test/core/surface/channel_create_test.c2
-rw-r--r--test/core/surface/invalid_channel_args_test.c34
-rw-r--r--test/core/surface/lame_client_test.c21
-rw-r--r--test/core/surface/public_headers_must_be_c89.c6
-rw-r--r--test/core/surface/secure_channel_create_test.c2
-rw-r--r--test/core/util/test_config.c1
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
new file mode 100644
index 0000000000..80ebcf280b
--- /dev/null
+++ b/test/core/census/data/context_full.pb
Binary files differ
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
new file mode 100644
index 0000000000..ab7ad7d109
--- /dev/null
+++ b/test/core/census/data/context_no_sample.pb
Binary files differ
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
new file mode 100644
index 0000000000..2a9527a75a
--- /dev/null
+++ b/test/core/census/data/context_span_only.pb
Binary files differ
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
new file mode 100644
index 0000000000..7fdf6f61a3
--- /dev/null
+++ b/test/core/census/data/context_trace_only.pb
Binary files differ
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>