aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/core
diff options
context:
space:
mode:
authorGravatar Vijay Pai <vpai@google.com>2018-02-02 09:12:11 -0800
committerGravatar GitHub <noreply@github.com>2018-02-02 09:12:11 -0800
commit4c0640ebd65f2661664f882c673707c1c5807ccd (patch)
tree4a002106829115e970939568154ed0175e337572 /test/core
parent0dbb00eef0e53c87dcd6958839ec0d532cdf858c (diff)
parente5b0a504167fbc6277d034709aa29ea07fa09a00 (diff)
Merge branch 'master' into gpr_review3
Diffstat (limited to 'test/core')
-rw-r--r--test/core/bad_client/bad_client.cc299
-rw-r--r--test/core/bad_client/bad_client.h63
-rwxr-xr-xtest/core/bad_client/gen_build_yaml.py2
-rwxr-xr-xtest/core/bad_client/generate_tests.bzl2
-rw-r--r--test/core/bad_client/tests/head_of_line_blocking.cc3
-rw-r--r--test/core/bad_client/tests/large_metadata.cc119
-rw-r--r--test/core/bad_client/tests/window_overflow.cc11
-rw-r--r--test/core/client_channel/resolvers/BUILD12
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc304
-rw-r--r--test/core/end2end/h2_ssl_cert_test.cc16
-rw-r--r--test/core/end2end/tests/streaming_error_response.cc2
-rw-r--r--test/core/fling/client.cc6
-rw-r--r--test/core/http/BUILD15
-rw-r--r--test/core/http/httpcli_test.cc17
-rw-r--r--test/core/http/httpscli_test.cc25
l---------test/core/http/python_wrapper.sh1
-rw-r--r--test/core/memory_usage/server.cc1
-rw-r--r--test/core/surface/BUILD12
-rw-r--r--test/core/surface/alarm_test.cc116
-rw-r--r--test/core/surface/byte_buffer_reader_test.cc8
-rw-r--r--test/core/surface/public_headers_must_be_c89.c4
-rw-r--r--test/core/transport/chttp2/settings_timeout_test.cc6
-rw-r--r--test/core/tsi/ssl_transport_security_test.cc10
-rw-r--r--test/core/util/passthru_endpoint.cc26
-rw-r--r--test/core/util/passthru_endpoint.h8
25 files changed, 728 insertions, 360 deletions
diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc
index dd8d88170e..df803d16a2 100644
--- a/test/core/bad_client/bad_client.cc
+++ b/test/core/bad_client/bad_client.cc
@@ -34,25 +34,32 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/server.h"
+#include "test/core/end2end/cq_verifier.h"
+#define MIN_HTTP2_FRAME_SIZE 9
+
+/* Args to provide to thread running server side validator */
typedef struct {
grpc_server* server;
grpc_completion_queue* cq;
grpc_bad_client_server_side_validator validator;
void* registered_method;
gpr_event done_thd;
- gpr_event done_write;
} thd_args;
+/* Run the server side validator and set done_thd once done */
static void thd_func(void* arg) {
thd_args* a = (thd_args*)arg;
- a->validator(a->server, a->cq, a->registered_method);
+ if (a->validator != nullptr) {
+ a->validator(a->server, a->cq, a->registered_method);
+ }
gpr_event_set(&a->done_thd, (void*)1);
}
-static void done_write(void* arg, grpc_error* error) {
- thd_args* a = (thd_args*)arg;
- gpr_event_set(&a->done_write, (void*)1);
+/* Sets the done_write event */
+static void set_done_write(void* arg, grpc_error* error) {
+ gpr_event* done_write = (gpr_event*)arg;
+ gpr_event_set(done_write, (void*)1);
}
static void server_setup_transport(void* ts, grpc_transport* transport) {
@@ -62,136 +69,172 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_server_get_channel_args(a->server));
}
-static void read_done(void* arg, grpc_error* error) {
+/* Sets the read_done event */
+static void set_read_done(void* arg, grpc_error* error) {
gpr_event* read_done = (gpr_event*)arg;
gpr_event_set(read_done, (void*)1);
}
-void grpc_run_bad_client_test(
- grpc_bad_client_server_side_validator server_validator,
- grpc_bad_client_client_stream_validator client_validator,
- const char* client_payload, size_t client_payload_length, uint32_t flags) {
- grpc_endpoint_pair sfd;
- thd_args a;
- gpr_thd_id id;
- char* hex;
- grpc_transport* transport;
- grpc_slice slice =
- grpc_slice_from_copied_buffer(client_payload, client_payload_length);
- grpc_slice_buffer outgoing;
- grpc_closure done_write_closure;
- grpc_core::ExecCtx exec_ctx;
- grpc_completion_queue* shutdown_cq;
+/* shutdown client */
+static void shutdown_client(grpc_endpoint** client_fd) {
+ if (*client_fd != nullptr) {
+ grpc_endpoint_shutdown(
+ *client_fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Disconnect"));
+ grpc_endpoint_destroy(*client_fd);
+ grpc_core::ExecCtx::Get()->Flush();
+ *client_fd = nullptr;
+ }
+}
- if (client_payload_length < 4 * 1024) {
- hex = gpr_dump(client_payload, client_payload_length,
+/* Runs client side validator */
+void grpc_run_client_side_validator(grpc_bad_client_arg* arg, uint32_t flags,
+ grpc_endpoint_pair* sfd,
+ grpc_completion_queue* client_cq) {
+ char* hex;
+ gpr_event done_write;
+ if (arg->client_payload_length < 4 * 1024) {
+ hex = gpr_dump(arg->client_payload, arg->client_payload_length,
GPR_DUMP_HEX | GPR_DUMP_ASCII);
-
/* Add a debug log */
gpr_log(GPR_INFO, "TEST: %s", hex);
-
gpr_free(hex);
} else {
gpr_log(GPR_INFO, "TEST: (%" PRIdPTR " byte long string)",
- client_payload_length);
+ arg->client_payload_length);
}
- /* Init grpc */
- grpc_init();
-
- /* Create endpoints */
- sfd = grpc_iomgr_create_endpoint_pair("fixture", nullptr);
-
- /* Create server, completion events */
- a.server = grpc_server_create(nullptr, nullptr);
- a.cq = grpc_completion_queue_create_for_next(nullptr);
- gpr_event_init(&a.done_thd);
- gpr_event_init(&a.done_write);
- a.validator = server_validator;
- grpc_server_register_completion_queue(a.server, a.cq, nullptr);
- a.registered_method =
- grpc_server_register_method(a.server, GRPC_BAD_CLIENT_REGISTERED_METHOD,
- GRPC_BAD_CLIENT_REGISTERED_HOST,
- GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER, 0);
- grpc_server_start(a.server);
- transport = grpc_create_chttp2_transport(nullptr, sfd.server, false);
- server_setup_transport(&a, transport);
- grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
-
- /* Bind everything into the same pollset */
- grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
- grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
-
- /* Check a ground truth */
- GPR_ASSERT(grpc_server_has_open_connections(a.server));
-
- /* Start validator */
- gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
+ grpc_slice slice = grpc_slice_from_copied_buffer(arg->client_payload,
+ arg->client_payload_length);
+ grpc_slice_buffer outgoing;
+ grpc_closure done_write_closure;
+ gpr_event_init(&done_write);
grpc_slice_buffer_init(&outgoing);
grpc_slice_buffer_add(&outgoing, slice);
- GRPC_CLOSURE_INIT(&done_write_closure, done_write, &a,
+ GRPC_CLOSURE_INIT(&done_write_closure, set_done_write, &done_write,
grpc_schedule_on_exec_ctx);
/* Write data */
- grpc_endpoint_write(sfd.client, &outgoing, &done_write_closure);
+ grpc_endpoint_write(sfd->client, &outgoing, &done_write_closure);
grpc_core::ExecCtx::Get()->Flush();
/* Await completion, unless the request is large and write may not finish
* before the peer shuts down. */
if (!(flags & GRPC_BAD_CLIENT_LARGE_REQUEST)) {
GPR_ASSERT(
- gpr_event_wait(&a.done_write, grpc_timeout_seconds_to_deadline(5)));
+ gpr_event_wait(&done_write, grpc_timeout_seconds_to_deadline(5)));
}
if (flags & GRPC_BAD_CLIENT_DISCONNECT) {
- grpc_endpoint_shutdown(
- sfd.client, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Disconnect"));
- grpc_endpoint_destroy(sfd.client);
- grpc_core::ExecCtx::Get()->Flush();
- sfd.client = nullptr;
+ shutdown_client(&sfd->client);
}
- GPR_ASSERT(gpr_event_wait(&a.done_thd, grpc_timeout_seconds_to_deadline(5)));
-
- if (sfd.client != nullptr) {
- // Validate client stream, if requested.
- if (client_validator != nullptr) {
+ if (sfd->client != nullptr) {
+ /* Validate client stream, if requested. */
+ if (arg->client_validator != nullptr) {
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
grpc_slice_buffer incoming;
grpc_slice_buffer_init(&incoming);
- // We may need to do multiple reads to read the complete server response.
+ /* We may need to do multiple reads to read the complete server
+ * response. */
while (true) {
gpr_event read_done_event;
gpr_event_init(&read_done_event);
grpc_closure read_done_closure;
- GRPC_CLOSURE_INIT(&read_done_closure, read_done, &read_done_event,
+ GRPC_CLOSURE_INIT(&read_done_closure, set_read_done, &read_done_event,
grpc_schedule_on_exec_ctx);
- grpc_endpoint_read(sfd.client, &incoming, &read_done_closure);
+ grpc_endpoint_read(sfd->client, &incoming, &read_done_closure);
grpc_core::ExecCtx::Get()->Flush();
do {
GPR_ASSERT(gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0);
- GPR_ASSERT(
- grpc_completion_queue_next(
- a.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
- .type == GRPC_QUEUE_TIMEOUT);
+ /* Perform a cq next just to provide a thread that can read incoming
+ bytes on the client fd */
+ GPR_ASSERT(grpc_completion_queue_next(
+ client_cq, grpc_timeout_milliseconds_to_deadline(100),
+ nullptr)
+ .type == GRPC_QUEUE_TIMEOUT);
} while (!gpr_event_get(&read_done_event));
- if (client_validator(&incoming)) break;
+ if (arg->client_validator(&incoming, arg->client_validator_arg)) break;
gpr_log(GPR_INFO,
"client validator failed; trying additional read "
"in case we didn't get all the data");
}
grpc_slice_buffer_destroy_internal(&incoming);
}
- // Shutdown.
- grpc_endpoint_shutdown(
- sfd.client, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test Shutdown"));
- grpc_endpoint_destroy(sfd.client);
grpc_core::ExecCtx::Get()->Flush();
}
- GPR_ASSERT(
- gpr_event_wait(&a.done_write, grpc_timeout_seconds_to_deadline(1)));
+ /* If the request was too large, then we need to forcefully shut down the
+ * client, so that the write can be considered completed */
+ if (flags & GRPC_BAD_CLIENT_LARGE_REQUEST) {
+ shutdown_client(&sfd->client);
+ }
+
+ /* Make sure that the client is done writing */
+ while (!gpr_event_get(&done_write)) {
+ GPR_ASSERT(
+ grpc_completion_queue_next(
+ client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
+ .type == GRPC_QUEUE_TIMEOUT);
+ }
+
+ grpc_slice_buffer_destroy_internal(&outgoing);
+ grpc_core::ExecCtx::Get()->Flush();
+}
+
+void grpc_run_bad_client_test(
+ grpc_bad_client_server_side_validator server_validator,
+ grpc_bad_client_arg args[], int num_args, uint32_t flags) {
+ grpc_endpoint_pair sfd;
+ thd_args a;
+ grpc_transport* transport;
+ grpc_core::ExecCtx exec_ctx;
+ grpc_completion_queue* shutdown_cq;
+ grpc_completion_queue* client_cq;
+
+ /* Init grpc */
+ grpc_init();
+
+ /* Create endpoints */
+ sfd = grpc_iomgr_create_endpoint_pair("fixture", nullptr);
+
+ /* Create server, completion events */
+ a.server = grpc_server_create(nullptr, nullptr);
+ a.cq = grpc_completion_queue_create_for_next(nullptr);
+ client_cq = grpc_completion_queue_create_for_next(nullptr);
+
+ grpc_server_register_completion_queue(a.server, a.cq, nullptr);
+ a.registered_method =
+ grpc_server_register_method(a.server, GRPC_BAD_CLIENT_REGISTERED_METHOD,
+ GRPC_BAD_CLIENT_REGISTERED_HOST,
+ GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER, 0);
+ grpc_server_start(a.server);
+ transport = grpc_create_chttp2_transport(nullptr, sfd.server, false);
+ server_setup_transport(&a, transport);
+ grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
+
+ /* Bind fds to pollsets */
+ grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(client_cq));
+ grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
+
+ /* Check a ground truth */
+ GPR_ASSERT(grpc_server_has_open_connections(a.server));
+
+ gpr_thd_id id;
+ gpr_event_init(&a.done_thd);
+ a.validator = server_validator;
+ /* Start validator */
+ gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
+ for (int i = 0; i < num_args; i++) {
+ grpc_run_client_side_validator(&args[i], i == (num_args - 1) ? flags : 0,
+ &sfd, client_cq);
+ }
+ /* Wait for server thread to finish */
+ GPR_ASSERT(gpr_event_wait(&a.done_thd, grpc_timeout_seconds_to_deadline(1)));
+
+ /* Shutdown. */
+ shutdown_client(&sfd.client);
+
shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
grpc_server_shutdown_and_notify(a.server, shutdown_cq, nullptr);
GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, nullptr,
@@ -201,7 +244,91 @@ void grpc_run_bad_client_test(
grpc_completion_queue_destroy(shutdown_cq);
grpc_server_destroy(a.server);
grpc_completion_queue_destroy(a.cq);
- grpc_slice_buffer_destroy_internal(&outgoing);
-
+ grpc_completion_queue_destroy(client_cq);
grpc_shutdown();
}
+
+bool client_connection_preface_validator(grpc_slice_buffer* incoming,
+ void* arg) {
+ if (incoming->count < 1) {
+ return false;
+ }
+ grpc_slice slice = incoming->slices[0];
+ /* There should be atleast a settings frame present */
+ if (GRPC_SLICE_LENGTH(slice) < MIN_HTTP2_FRAME_SIZE) {
+ return false;
+ }
+ const uint8_t* p = GRPC_SLICE_START_PTR(slice);
+ /* Check the frame type (SETTINGS) */
+ if (*(p + 3) != 4) {
+ return false;
+ }
+ return true;
+}
+
+/* connection preface and settings frame to be sent by the client */
+#define CONNECTION_PREFACE_FROM_CLIENT \
+ "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
+ "\x00\x00\x00\x04\x00\x00\x00\x00\x00"
+
+grpc_bad_client_arg connection_preface_arg = {
+ client_connection_preface_validator, nullptr,
+ CONNECTION_PREFACE_FROM_CLIENT, sizeof(CONNECTION_PREFACE_FROM_CLIENT) - 1};
+
+bool rst_stream_client_validator(grpc_slice_buffer* incoming, void* arg) {
+ // Get last frame from incoming slice buffer.
+ grpc_slice_buffer last_frame_buffer;
+ grpc_slice_buffer_init(&last_frame_buffer);
+ grpc_slice_buffer_trim_end(incoming, 13, &last_frame_buffer);
+ GPR_ASSERT(last_frame_buffer.count == 1);
+ grpc_slice last_frame = last_frame_buffer.slices[0];
+
+ const uint8_t* p = GRPC_SLICE_START_PTR(last_frame);
+ bool success =
+ // Length == 4
+ *p++ != 0 || *p++ != 0 || *p++ != 4 ||
+ // Frame type (RST_STREAM)
+ *p++ != 3 ||
+ // Flags
+ *p++ != 0 ||
+ // Stream ID.
+ *p++ != 0 || *p++ != 0 || *p++ != 0 || *p++ != 1 ||
+ // Payload (error code)
+ *p++ == 0 || *p++ == 0 || *p++ == 0 || *p == 0 || *p == 11;
+
+ if (!success) {
+ gpr_log(GPR_INFO, "client expected RST_STREAM frame, not found");
+ }
+
+ grpc_slice_buffer_destroy(&last_frame_buffer);
+ return success;
+}
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+void server_verifier_request_call(grpc_server* server,
+ grpc_completion_queue* cq,
+ void* registered_method) {
+ grpc_call_error error;
+ grpc_call* s;
+ grpc_call_details call_details;
+ cq_verifier* cqv = cq_verifier_create(cq);
+ grpc_metadata_array request_metadata_recv;
+
+ grpc_call_details_init(&call_details);
+ grpc_metadata_array_init(&request_metadata_recv);
+
+ error = grpc_server_request_call(server, &s, &call_details,
+ &request_metadata_recv, cq, cq, tag(101));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+ cq_verify(cqv);
+
+ GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.host, "localhost"));
+ GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo/bar"));
+
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+ grpc_call_unref(s);
+ cq_verifier_destroy(cqv);
+}
diff --git a/test/core/bad_client/bad_client.h b/test/core/bad_client/bad_client.h
index d3abfac2aa..de7d830cd7 100644
--- a/test/core/bad_client/bad_client.h
+++ b/test/core/bad_client/bad_client.h
@@ -28,30 +28,69 @@
#define GRPC_BAD_CLIENT_REGISTERED_METHOD "/registered/bar"
#define GRPC_BAD_CLIENT_REGISTERED_HOST "localhost"
+/* The server side validator function to run */
typedef void (*grpc_bad_client_server_side_validator)(grpc_server* server,
grpc_completion_queue* cq,
void* registered_method);
-// Returns false if we need to read more data.
+/* Returns false if we need to read more data. */
typedef bool (*grpc_bad_client_client_stream_validator)(
- grpc_slice_buffer* incoming);
+ grpc_slice_buffer* incoming, void* arg);
+struct grpc_bad_client_arg {
+ grpc_bad_client_client_stream_validator client_validator;
+ void* client_validator_arg;
+ const char* client_payload;
+ size_t client_payload_length;
+};
+
+/* Flags for grpc_run_bad_client_test */
#define GRPC_BAD_CLIENT_DISCONNECT 1
#define GRPC_BAD_CLIENT_LARGE_REQUEST 2
/* Test runner.
-
- Create a server, and send client_payload to it as bytes from a client.
- Execute server_validator in a separate thread to assert that the bytes are
- handled as expected. */
+ *
+ * Create a server, and for each arg in \a args send client_payload. For each
+ * payload, run client_validator to make sure that the response is as expected.
+ * Also execute \a server_validator in a separate thread to assert that the
+ * bytes are handled as expected.
+ *
+ * The flags are only applicable to the last validator in the array. (This can
+ * be changed in the future if necessary)
+ */
void grpc_run_bad_client_test(
grpc_bad_client_server_side_validator server_validator,
- grpc_bad_client_client_stream_validator client_validator,
- const char* client_payload, size_t client_payload_length, uint32_t flags);
+ grpc_bad_client_arg args[], int num_args, uint32_t flags);
+
+/* A hack to let old tests work as before. In these tests, instead of an array,
+ * the tests provide a single client_validator and payload
+ */
+#define COMBINE1(X, Y) X##Y
+#define COMBINE(X, Y) COMBINE1(X, Y)
+
+#define GRPC_RUN_BAD_CLIENT_TEST(server_validator, client_validator, payload, \
+ flags) \
+ grpc_bad_client_arg COMBINE(bca, __LINE__) = {client_validator, nullptr, \
+ payload, sizeof(payload) - 1}; \
+ grpc_run_bad_client_test(server_validator, &COMBINE(bca, __LINE__), 1, flags)
+
+/* Helper validator functions */
+/* Client side validator for connection preface from server. \a arg is unused */
+bool client_connection_preface_validator(grpc_slice_buffer* incoming,
+ void* arg);
+
+/* Client side validator for checking if reset stream is present at the end
+ * of the buffer. \a arg is unused.
+ */
+bool rst_stream_client_validator(grpc_slice_buffer* incoming, void* arg);
-#define GRPC_RUN_BAD_CLIENT_TEST(server_validator, client_validator, payload, \
- flags) \
- grpc_run_bad_client_test(server_validator, client_validator, payload, \
- sizeof(payload) - 1, flags)
+/* Helper grpc_bad_client_arg arguments for direct use */
+/* Sends a connection preface from the client with an empty settings frame */
+extern grpc_bad_client_arg connection_preface_arg;
+/* Server side verifier function that performs a
+ * single grpc_server_request_call */
+void server_verifier_request_call(grpc_server* server,
+ grpc_completion_queue* cq,
+ void* registered_method);
#endif /* GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H */
diff --git a/test/core/bad_client/gen_build_yaml.py b/test/core/bad_client/gen_build_yaml.py
index 14c8a27334..a8fd777216 100755
--- a/test/core/bad_client/gen_build_yaml.py
+++ b/test/core/bad_client/gen_build_yaml.py
@@ -30,7 +30,7 @@ BAD_CLIENT_TESTS = {
'headers': default_test_options._replace(cpu_cost=0.2),
'initial_settings_frame': default_test_options._replace(cpu_cost=0.2),
'head_of_line_blocking': default_test_options,
- # 'large_metadata': default_test_options, #disabling as per issue #11745
+ 'large_metadata': default_test_options,
'server_registered_method': default_test_options,
'simple_request': default_test_options,
'window_overflow': default_test_options,
diff --git a/test/core/bad_client/generate_tests.bzl b/test/core/bad_client/generate_tests.bzl
index 022edf3ff3..b595defb8c 100755
--- a/test/core/bad_client/generate_tests.bzl
+++ b/test/core/bad_client/generate_tests.bzl
@@ -28,7 +28,7 @@ BAD_CLIENT_TESTS = {
'headers': test_options(),
'initial_settings_frame': test_options(),
'head_of_line_blocking': test_options(),
- # 'large_metadata': test_options(), # disabling as per issue #11745
+ 'large_metadata': test_options(),
'server_registered_method': test_options(),
'simple_request': test_options(),
'window_overflow': test_options(),
diff --git a/test/core/bad_client/tests/head_of_line_blocking.cc b/test/core/bad_client/tests/head_of_line_blocking.cc
index f56c4d71dd..8668e091b6 100644
--- a/test/core/bad_client/tests/head_of_line_blocking.cc
+++ b/test/core/bad_client/tests/head_of_line_blocking.cc
@@ -131,7 +131,8 @@ int main(int argc, char** argv) {
addbuf(hdr, sizeof(hdr));
addbuf(msg, FRAME_SIZE);
}
- grpc_run_bad_client_test(verifier, nullptr, g_buffer, g_count, 0);
+ grpc_bad_client_arg bca = {nullptr, nullptr, g_buffer, g_count};
+ grpc_run_bad_client_test(verifier, &bca, 1, 0);
gpr_free(g_buffer);
grpc_shutdown();
diff --git a/test/core/bad_client/tests/large_metadata.cc b/test/core/bad_client/tests/large_metadata.cc
index ff3e9eb932..d534753f53 100644
--- a/test/core/bad_client/tests/large_metadata.cc
+++ b/test/core/bad_client/tests/large_metadata.cc
@@ -31,23 +31,20 @@
// be longer than the C99 string literal limit. Instead, we dynamically
// construct it by adding the large headers one at a time.
-#define PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR \
- "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* settings frame */ \
- "\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* headers: generated from \
- large_metadata.headers in this \
- directory */ \
- "\x00\x00\x00\x04\x01\x00\x00\x00\x00" \
- "\x00" \
- "5{\x01\x05\x00\x00\x00\x01" \
- "\x10\x05:path\x08/foo/bar" \
- "\x10\x07:scheme\x04http" \
- "\x10\x07:method\x04POST" \
- "\x10\x0a:authority\x09localhost" \
- "\x10\x0c" \
- "content-type\x10" \
- "application/grpc" \
- "\x10\x14grpc-accept-encoding\x15identity,deflate,gzip" \
- "\x10\x02te\x08trailers" \
+/* headers: generated from large_metadata.headers in this directory */
+#define PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST \
+ "\x00\x00\x00\x04\x01\x00\x00\x00\x00" \
+ "\x00" \
+ "5{\x01\x05\x00\x00\x00\x01" \
+ "\x10\x05:path\x08/foo/bar" \
+ "\x10\x07:scheme\x04http" \
+ "\x10\x07:method\x04POST" \
+ "\x10\x0a:authority\x09localhost" \
+ "\x10\x0c" \
+ "content-type\x10" \
+ "application/grpc" \
+ "\x10\x14grpc-accept-encoding\x15identity,deflate,gzip" \
+ "\x10\x02te\x08trailers" \
"\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)"
// Each large-metadata header is constructed from these start and end
@@ -65,8 +62,8 @@
// The number of headers we're adding and the total size of the client
// payload.
#define NUM_HEADERS 46
-#define PFX_TOO_MUCH_METADATA_FROM_CLIENT_PAYLOAD_SIZE \
- ((sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR) - 1) + \
+#define TOO_MUCH_METADATA_FROM_CLIENT_REQUEST_SIZE \
+ ((sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST) - 1) + \
(NUM_HEADERS * PFX_TOO_MUCH_METADATA_FROM_CLIENT_HEADER_SIZE) + 1)
#define PFX_TOO_MUCH_METADATA_FROM_SERVER_STR \
@@ -95,32 +92,6 @@
static void* tag(intptr_t t) { return (void*)t; }
-static void server_verifier(grpc_server* server, grpc_completion_queue* cq,
- void* registered_method) {
- grpc_call_error error;
- grpc_call* s;
- grpc_call_details call_details;
- cq_verifier* cqv = cq_verifier_create(cq);
- grpc_metadata_array request_metadata_recv;
-
- grpc_call_details_init(&call_details);
- grpc_metadata_array_init(&request_metadata_recv);
-
- error = grpc_server_request_call(server, &s, &call_details,
- &request_metadata_recv, cq, cq, tag(101));
- GPR_ASSERT(GRPC_CALL_OK == error);
- CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
- cq_verify(cqv);
-
- GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.host, "localhost"));
- GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo/bar"));
-
- grpc_metadata_array_destroy(&request_metadata_recv);
- grpc_call_details_destroy(&call_details);
- grpc_call_unref(s);
- cq_verifier_destroy(cqv);
-}
-
static void server_verifier_sends_too_much_metadata(grpc_server* server,
grpc_completion_queue* cq,
void* registered_method) {
@@ -167,43 +138,6 @@ static void server_verifier_sends_too_much_metadata(grpc_server* server,
cq_verifier_destroy(cqv);
}
-static bool client_validator(grpc_slice_buffer* incoming) {
- for (size_t i = 0; i < incoming->count; ++i) {
- const char* s = (const char*)GRPC_SLICE_START_PTR(incoming->slices[i]);
- char* hex = gpr_dump(s, GRPC_SLICE_LENGTH(incoming->slices[i]),
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
- gpr_log(GPR_INFO, "RESPONSE SLICE %" PRIdPTR ": %s", i, hex);
- gpr_free(hex);
- }
-
- // Get last frame from incoming slice buffer.
- grpc_slice_buffer last_frame_buffer;
- grpc_slice_buffer_init(&last_frame_buffer);
- grpc_slice_buffer_trim_end(incoming, 13, &last_frame_buffer);
- GPR_ASSERT(last_frame_buffer.count == 1);
- grpc_slice last_frame = last_frame_buffer.slices[0];
-
- const uint8_t* p = GRPC_SLICE_START_PTR(last_frame);
- bool success =
- // Length == 4
- *p++ != 0 || *p++ != 0 || *p++ != 4 ||
- // Frame type (RST_STREAM)
- *p++ != 3 ||
- // Flags
- *p++ != 0 ||
- // Stream ID.
- *p++ != 0 || *p++ != 0 || *p++ != 0 || *p++ != 1 ||
- // Payload (error code)
- *p++ == 0 || *p++ == 0 || *p++ == 0 || *p == 0 || *p == 11;
-
- if (!success) {
- gpr_log(GPR_INFO, "client expected RST_STREAM frame, not found");
- }
-
- grpc_slice_buffer_destroy(&last_frame_buffer);
- return success;
-}
-
int main(int argc, char** argv) {
int i;
@@ -222,19 +156,22 @@ int main(int argc, char** argv) {
size_t headers_len;
const char* client_headers = gpr_strvec_flatten(&headers, &headers_len);
gpr_strvec_destroy(&headers);
- char client_payload[PFX_TOO_MUCH_METADATA_FROM_CLIENT_PAYLOAD_SIZE] =
- PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR;
- memcpy(
- client_payload + sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR) - 1,
- client_headers, headers_len);
- GRPC_RUN_BAD_CLIENT_TEST(server_verifier, client_validator, client_payload,
- 0);
+ char client_payload[TOO_MUCH_METADATA_FROM_CLIENT_REQUEST_SIZE] =
+ PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST;
+ memcpy(client_payload + sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST) - 1,
+ client_headers, headers_len);
+ grpc_bad_client_arg args[2];
+ args[0] = connection_preface_arg;
+ args[1].client_validator = rst_stream_client_validator;
+ args[1].client_payload = client_payload;
+ args[1].client_payload_length = sizeof(client_payload) - 1;
+
+ grpc_run_bad_client_test(server_verifier_request_call, args, 2, 0);
gpr_free((void*)client_headers);
// Test sending more metadata than the client will accept.
GRPC_RUN_BAD_CLIENT_TEST(server_verifier_sends_too_much_metadata,
- client_validator,
+ rst_stream_client_validator,
PFX_TOO_MUCH_METADATA_FROM_SERVER_STR, 0);
-
return 0;
}
diff --git a/test/core/bad_client/tests/window_overflow.cc b/test/core/bad_client/tests/window_overflow.cc
index ed8279c951..fe6b05d03a 100644
--- a/test/core/bad_client/tests/window_overflow.cc
+++ b/test/core/bad_client/tests/window_overflow.cc
@@ -26,8 +26,7 @@
#include "src/core/lib/surface/server.h"
#define PFX_STR \
- "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
- "\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* settings frame */ \
+ "\x00\x00\x00\x04\x01\x00\x00\x00\x00" \
"\x00\x00\xc9\x01\x04\x00\x00\x00\x01" /* headers: generated from \
simple_request.headers in this \
directory */ \
@@ -70,7 +69,7 @@ int main(int argc, char** argv) {
#define MAX_FRAME_SIZE 16384
#define MESSAGES_PER_FRAME (MAX_FRAME_SIZE / 5)
#define FRAME_SIZE (MESSAGES_PER_FRAME * 5)
-#define SEND_SIZE (6 * 1024 * 1024)
+#define SEND_SIZE (4 * 1024 * 1024)
#define NUM_FRAMES (SEND_SIZE / FRAME_SIZE + 1)
grpc_test_init(argc, argv);
grpc_init();
@@ -92,8 +91,10 @@ int main(int argc, char** argv) {
addbuf(message, sizeof(message));
}
}
- grpc_run_bad_client_test(verifier, nullptr, g_buffer, g_count,
- GRPC_BAD_CLIENT_LARGE_REQUEST);
+ grpc_bad_client_arg bca[2];
+ bca[0] = connection_preface_arg;
+ bca[1] = {rst_stream_client_validator, nullptr, g_buffer, g_count};
+ grpc_run_bad_client_test(verifier, bca, 2, GRPC_BAD_CLIENT_LARGE_REQUEST);
gpr_free(g_buffer);
grpc_shutdown();
diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD
index b5269c7ef0..d8b0395846 100644
--- a/test/core/client_channel/resolvers/BUILD
+++ b/test/core/client_channel/resolvers/BUILD
@@ -43,6 +43,18 @@ grpc_cc_test(
)
grpc_cc_test(
+ name = "dns_resolver_cooldown_test",
+ srcs = ["dns_resolver_cooldown_test.cc"],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+grpc_cc_test(
name = "sockaddr_resolver_test",
srcs = ["sockaddr_resolver_test.cc"],
language = "C++",
diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
new file mode 100644
index 0000000000..64342b48c8
--- /dev/null
+++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
@@ -0,0 +1,304 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstring>
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "test/core/util/test_config.h"
+
+static grpc_combiner* g_combiner;
+
+static void (*g_default_grpc_resolve_address)(
+ const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties, grpc_closure* on_done,
+ grpc_resolved_addresses** addrs);
+
+grpc_ares_request* (*g_default_dns_lookup_ares)(
+ const char* dns_server, const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties, grpc_closure* on_done,
+ grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json);
+
+// Counter incremented by test_resolve_address_impl indicating the number of
+// times a system-level resolution has happened.
+static int g_resolution_count;
+
+struct iomgr_args {
+ gpr_event ev;
+ gpr_atm done_atm;
+ gpr_mu* mu;
+ grpc_pollset* pollset;
+ grpc_pollset_set* pollset_set;
+} g_iomgr_args;
+
+// Wrapper around g_default_grpc_resolve_address in order to count the number of
+// times we incur in a system-level name resolution.
+static void test_resolve_address_impl(const char* name,
+ const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addrs) {
+ g_default_grpc_resolve_address(name, default_port, g_iomgr_args.pollset_set,
+ on_done, addrs);
+ ++g_resolution_count;
+}
+
+grpc_ares_request* test_dns_lookup_ares(
+ const char* dns_server, const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties, grpc_closure* on_done,
+ grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json) {
+ grpc_ares_request* result = g_default_dns_lookup_ares(
+ dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs,
+ check_grpclb, service_config_json);
+ ++g_resolution_count;
+ return result;
+}
+
+static gpr_timespec test_deadline(void) {
+ return grpc_timeout_seconds_to_deadline(100);
+}
+
+static void do_nothing(void* arg, grpc_error* error) {}
+
+void iomgr_args_init(iomgr_args* args) {
+ gpr_event_init(&args->ev);
+ args->pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
+ grpc_pollset_init(args->pollset, &args->mu);
+ args->pollset_set = grpc_pollset_set_create();
+ grpc_pollset_set_add_pollset(args->pollset_set, args->pollset);
+ gpr_atm_rel_store(&args->done_atm, 0);
+}
+
+void iomgr_args_finish(iomgr_args* args) {
+ GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
+ grpc_pollset_set_del_pollset(args->pollset_set, args->pollset);
+ grpc_pollset_set_destroy(args->pollset_set);
+ grpc_closure do_nothing_cb;
+ GRPC_CLOSURE_INIT(&do_nothing_cb, do_nothing, nullptr,
+ grpc_schedule_on_exec_ctx);
+ gpr_mu_lock(args->mu);
+ grpc_pollset_shutdown(args->pollset, &do_nothing_cb);
+ gpr_mu_unlock(args->mu);
+ // exec_ctx needs to be flushed before calling grpc_pollset_destroy()
+ grpc_core::ExecCtx::Get()->Flush();
+ grpc_pollset_destroy(args->pollset);
+ gpr_free(args->pollset);
+}
+
+static grpc_millis n_sec_deadline(int seconds) {
+ return grpc_timespec_to_millis_round_up(
+ grpc_timeout_seconds_to_deadline(seconds));
+}
+
+static void poll_pollset_until_request_done(iomgr_args* args) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_millis deadline = n_sec_deadline(10);
+ while (true) {
+ bool done = gpr_atm_acq_load(&args->done_atm) != 0;
+ if (done) {
+ break;
+ }
+ grpc_millis time_left = deadline - grpc_core::ExecCtx::Get()->Now();
+ gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRIdPTR, done, time_left);
+ GPR_ASSERT(time_left >= 0);
+ grpc_pollset_worker* worker = nullptr;
+ gpr_mu_lock(args->mu);
+ GRPC_LOG_IF_ERROR("pollset_work", grpc_pollset_work(args->pollset, &worker,
+ n_sec_deadline(1)));
+ gpr_mu_unlock(args->mu);
+ grpc_core::ExecCtx::Get()->Flush();
+ }
+ gpr_event_set(&args->ev, (void*)1);
+}
+
+typedef struct on_resolution_cb_arg {
+ const char* uri_str;
+ grpc_resolver* resolver;
+ grpc_channel_args* result;
+ grpc_millis delay_before_second_resolution;
+ bool using_cares;
+} on_resolution_cb_arg;
+
+// Counter for the number of times a resolution notification callback has been
+// invoked.
+static int g_on_resolution_invocations_count;
+
+// Set to true by the last callback in the resolution chain.
+bool g_all_callbacks_invoked;
+
+void on_third_resolution(void* arg, grpc_error* error) {
+ on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ ++g_on_resolution_invocations_count;
+ grpc_channel_args_destroy(cb_arg->result);
+ gpr_log(GPR_INFO,
+ "3rd: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
+ g_on_resolution_invocations_count, g_resolution_count);
+ // In this case we expect to have incurred in another system-level resolution
+ // because on_second_resolution slept for longer than the min resolution
+ // period.
+ GPR_ASSERT(g_on_resolution_invocations_count == 3);
+ GPR_ASSERT(g_resolution_count == 2);
+ grpc_resolver_shutdown_locked(cb_arg->resolver);
+ GRPC_RESOLVER_UNREF(cb_arg->resolver, "on_third_resolution");
+ if (cb_arg->using_cares) {
+ gpr_atm_rel_store(&g_iomgr_args.done_atm, 1);
+ gpr_mu_lock(g_iomgr_args.mu);
+ GRPC_LOG_IF_ERROR("pollset_kick",
+ grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
+ gpr_mu_unlock(g_iomgr_args.mu);
+ }
+ gpr_free(cb_arg);
+ g_all_callbacks_invoked = true;
+}
+
+void on_second_resolution(void* arg, grpc_error* error) {
+ on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+ ++g_on_resolution_invocations_count;
+ grpc_channel_args_destroy(cb_arg->result);
+
+ gpr_log(GPR_INFO,
+ "2nd: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
+ g_on_resolution_invocations_count, g_resolution_count);
+ // The resolution request for which this function is the callback happened
+ // before the min resolution period. Therefore, no new system-level
+ // resolutions happened, as indicated by g_resolution_count.
+ GPR_ASSERT(g_on_resolution_invocations_count == 2);
+ GPR_ASSERT(g_resolution_count == 1);
+ grpc_core::ExecCtx::Get()->TestOnlySetNow(
+ cb_arg->delay_before_second_resolution * 2);
+ grpc_resolver_next_locked(
+ cb_arg->resolver, &cb_arg->result,
+ GRPC_CLOSURE_CREATE(on_third_resolution, arg,
+ grpc_combiner_scheduler(g_combiner)));
+ grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
+ if (cb_arg->using_cares) {
+ gpr_mu_lock(g_iomgr_args.mu);
+ GRPC_LOG_IF_ERROR("pollset_kick",
+ grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
+ gpr_mu_unlock(g_iomgr_args.mu);
+ }
+}
+
+void on_first_resolution(void* arg, grpc_error* error) {
+ on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+ ++g_on_resolution_invocations_count;
+ grpc_channel_args_destroy(cb_arg->result);
+ grpc_resolver_next_locked(
+ cb_arg->resolver, &cb_arg->result,
+ GRPC_CLOSURE_CREATE(on_second_resolution, arg,
+ grpc_combiner_scheduler(g_combiner)));
+ grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
+ gpr_log(GPR_INFO,
+ "1st: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
+ g_on_resolution_invocations_count, g_resolution_count);
+ // Theres one initial system-level resolution and one invocation of a
+ // notification callback (the current function).
+ GPR_ASSERT(g_on_resolution_invocations_count == 1);
+ GPR_ASSERT(g_resolution_count == 1);
+ if (cb_arg->using_cares) {
+ gpr_mu_lock(g_iomgr_args.mu);
+ GRPC_LOG_IF_ERROR("pollset_kick",
+ grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
+ gpr_mu_unlock(g_iomgr_args.mu);
+ }
+}
+
+static void start_test_under_combiner(void* arg, grpc_error* error) {
+ on_resolution_cb_arg* res_cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+ grpc_resolver* resolver;
+ grpc_resolver_factory* factory = grpc_resolver_factory_lookup("dns");
+ grpc_uri* uri = grpc_uri_parse(res_cb_arg->uri_str, 0);
+ grpc_resolver_args args;
+ gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", res_cb_arg->uri_str,
+ factory->vtable->scheme);
+ GPR_ASSERT(uri);
+ memset(&args, 0, sizeof(args));
+ args.uri = uri;
+ args.combiner = g_combiner;
+ g_on_resolution_invocations_count = 0;
+ g_resolution_count = 0;
+ constexpr int kMinResolutionPeriodMs = 1000;
+
+ grpc_arg cooldown_arg;
+ cooldown_arg.key =
+ const_cast<char*>(GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
+ cooldown_arg.type = GRPC_ARG_INTEGER;
+ cooldown_arg.value.integer = kMinResolutionPeriodMs;
+ auto* cooldown_channel_args =
+ grpc_channel_args_copy_and_add(nullptr, &cooldown_arg, 1);
+ args.args = cooldown_channel_args;
+ resolver = grpc_resolver_factory_create_resolver(factory, &args);
+ grpc_channel_args_destroy(cooldown_channel_args);
+ GPR_ASSERT(resolver != nullptr);
+ res_cb_arg->resolver = resolver;
+ res_cb_arg->delay_before_second_resolution = kMinResolutionPeriodMs;
+ // First resolution, would incur in system-level resolution.
+ grpc_resolver_next_locked(
+ resolver, &res_cb_arg->result,
+ GRPC_CLOSURE_CREATE(on_first_resolution, res_cb_arg,
+ grpc_combiner_scheduler(g_combiner)));
+ grpc_uri_destroy(uri);
+ grpc_resolver_factory_unref(factory);
+}
+
+static void test_cooldown(bool using_cares) {
+ grpc_core::ExecCtx exec_ctx;
+ if (using_cares) iomgr_args_init(&g_iomgr_args);
+ on_resolution_cb_arg* res_cb_arg =
+ static_cast<on_resolution_cb_arg*>(gpr_zalloc(sizeof(*res_cb_arg)));
+ res_cb_arg->uri_str = "dns:127.0.0.1";
+ res_cb_arg->using_cares = using_cares;
+
+ GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(start_test_under_combiner, res_cb_arg,
+ grpc_combiner_scheduler(g_combiner)),
+ GRPC_ERROR_NONE);
+ if (using_cares) {
+ grpc_core::ExecCtx::Get()->Flush();
+ poll_pollset_until_request_done(&g_iomgr_args);
+ iomgr_args_finish(&g_iomgr_args);
+ }
+}
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+
+ g_combiner = grpc_combiner_create();
+
+ const bool using_cares = (grpc_resolve_address == grpc_resolve_address_ares);
+ g_default_grpc_resolve_address = grpc_resolve_address;
+ g_default_dns_lookup_ares = grpc_dns_lookup_ares;
+ grpc_dns_lookup_ares = test_dns_lookup_ares;
+ grpc_resolve_address = test_resolve_address_impl;
+
+ test_cooldown(using_cares);
+
+ {
+ grpc_core::ExecCtx exec_ctx;
+ GRPC_COMBINER_UNREF(g_combiner, "test");
+ }
+ grpc_shutdown();
+ GPR_ASSERT(g_all_callbacks_invoked);
+ return 0;
+}
diff --git a/test/core/end2end/h2_ssl_cert_test.cc b/test/core/end2end/h2_ssl_cert_test.cc
index 3383d6d5d1..9adb96e926 100644
--- a/test/core/end2end/h2_ssl_cert_test.cc
+++ b/test/core/end2end/h2_ssl_cert_test.cc
@@ -272,6 +272,20 @@ static void drain_cq(grpc_completion_queue* cq) {
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
+ /* Perform a completion queue next, so that any pending operations can be
+ * finished, and resources can be released. This is so that, shutdown does not
+ * hang. For example, the server might be stuck in the handshaking code, which
+ * keeps a ref to a listener. Unless, it is unref'd, shutdown won't be able
+ * to proceed.
+ *
+ * (If shutdown times out, it is probably because 100ms wasn't enough. In that
+ * case, the deadline can be increased. Or, we could simply have another
+ * thread for the server to poll the completion queue while the shutdown
+ * progresses.)
+ */
+ GPR_ASSERT(grpc_completion_queue_next(
+ f->cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
+ .type == GRPC_QUEUE_TIMEOUT);
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
@@ -288,8 +302,8 @@ static void shutdown_client(grpc_end2end_test_fixture* f) {
}
static void end_test(grpc_end2end_test_fixture* f) {
- shutdown_server(f);
shutdown_client(f);
+ shutdown_server(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
diff --git a/test/core/end2end/tests/streaming_error_response.cc b/test/core/end2end/tests/streaming_error_response.cc
index fe53fda9ef..6ad1cec086 100644
--- a/test/core/end2end/tests/streaming_error_response.cc
+++ b/test/core/end2end/tests/streaming_error_response.cc
@@ -111,7 +111,7 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
grpc_byte_buffer* response_payload1_recv = nullptr;
grpc_byte_buffer* response_payload2_recv = nullptr;
grpc_call_details call_details;
- grpc_status_code status;
+ grpc_status_code status = GRPC_STATUS_OK;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
diff --git a/test/core/fling/client.cc b/test/core/fling/client.cc
index b6d6cb9518..66810975fd 100644
--- a/test/core/fling/client.cc
+++ b/test/core/fling/client.cc
@@ -74,7 +74,7 @@ static void init_ping_pong_request(void) {
}
static void step_ping_pong_request(void) {
- GPR_TIMER_BEGIN("ping_pong", 1);
+ GPR_TIMER_SCOPE("ping_pong", 1);
grpc_slice host = grpc_slice_from_static_string("localhost");
call = grpc_channel_create_call(
channel, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
@@ -87,7 +87,6 @@ static void step_ping_pong_request(void) {
grpc_call_unref(call);
grpc_byte_buffer_destroy(response_payload_recv);
call = nullptr;
- GPR_TIMER_END("ping_pong", 1);
}
static void init_ping_pong_stream(void) {
@@ -117,13 +116,12 @@ static void init_ping_pong_stream(void) {
}
static void step_ping_pong_stream(void) {
+ GPR_TIMER_SCOPE("ping_pong", 1);
grpc_call_error error;
- GPR_TIMER_BEGIN("ping_pong", 1);
error = grpc_call_start_batch(call, stream_step_ops, 2, (void*)1, nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
grpc_byte_buffer_destroy(response_payload_recv);
- GPR_TIMER_END("ping_pong", 1);
}
static double now(void) {
diff --git a/test/core/http/BUILD b/test/core/http/BUILD
index a5ae6272db..03b8f4edfe 100644
--- a/test/core/http/BUILD
+++ b/test/core/http/BUILD
@@ -66,7 +66,12 @@ grpc_cc_test(
name = "httpcli_test",
srcs = ["httpcli_test.cc"],
language = "C++",
- data = ["test_server.py"],
+ data = [
+ "python_wrapper.sh",
+ "test_server.py",
+ "//src/core/tsi/test_creds:server1.pem",
+ "//src/core/tsi/test_creds:server1.key"
+ ],
deps = [
"//:gpr",
"//:grpc",
@@ -80,7 +85,13 @@ grpc_cc_test(
name = "httpscli_test",
srcs = ["httpscli_test.cc"],
language = "C++",
- data = ["test_server.py"],
+ data = [
+ "python_wrapper.sh",
+ "test_server.py",
+ "//src/core/tsi/test_creds:ca.pem",
+ "//src/core/tsi/test_creds:server1.pem",
+ "//src/core/tsi/test_creds:server1.key"
+ ],
deps = [
"//:gpr",
"//:grpc",
diff --git a/test/core/http/httpcli_test.cc b/test/core/http/httpcli_test.cc
index aa9416c3dd..3d892b939c 100644
--- a/test/core/http/httpcli_test.cc
+++ b/test/core/http/httpcli_test.cc
@@ -155,10 +155,17 @@ int main(int argc, char** argv) {
int arg_shift = 0;
/* figure out where we are */
char* root;
- if (lslash) {
- root = static_cast<char*>(gpr_malloc((size_t)(lslash - me + 1)));
+ if (lslash != nullptr) {
+ /* Hack for bazel target */
+ if ((unsigned)(lslash - me) >= (sizeof("http") - 1) &&
+ strncmp(me + (lslash - me) - sizeof("http") + 1, "http",
+ sizeof("http") - 1) == 0) {
+ lslash = me + (lslash - me) - sizeof("http");
+ }
+ root = static_cast<char*>(
+ gpr_malloc((size_t)(lslash - me + sizeof("/../.."))));
memcpy(root, me, (size_t)(lslash - me));
- root[lslash - me] = 0;
+ memcpy(root + (lslash - me), "/../..", sizeof("/../.."));
} else {
root = gpr_strdup(".");
}
@@ -168,8 +175,8 @@ int main(int argc, char** argv) {
args[0] = gpr_strdup(argv[1]);
} else {
arg_shift = 1;
- gpr_asprintf(&args[0], "%s/../../tools/distrib/python_wrapper.sh", root);
- gpr_asprintf(&args[1], "%s/../../test/core/http/test_server.py", root);
+ gpr_asprintf(&args[0], "%s/test/core/http/python_wrapper.sh", root);
+ gpr_asprintf(&args[1], "%s/test/core/http/test_server.py", root);
}
/* start the server */
diff --git a/test/core/http/httpscli_test.cc b/test/core/http/httpscli_test.cc
index ed2016e643..7e99ad4249 100644
--- a/test/core/http/httpscli_test.cc
+++ b/test/core/http/httpscli_test.cc
@@ -21,11 +21,13 @@
#include <string.h>
#include <grpc/grpc.h>
+#include <grpc/grpc_security_constants.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/gpr/env.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "test/core/util/port.h"
#include "test/core/util/subprocess.h"
@@ -153,10 +155,17 @@ int main(int argc, char** argv) {
int arg_shift = 0;
/* figure out where we are */
char* root;
- if (lslash) {
- root = static_cast<char*>(gpr_malloc((size_t)(lslash - me + 1)));
+ if (lslash != nullptr) {
+ /* Hack for bazel target */
+ if ((unsigned)(lslash - me) >= (sizeof("http") - 1) &&
+ strncmp(me + (lslash - me) - sizeof("http") + 1, "http",
+ sizeof("http") - 1) == 0) {
+ lslash = me + (lslash - me) - sizeof("http");
+ }
+ root = static_cast<char*>(
+ gpr_malloc((size_t)(lslash - me + sizeof("/../.."))));
memcpy(root, me, (size_t)(lslash - me));
- root[lslash - me] = 0;
+ memcpy(root + (lslash - me), "/../..", sizeof("/../.."));
} else {
root = gpr_strdup(".");
}
@@ -166,10 +175,16 @@ int main(int argc, char** argv) {
args[0] = gpr_strdup(argv[1]);
} else {
arg_shift = 1;
- gpr_asprintf(&args[0], "%s/../../tools/distrib/python_wrapper.sh", root);
- gpr_asprintf(&args[1], "%s/../../test/core/http/test_server.py", root);
+ gpr_asprintf(&args[0], "%s/test/core/http/python_wrapper.sh", root);
+ gpr_asprintf(&args[1], "%s/test/core/http/test_server.py", root);
}
+ /* Set the environment variable for the SSL certificate file */
+ char* pem_file;
+ gpr_asprintf(&pem_file, "%s/src/core/tsi/test_creds/ca.pem", root);
+ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, pem_file);
+ gpr_free(pem_file);
+
/* start the server */
args[1 + arg_shift] = const_cast<char*>("--port");
gpr_asprintf(&args[2 + arg_shift], "%d", port);
diff --git a/test/core/http/python_wrapper.sh b/test/core/http/python_wrapper.sh
new file mode 120000
index 0000000000..9ed6e3293f
--- /dev/null
+++ b/test/core/http/python_wrapper.sh
@@ -0,0 +1 @@
+../../../tools/distrib/python_wrapper.sh \ No newline at end of file
diff --git a/test/core/memory_usage/server.cc b/test/core/memory_usage/server.cc
index 4303ec70ec..7ee591dfac 100644
--- a/test/core/memory_usage/server.cc
+++ b/test/core/memory_usage/server.cc
@@ -289,6 +289,7 @@ int main(int argc, char** argv) {
}
// no break here since we want to continue to case
// FLING_SERVER_SEND_STATUS_SNAPSHOT to destroy the snapshot call
+ /* fallthrough */
case FLING_SERVER_SEND_STATUS_SNAPSHOT:
grpc_byte_buffer_destroy(payload_buffer);
grpc_byte_buffer_destroy(terminal_buffer);
diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD
index 6cec7feabc..d27123d1a3 100644
--- a/test/core/surface/BUILD
+++ b/test/core/surface/BUILD
@@ -19,18 +19,6 @@ licenses(["notice"]) # Apache v2
grpc_package(name = "test/core/surface")
grpc_cc_test(
- name = "alarm_test",
- srcs = ["alarm_test.cc"],
- language = "C++",
- deps = [
- "//:gpr",
- "//:grpc",
- "//test/core/util:gpr_test_util",
- "//test/core/util:grpc_test_util",
- ],
-)
-
-grpc_cc_test(
name = "grpc_byte_buffer_reader_test",
srcs = ["byte_buffer_reader_test.cc"],
language = "C++",
diff --git a/test/core/surface/alarm_test.cc b/test/core/surface/alarm_test.cc
deleted file mode 100644
index 67fc6833a5..0000000000
--- a/test/core/surface/alarm_test.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <grpc/support/useful.h>
-#include "test/core/util/test_config.h"
-
-#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
-
-static void* create_test_tag(void) {
- static intptr_t i = 0;
- return (void*)(++i);
-}
-
-/* helper for tests to shutdown correctly and tersely */
-static void shutdown_and_destroy(grpc_completion_queue* cc) {
- grpc_event ev;
- grpc_completion_queue_shutdown(cc);
- /* By the time grpc_completion_queue_shutdown runs, the cq's internal
- pending event counter might not have been updated yet by a previous
- cq_end_op_for_next (which releases a completed event first and only later
- updates the pending event counter), so we can't rely on a no-polling
- cq_next to never return GRPC_QUEUE_TIMEOUT. Using a deadline in the future
- solves the problem. See https://github.com/grpc/grpc/issues/13693.
- */
- ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(2),
- nullptr);
- GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
- grpc_completion_queue_destroy(cc);
-}
-
-static void test_alarm(void) {
- grpc_completion_queue* cc;
-
- LOG_TEST("test_alarm");
- cc = grpc_completion_queue_create_for_next(nullptr);
- {
- /* regular expiry */
- grpc_event ev;
- void* tag = create_test_tag();
- grpc_alarm* alarm = grpc_alarm_create(nullptr);
- grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(1), tag,
- nullptr);
-
- ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(2),
- nullptr);
- GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
- GPR_ASSERT(ev.tag == tag);
- GPR_ASSERT(ev.success);
- grpc_alarm_destroy(alarm, nullptr);
- }
- {
- /* cancellation */
- grpc_event ev;
- void* tag = create_test_tag();
- grpc_alarm* alarm = grpc_alarm_create(nullptr);
- grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(2), tag,
- nullptr);
-
- grpc_alarm_cancel(alarm, nullptr);
- ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(1),
- nullptr);
- GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
- GPR_ASSERT(ev.tag == tag);
- GPR_ASSERT(ev.success == 0);
- grpc_alarm_destroy(alarm, nullptr);
- }
- {
- /* alarm_destroy before cq_next */
- grpc_event ev;
- void* tag = create_test_tag();
- grpc_alarm* alarm = grpc_alarm_create(nullptr);
- grpc_alarm_set(alarm, cc, grpc_timeout_seconds_to_deadline(2), tag,
- nullptr);
-
- grpc_alarm_destroy(alarm, nullptr);
- ev = grpc_completion_queue_next(cc, grpc_timeout_seconds_to_deadline(1),
- nullptr);
- GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
- GPR_ASSERT(ev.tag == tag);
- GPR_ASSERT(ev.success == 0);
- }
- {
- /* alarm_destroy before set */
- grpc_alarm* alarm = grpc_alarm_create(nullptr);
- grpc_alarm_destroy(alarm, nullptr);
- }
-
- shutdown_and_destroy(cc);
-}
-
-int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
- grpc_init();
- test_alarm();
- grpc_shutdown();
- return 0;
-}
diff --git a/test/core/surface/byte_buffer_reader_test.cc b/test/core/surface/byte_buffer_reader_test.cc
index 0c8a07c7fd..91662b027a 100644
--- a/test/core/surface/byte_buffer_reader_test.cc
+++ b/test/core/surface/byte_buffer_reader_test.cc
@@ -205,8 +205,8 @@ static void test_readall(void) {
LOG_TEST("test_readall");
- memset(lotsa_as, 'a', 512);
- memset(lotsa_bs, 'b', 1024);
+ memset(lotsa_as, 'a', 512 * sizeof(lotsa_as[0]));
+ memset(lotsa_bs, 'b', 1024 * sizeof(lotsa_bs[0]));
/* use slices large enough to overflow inlining */
slices[0] = grpc_slice_malloc(512);
memcpy(GRPC_SLICE_START_PTR(slices[0]), lotsa_as, 512);
@@ -240,8 +240,8 @@ static void test_byte_buffer_copy(void) {
LOG_TEST("test_byte_buffer_copy");
- memset(lotsa_as, 'a', 512);
- memset(lotsa_bs, 'b', 1024);
+ memset(lotsa_as, 'a', 512 * sizeof(lotsa_as[0]));
+ memset(lotsa_bs, 'b', 1024 * sizeof(lotsa_bs[0]));
/* use slices large enough to overflow inlining */
slices[0] = grpc_slice_malloc(512);
memcpy(GRPC_SLICE_START_PTR(slices[0]), lotsa_as, 512);
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index a191987577..91554fe2a3 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -95,10 +95,6 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_completion_queue_destroy);
printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_init);
printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_flush);
- printf("%lx", (unsigned long) grpc_alarm_create);
- printf("%lx", (unsigned long) grpc_alarm_set);
- printf("%lx", (unsigned long) grpc_alarm_cancel);
- printf("%lx", (unsigned long) grpc_alarm_destroy);
printf("%lx", (unsigned long) grpc_channel_check_connectivity_state);
printf("%lx", (unsigned long) grpc_channel_num_external_connectivity_watchers);
printf("%lx", (unsigned long) grpc_channel_watch_connectivity_state);
diff --git a/test/core/transport/chttp2/settings_timeout_test.cc b/test/core/transport/chttp2/settings_timeout_test.cc
index d7d6ee7508..7fb395d4b6 100644
--- a/test/core/transport/chttp2/settings_timeout_test.cc
+++ b/test/core/transport/chttp2/settings_timeout_test.cc
@@ -169,7 +169,7 @@ class Client {
grpc_closure* closure() { return &closure_; }
- bool done() const { return done_; }
+ bool done() const { return gpr_atm_acq_load(&done_atm_) != 0; }
// Caller does NOT take ownership of the error.
grpc_error* error() const { return error_; }
@@ -179,11 +179,11 @@ class Client {
gpr_log(GPR_INFO, "OnEventDone(): %s", grpc_error_string(error));
EventState* state = (EventState*)arg;
state->error_ = GRPC_ERROR_REF(error);
- state->done_ = true;
+ gpr_atm_rel_store(&state->done_atm_, 1);
}
grpc_closure closure_;
- bool done_ = false;
+ gpr_atm done_atm_ = 0;
grpc_error* error_ = GRPC_ERROR_NONE;
};
diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc
index 8939c0434b..bf54383c54 100644
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -667,9 +667,15 @@ int main(int argc, char** argv) {
ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain();
ssl_tsi_test_do_handshake_with_bad_server_cert();
ssl_tsi_test_do_handshake_with_bad_client_cert();
- ssl_tsi_test_do_handshake_alpn_client_no_server();
+ // TODO: BoringSSL and OpenSSL have different behaviors on handling mismatched
+ // ALPN. Re-enable this test if we can detect in the runtime which SSL library
+ // is used.
+ // ssl_tsi_test_do_handshake_alpn_client_no_server();
ssl_tsi_test_do_handshake_alpn_server_no_client();
- ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
+ // TODO: BoringSSL and OpenSSL have different behaviors on handling mismatched
+ // ALPN. Re-enable this test if we can detect in the runtime which SSL library
+ // is used.
+ // ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
ssl_tsi_test_do_handshake_alpn_client_server_ok();
ssl_tsi_test_do_round_trip_for_all_configs();
ssl_tsi_test_do_round_trip_odd_buffer_size();
diff --git a/test/core/util/passthru_endpoint.cc b/test/core/util/passthru_endpoint.cc
index 5f127cb960..0da0765979 100644
--- a/test/core/util/passthru_endpoint.cc
+++ b/test/core/util/passthru_endpoint.cc
@@ -48,8 +48,6 @@ struct passthru_endpoint {
gpr_mu mu;
int halves;
grpc_passthru_endpoint_stats* stats;
- grpc_passthru_endpoint_stats
- dummy_stats; // used if constructor stats == nullptr
bool shutdown;
half client;
half server;
@@ -137,6 +135,7 @@ static void me_destroy(grpc_endpoint* ep) {
if (0 == --p->halves) {
gpr_mu_unlock(&p->mu);
gpr_mu_destroy(&p->mu);
+ grpc_passthru_endpoint_stats_destroy(p->stats);
grpc_slice_buffer_destroy_internal(&p->client.read_buffer);
grpc_slice_buffer_destroy_internal(&p->server.read_buffer);
grpc_resource_user_unref(p->client.resource_user);
@@ -194,11 +193,30 @@ void grpc_passthru_endpoint_create(grpc_endpoint** client,
passthru_endpoint* m = (passthru_endpoint*)gpr_malloc(sizeof(*m));
m->halves = 2;
m->shutdown = 0;
- m->stats = stats == nullptr ? &m->dummy_stats : stats;
- memset(m->stats, 0, sizeof(*m->stats));
+ if (stats == nullptr) {
+ m->stats = grpc_passthru_endpoint_stats_create();
+ } else {
+ gpr_ref(&stats->refs);
+ m->stats = stats;
+ }
half_init(&m->client, m, resource_quota, "client");
half_init(&m->server, m, resource_quota, "server");
gpr_mu_init(&m->mu);
*client = &m->client.base;
*server = &m->server.base;
}
+
+grpc_passthru_endpoint_stats* grpc_passthru_endpoint_stats_create() {
+ grpc_passthru_endpoint_stats* stats =
+ (grpc_passthru_endpoint_stats*)gpr_malloc(
+ sizeof(grpc_passthru_endpoint_stats));
+ memset(stats, 0, sizeof(*stats));
+ gpr_ref_init(&stats->refs, 1);
+ return stats;
+}
+
+void grpc_passthru_endpoint_stats_destroy(grpc_passthru_endpoint_stats* stats) {
+ if (gpr_unref(&stats->refs)) {
+ gpr_free(stats);
+ }
+}
diff --git a/test/core/util/passthru_endpoint.h b/test/core/util/passthru_endpoint.h
index bddd8ea6a2..a46c775505 100644
--- a/test/core/util/passthru_endpoint.h
+++ b/test/core/util/passthru_endpoint.h
@@ -23,7 +23,11 @@
#include "src/core/lib/iomgr/endpoint.h"
+/* The struct is refcounted, always use grpc_passthru_endpoint_stats_create and
+ * grpc_passthru_endpoint_stats_destroy, rather then embedding it in your
+ * objects by value. */
typedef struct {
+ gpr_refcount refs;
gpr_atm num_writes;
} grpc_passthru_endpoint_stats;
@@ -32,4 +36,8 @@ void grpc_passthru_endpoint_create(grpc_endpoint** client,
grpc_resource_quota* resource_quota,
grpc_passthru_endpoint_stats* stats);
+grpc_passthru_endpoint_stats* grpc_passthru_endpoint_stats_create();
+
+void grpc_passthru_endpoint_stats_destroy(grpc_passthru_endpoint_stats* stats);
+
#endif