diff options
author | Vijay Pai <vpai@google.com> | 2018-02-02 11:21:07 -0800 |
---|---|---|
committer | Vijay Pai <vpai@google.com> | 2018-02-02 11:21:07 -0800 |
commit | 1acfaca3e630fbb4c64de1eb7267f969730e49da (patch) | |
tree | 08619d38599aeb5dfdff0a7b341a07014f7ea4d1 /test/core | |
parent | 7ce8b94b691e08efc7206ac9365d71502872e154 (diff) | |
parent | c8e07c4964c98fb216dfcd562229ae515fc84a09 (diff) |
Merge branch 'master' into gpr_review_host_port
Diffstat (limited to 'test/core')
26 files changed, 727 insertions, 1401 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/BUILD b/test/core/client_channel/BUILD index ec72e0ea72..890e03fec1 100644 --- a/test/core/client_channel/BUILD +++ b/test/core/client_channel/BUILD @@ -23,24 +23,11 @@ load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") grpc_fuzzer( name = "uri_fuzzer_test", srcs = ["uri_fuzzer_test.cc"], - language = "C++", corpus = "uri_corpus", - deps = [ - "//:gpr", - "//:grpc", - "//test/core/util:grpc_test_util", - ], -) - -grpc_cc_test( - name = "lb_policies_test", - srcs = ["lb_policies_test.cc"], language = "C++", deps = [ "//:gpr", "//:grpc", - "//test/core/end2end:cq_verifier", - "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", ], ) diff --git a/test/core/client_channel/lb_policies_test.cc b/test/core/client_channel/lb_policies_test.cc deleted file mode 100644 index a632bef85b..0000000000 --- a/test/core/client_channel/lb_policies_test.cc +++ /dev/null @@ -1,1029 +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 <stdarg.h> -#include <string.h> - -#include <grpc/grpc.h> -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/string_util.h> -#include <grpc/support/time.h> - -#include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/ext/filters/client_channel/lb_policy_registry.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/gpr/host_port.h" -#include "src/core/lib/gpr/string.h" -#include "src/core/lib/surface/channel.h" -#include "src/core/lib/surface/server.h" -#include "test/core/end2end/cq_verifier.h" -#include "test/core/util/port.h" -#include "test/core/util/test_config.h" - -#define RETRY_TIMEOUT 300 - -typedef struct servers_fixture { - size_t num_servers; - grpc_server** servers; - grpc_call** server_calls; - grpc_completion_queue* cq; - grpc_completion_queue* shutdown_cq; - char** servers_hostports; - grpc_metadata_array* request_metadata_recv; -} servers_fixture; - -typedef struct request_sequences { - size_t n; /* number of iterations */ - int* connections; /* indexed by the interation number, value is the index of - the server it connected to or -1 if none */ - /* indexed by the interation number, value is the client connectivity state */ - grpc_connectivity_state* connectivity_states; -} request_sequences; - -typedef void (*verifier_fn)(const servers_fixture*, grpc_channel*, - const request_sequences*, const size_t); - -typedef struct test_spec { - size_t num_iters; - size_t num_servers; - - int** kill_at; - int** revive_at; - - const char* description; - - verifier_fn verifier; - -} test_spec; - -static void test_spec_reset(test_spec* spec) { - size_t i, j; - - for (i = 0; i < spec->num_iters; i++) { - for (j = 0; j < spec->num_servers; j++) { - spec->kill_at[i][j] = 0; - spec->revive_at[i][j] = 0; - } - } -} - -static test_spec* test_spec_create(size_t num_iters, size_t num_servers) { - test_spec* spec; - size_t i; - - spec = static_cast<test_spec*>(gpr_malloc(sizeof(test_spec))); - spec->num_iters = num_iters; - spec->num_servers = num_servers; - spec->kill_at = static_cast<int**>(gpr_malloc(sizeof(int*) * num_iters)); - spec->revive_at = static_cast<int**>(gpr_malloc(sizeof(int*) * num_iters)); - for (i = 0; i < num_iters; i++) { - spec->kill_at[i] = static_cast<int*>(gpr_malloc(sizeof(int) * num_servers)); - spec->revive_at[i] = - static_cast<int*>(gpr_malloc(sizeof(int) * num_servers)); - } - - test_spec_reset(spec); - return spec; -} - -static void test_spec_destroy(test_spec* spec) { - size_t i; - for (i = 0; i < spec->num_iters; i++) { - gpr_free(spec->kill_at[i]); - gpr_free(spec->revive_at[i]); - } - - gpr_free(spec->kill_at); - gpr_free(spec->revive_at); - - gpr_free(spec); -} - -static void* tag(intptr_t t) { return (void*)t; } - -static gpr_timespec n_millis_time(int n) { - return gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(n, GPR_TIMESPAN)); -} - -static void drain_cq(grpc_completion_queue* cq) { - grpc_event ev; - do { - ev = grpc_completion_queue_next(cq, n_millis_time(5000), nullptr); - } while (ev.type != GRPC_QUEUE_SHUTDOWN); -} - -static void kill_server(const servers_fixture* f, size_t i) { - gpr_log(GPR_INFO, "KILLING SERVER %" PRIuPTR, i); - GPR_ASSERT(f->servers[i] != nullptr); - grpc_server_shutdown_and_notify(f->servers[i], f->shutdown_cq, tag(10000)); - GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(10000), - n_millis_time(5000), nullptr) - .type == GRPC_OP_COMPLETE); - grpc_server_destroy(f->servers[i]); - f->servers[i] = nullptr; -} - -typedef struct request_data { - grpc_metadata_array initial_metadata_recv; - grpc_metadata_array trailing_metadata_recv; - grpc_slice details; - grpc_status_code status; - grpc_call_details* call_details; -} request_data; - -static void revive_server(const servers_fixture* f, request_data* rdata, - size_t i) { - int got_port; - gpr_log(GPR_INFO, "RAISE AGAIN SERVER %" PRIuPTR, i); - GPR_ASSERT(f->servers[i] == nullptr); - - gpr_log(GPR_DEBUG, "revive: %s", f->servers_hostports[i]); - - f->servers[i] = grpc_server_create(nullptr, nullptr); - grpc_server_register_completion_queue(f->servers[i], f->cq, nullptr); - GPR_ASSERT((got_port = grpc_server_add_insecure_http2_port( - f->servers[i], f->servers_hostports[i])) > 0); - grpc_server_start(f->servers[i]); - - GPR_ASSERT(GRPC_CALL_OK == - grpc_server_request_call(f->servers[i], &f->server_calls[i], - &rdata->call_details[i], - &f->request_metadata_recv[i], f->cq, - f->cq, tag(1000 + (int)i))); -} - -static servers_fixture* setup_servers(const char* server_host, - request_data* rdata, - const size_t num_servers) { - servers_fixture* f = - static_cast<servers_fixture*>(gpr_malloc(sizeof(servers_fixture))); - size_t i; - - f->num_servers = num_servers; - f->server_calls = - static_cast<grpc_call**>(gpr_malloc(sizeof(grpc_call*) * num_servers)); - f->request_metadata_recv = static_cast<grpc_metadata_array*>( - gpr_malloc(sizeof(grpc_metadata_array) * num_servers)); - /* Create servers. */ - f->servers = static_cast<grpc_server**>( - gpr_malloc(sizeof(grpc_server*) * num_servers)); - f->servers_hostports = - static_cast<char**>(gpr_malloc(sizeof(char*) * num_servers)); - f->cq = grpc_completion_queue_create_for_next(nullptr); - f->shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr); - for (i = 0; i < num_servers; i++) { - grpc_metadata_array_init(&f->request_metadata_recv[i]); - gpr_join_host_port(&f->servers_hostports[i], server_host, - grpc_pick_unused_port_or_die()); - f->servers[i] = nullptr; - revive_server(f, rdata, i); - } - return f; -} - -static void teardown_servers(servers_fixture* f) { - size_t i; - /* Destroy server. */ - for (i = 0; i < f->num_servers; i++) { - if (f->servers[i] == nullptr) continue; - grpc_server_shutdown_and_notify(f->servers[i], f->shutdown_cq, tag(10000)); - GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(10000), - n_millis_time(5000), nullptr) - .type == GRPC_OP_COMPLETE); - grpc_server_destroy(f->servers[i]); - } - grpc_completion_queue_shutdown(f->cq); - drain_cq(f->cq); - grpc_completion_queue_destroy(f->cq); - grpc_completion_queue_destroy(f->shutdown_cq); - - gpr_free(f->servers); - - for (i = 0; i < f->num_servers; i++) { - gpr_free(f->servers_hostports[i]); - grpc_metadata_array_destroy(&f->request_metadata_recv[i]); - } - - gpr_free(f->servers_hostports); - gpr_free(f->request_metadata_recv); - gpr_free(f->server_calls); - gpr_free(f); -} - -static request_sequences request_sequences_create(size_t n) { - request_sequences res; - res.n = n; - res.connections = static_cast<int*>(gpr_malloc(sizeof(*res.connections) * n)); - res.connectivity_states = static_cast<grpc_connectivity_state*>( - gpr_malloc(sizeof(*res.connectivity_states) * n)); - memset(res.connections, 0, sizeof(*res.connections) * n); - memset(res.connectivity_states, 0, sizeof(*res.connectivity_states) * n); - return res; -} - -static void request_sequences_destroy(const request_sequences* rseqs) { - gpr_free(rseqs->connections); - gpr_free(rseqs->connectivity_states); -} - -/** Returns connection sequence (server indices), which must be freed */ -static request_sequences perform_request(servers_fixture* f, - grpc_channel* client, - request_data* rdata, - const test_spec* spec) { - grpc_call* c; - int s_idx; - int* s_valid; - grpc_op ops[6]; - grpc_op* op; - int was_cancelled; - size_t i, iter_num; - grpc_event ev; - int read_tag; - int completed_client; - const request_sequences sequences = request_sequences_create(spec->num_iters); - - s_valid = static_cast<int*>(gpr_malloc(sizeof(int) * f->num_servers)); - - for (iter_num = 0; iter_num < spec->num_iters; iter_num++) { - cq_verifier* cqv = cq_verifier_create(f->cq); - was_cancelled = 2; - - for (i = 0; i < f->num_servers; i++) { - if (spec->kill_at[iter_num][i] != 0) { - kill_server(f, i); - } else if (spec->revive_at[iter_num][i] != 0) { - /* killing takes precedence */ - revive_server(f, rdata, i); - } - } - - sequences.connections[iter_num] = -1; - grpc_metadata_array_init(&rdata->initial_metadata_recv); - grpc_metadata_array_init(&rdata->trailing_metadata_recv); - - for (i = 0; i < f->num_servers; i++) { - grpc_call_details_init(&rdata->call_details[i]); - } - memset(s_valid, 0, f->num_servers * sizeof(int)); - - grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr"); - c = grpc_channel_create_call(client, nullptr, GRPC_PROPAGATE_DEFAULTS, - f->cq, grpc_slice_from_static_string("/foo"), - &host, gpr_inf_future(GPR_CLOCK_REALTIME), - nullptr); - GPR_ASSERT(c); - completed_client = 0; - - 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 = nullptr; - op++; - op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - op->flags = 0; - op->reserved = nullptr; - op++; - op->op = GRPC_OP_RECV_INITIAL_METADATA; - op->data.recv_initial_metadata.recv_initial_metadata = - &rdata->initial_metadata_recv; - op->flags = 0; - op->reserved = nullptr; - op++; - op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = - &rdata->trailing_metadata_recv; - op->data.recv_status_on_client.status = &rdata->status; - op->data.recv_status_on_client.status_details = &rdata->details; - op->flags = 0; - op->reserved = nullptr; - op++; - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, (size_t)(op - ops), - tag(1), nullptr)); - - s_idx = -1; - while ((ev = grpc_completion_queue_next( - f->cq, grpc_timeout_milliseconds_to_deadline(RETRY_TIMEOUT), - nullptr)) - .type != GRPC_QUEUE_TIMEOUT) { - GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); - read_tag = ((int)(intptr_t)ev.tag); - const grpc_connectivity_state conn_state = - grpc_channel_check_connectivity_state(client, 0); - sequences.connectivity_states[iter_num] = conn_state; - gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%" PRIuPTR, - ev.success, ev.type, read_tag, iter_num); - if (ev.success && read_tag >= 1000) { - GPR_ASSERT(s_idx == -1); /* only one server must reply */ - /* only server notifications for non-shutdown events */ - s_idx = read_tag - 1000; - s_valid[s_idx] = 1; - sequences.connections[iter_num] = s_idx; - break; - } else if (read_tag == 1) { - gpr_log(GPR_DEBUG, "client timed out"); - GPR_ASSERT(ev.success); - completed_client = 1; - } - } - - if (s_idx >= 0) { - 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 = nullptr; - 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_UNIMPLEMENTED; - grpc_slice status_details = grpc_slice_from_static_string("xyz"); - op->data.send_status_from_server.status_details = &status_details; - op->flags = 0; - op->reserved = nullptr; - op++; - op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; - op->data.recv_close_on_server.cancelled = &was_cancelled; - op->flags = 0; - op->reserved = nullptr; - op++; - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(f->server_calls[s_idx], - ops, (size_t)(op - ops), - tag(102), nullptr)); - - CQ_EXPECT_COMPLETION(cqv, tag(102), 1); - if (!completed_client) { - CQ_EXPECT_COMPLETION(cqv, tag(1), 1); - } - cq_verify(cqv); - - GPR_ASSERT(rdata->status == GRPC_STATUS_UNIMPLEMENTED); - GPR_ASSERT(0 == grpc_slice_str_cmp(rdata->details, "xyz")); - GPR_ASSERT(0 == - grpc_slice_str_cmp(rdata->call_details[s_idx].method, "/foo")); - GPR_ASSERT(0 == grpc_slice_str_cmp(rdata->call_details[s_idx].host, - "foo.test.google.fr")); - GPR_ASSERT(was_cancelled == 1); - - grpc_call_unref(f->server_calls[s_idx]); - - /* ask for the next request on this server */ - GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( - f->servers[s_idx], &f->server_calls[s_idx], - &rdata->call_details[s_idx], - &f->request_metadata_recv[s_idx], f->cq, - f->cq, tag(1000 + (int)s_idx))); - } else { /* no response from server */ - grpc_call_cancel(c, nullptr); - if (!completed_client) { - CQ_EXPECT_COMPLETION(cqv, tag(1), 1); - cq_verify(cqv); - } - } - - GPR_ASSERT(grpc_completion_queue_next( - f->cq, grpc_timeout_milliseconds_to_deadline(RETRY_TIMEOUT), - nullptr) - .type == GRPC_QUEUE_TIMEOUT); - - grpc_metadata_array_destroy(&rdata->initial_metadata_recv); - grpc_metadata_array_destroy(&rdata->trailing_metadata_recv); - - cq_verifier_destroy(cqv); - - grpc_call_unref(c); - - for (i = 0; i < f->num_servers; i++) { - grpc_call_details_destroy(&rdata->call_details[i]); - } - grpc_slice_unref(rdata->details); - } - - gpr_free(s_valid); - - return sequences; -} - -static grpc_call** perform_multirequest(servers_fixture* f, - grpc_channel* client, - size_t concurrent_calls) { - grpc_call** calls; - grpc_op ops[6]; - grpc_op* op; - size_t i; - - calls = static_cast<grpc_call**>( - gpr_malloc(sizeof(grpc_call*) * concurrent_calls)); - for (i = 0; i < f->num_servers; i++) { - kill_server(f, i); - } - - 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 = nullptr; - op++; - op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - op->flags = 0; - op->reserved = nullptr; - - grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr"); - for (i = 0; i < concurrent_calls; i++) { - calls[i] = grpc_channel_create_call( - client, nullptr, GRPC_PROPAGATE_DEFAULTS, f->cq, - grpc_slice_from_static_string("/foo"), &host, - gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); - GPR_ASSERT(calls[i]); - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(calls[i], ops, - (size_t)(op - ops), tag(1), - nullptr)); - } - - return calls; -} - -void run_spec(const test_spec* spec) { - grpc_channel* client; - char* client_hostport; - char* servers_hostports_str; - request_data rdata; - servers_fixture* f; - grpc_channel_args args; - grpc_arg arg_array[2]; - rdata.call_details = static_cast<grpc_call_details*>( - gpr_malloc(sizeof(grpc_call_details) * spec->num_servers)); - f = setup_servers("127.0.0.1", &rdata, spec->num_servers); - - /* Create client. */ - servers_hostports_str = gpr_strjoin_sep((const char**)f->servers_hostports, - f->num_servers, ",", nullptr); - gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str); - - arg_array[0].type = GRPC_ARG_INTEGER; - arg_array[0].key = - const_cast<char*>("grpc.testing.fixed_reconnect_backoff_ms"); - arg_array[0].value.integer = RETRY_TIMEOUT; - arg_array[1].type = GRPC_ARG_STRING; - arg_array[1].key = const_cast<char*>(GRPC_ARG_LB_POLICY_NAME); - arg_array[1].value.string = const_cast<char*>("round_robin"); - args.num_args = 2; - args.args = arg_array; - - client = grpc_insecure_channel_create(client_hostport, &args, nullptr); - - gpr_log(GPR_INFO, "Testing '%s' with servers=%s client=%s", spec->description, - servers_hostports_str, client_hostport); - - const request_sequences sequences = perform_request(f, client, &rdata, spec); - - spec->verifier(f, client, &sequences, spec->num_iters); - - gpr_free(client_hostport); - gpr_free(servers_hostports_str); - gpr_free(rdata.call_details); - request_sequences_destroy(&sequences); - - grpc_channel_destroy(client); /* calls the LB's shutdown func */ - teardown_servers(f); -} - -static grpc_channel* create_client(const servers_fixture* f) { - grpc_channel* client; - char* client_hostport; - char* servers_hostports_str; - grpc_arg arg_array[3]; - grpc_channel_args args; - - servers_hostports_str = gpr_strjoin_sep((const char**)f->servers_hostports, - f->num_servers, ",", nullptr); - gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str); - - arg_array[0].type = GRPC_ARG_INTEGER; - arg_array[0].key = - const_cast<char*>("grpc.testing.fixed_reconnect_backoff_ms"); - arg_array[0].value.integer = RETRY_TIMEOUT; - arg_array[1].type = GRPC_ARG_STRING; - arg_array[1].key = const_cast<char*>(GRPC_ARG_LB_POLICY_NAME); - arg_array[1].value.string = const_cast<char*>("ROUND_ROBIN"); - arg_array[2].type = GRPC_ARG_INTEGER; - arg_array[2].key = - const_cast<char*>(GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS); - arg_array[2].value.integer = 0; - args.num_args = GPR_ARRAY_SIZE(arg_array); - args.args = arg_array; - - client = grpc_insecure_channel_create(client_hostport, &args, nullptr); - gpr_free(client_hostport); - gpr_free(servers_hostports_str); - - return client; -} - -static void test_ping() { - grpc_channel* client; - request_data rdata; - servers_fixture* f; - cq_verifier* cqv; - grpc_connectivity_state state = GRPC_CHANNEL_IDLE; - const size_t num_servers = 1; - int i; - - rdata.call_details = static_cast<grpc_call_details*>( - gpr_malloc(sizeof(grpc_call_details) * num_servers)); - f = setup_servers("127.0.0.1", &rdata, num_servers); - cqv = cq_verifier_create(f->cq); - - client = create_client(f); - - grpc_channel_ping(client, f->cq, tag(0), nullptr); - CQ_EXPECT_COMPLETION(cqv, tag(0), 0); - - /* check that we're still in idle, and start connecting */ - GPR_ASSERT(grpc_channel_check_connectivity_state(client, 1) == - GRPC_CHANNEL_IDLE); - /* we'll go through some set of transitions (some might be missed), until - READY is reached */ - while (state != GRPC_CHANNEL_READY) { - grpc_channel_watch_connectivity_state( - client, state, grpc_timeout_seconds_to_deadline(3), f->cq, tag(99)); - CQ_EXPECT_COMPLETION(cqv, tag(99), 1); - cq_verify(cqv); - state = grpc_channel_check_connectivity_state(client, 0); - GPR_ASSERT(state == GRPC_CHANNEL_READY || - state == GRPC_CHANNEL_CONNECTING || - state == GRPC_CHANNEL_TRANSIENT_FAILURE); - } - - for (i = 1; i <= 5; i++) { - grpc_channel_ping(client, f->cq, tag(i), nullptr); - CQ_EXPECT_COMPLETION(cqv, tag(i), 1); - cq_verify(cqv); - } - gpr_free(rdata.call_details); - - grpc_channel_destroy(client); - teardown_servers(f); - - cq_verifier_destroy(cqv); -} - -static void test_pending_calls(size_t concurrent_calls) { - size_t i; - grpc_call** calls; - grpc_channel* client; - request_data rdata; - servers_fixture* f; - test_spec* spec = test_spec_create(0, 4); - rdata.call_details = static_cast<grpc_call_details*>( - gpr_malloc(sizeof(grpc_call_details) * spec->num_servers)); - f = setup_servers("127.0.0.1", &rdata, spec->num_servers); - - client = create_client(f); - calls = perform_multirequest(f, client, concurrent_calls); - grpc_call_cancel(calls[0], nullptr); /* exercise the cancel pick path whilst - there are pending picks */ - - gpr_free(rdata.call_details); - - grpc_channel_destroy(client); /* calls the LB's shutdown func */ - /* destroy the calls after the channel so that they are still around for the - * LB's shutdown func to process */ - for (i = 0; i < concurrent_calls; i++) { - grpc_call_unref(calls[i]); - } - gpr_free(calls); - teardown_servers(f); - test_spec_destroy(spec); -} - -static void test_get_channel_info() { - grpc_channel* channel = - grpc_insecure_channel_create("ipv4:127.0.0.1:1234", nullptr, nullptr); - // Ensures that resolver returns. - grpc_channel_check_connectivity_state(channel, true /* try_to_connect */); - // First, request no fields. This is a no-op. - grpc_channel_info channel_info; - memset(&channel_info, 0, sizeof(channel_info)); - grpc_channel_get_info(channel, &channel_info); - // Request LB policy name. - char* lb_policy_name = nullptr; - channel_info.lb_policy_name = &lb_policy_name; - grpc_channel_get_info(channel, &channel_info); - GPR_ASSERT(lb_policy_name != nullptr); - GPR_ASSERT(strcmp(lb_policy_name, "pick_first") == 0); - gpr_free(lb_policy_name); - // Request service config, which does not exist, so we'll get nothing back. - memset(&channel_info, 0, sizeof(channel_info)); - char* service_config_json = const_cast<char*>("dummy_string"); - channel_info.service_config_json = &service_config_json; - grpc_channel_get_info(channel, &channel_info); - GPR_ASSERT(service_config_json == nullptr); - // Recreate the channel such that it has a service config. - grpc_channel_destroy(channel); - grpc_arg arg; - arg.type = GRPC_ARG_STRING; - arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG); - arg.value.string = - const_cast<char*>("{\"loadBalancingPolicy\": \"ROUND_ROBIN\"}"); - grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); - channel = grpc_insecure_channel_create("ipv4:127.0.0.1:1234", args, nullptr); - { - grpc_core::ExecCtx exec_ctx; - grpc_channel_args_destroy(args); - } - // Ensures that resolver returns. - grpc_channel_check_connectivity_state(channel, true /* try_to_connect */); - // Now request the service config again. - grpc_channel_get_info(channel, &channel_info); - GPR_ASSERT(service_config_json != nullptr); - GPR_ASSERT(strcmp(service_config_json, arg.value.string) == 0); - gpr_free(service_config_json); - // Clean up. - grpc_channel_destroy(channel); -} - -static void print_failed_expectations(const int* expected_connection_sequence, - const int* actual_connection_sequence, - const size_t expected_seq_length, - const size_t num_iters) { - size_t i; - for (i = 0; i < num_iters; i++) { - gpr_log(GPR_ERROR, - "FAILURE: Iter (expected, actual): %" PRIuPTR " (%d, %d)", i, - expected_connection_sequence[i % expected_seq_length], - actual_connection_sequence[i]); - } -} - -static void verify_vanilla_round_robin(const servers_fixture* f, - grpc_channel* client, - const request_sequences* sequences, - const size_t num_iters) { - const size_t expected_seq_length = f->num_servers; - - /* verify conn. seq. expectation */ - /* get the first sequence of "num_servers" elements */ - int* expected_connection_sequence = - static_cast<int*>(gpr_malloc(sizeof(int) * expected_seq_length)); - memcpy(expected_connection_sequence, sequences->connections, - sizeof(int) * expected_seq_length); - - for (size_t i = 0; i < num_iters; i++) { - const int actual = sequences->connections[i]; - const int expected = expected_connection_sequence[i % expected_seq_length]; - if (actual != expected) { - gpr_log( - GPR_ERROR, - "CONNECTION SEQUENCE FAILURE: expected %d, got %d at iteration #%d", - expected, actual, (int)i); - abort(); - } - } - - /* All servers are available, therefore all client subchannels are READY, even - * when we only need one for the client channel state to be READY */ - for (size_t i = 0; i < sequences->n; i++) { - const grpc_connectivity_state actual = - static_cast<grpc_connectivity_state>(sequences->connectivity_states[i]); - const grpc_connectivity_state expected = GRPC_CHANNEL_READY; - if (actual != expected) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " - "at iteration #%d", - grpc_connectivity_state_name(expected), - grpc_connectivity_state_name(actual), (int)i); - abort(); - } - } - - gpr_free(expected_connection_sequence); -} - -/* At the start of the second iteration, all but the first and last servers (as - * given in "f") are killed */ -static void verify_vanishing_floor_round_robin( - const servers_fixture* f, grpc_channel* client, - const request_sequences* sequences, const size_t num_iters) { - int* expected_connection_sequence; - const size_t expected_seq_length = 2; - size_t i; - - /* verify conn. seq. expectation */ - /* copy the first full sequence (without -1s) */ - expected_connection_sequence = - static_cast<int*>(gpr_malloc(sizeof(int) * expected_seq_length)); - memcpy(expected_connection_sequence, sequences->connections + 2, - expected_seq_length * sizeof(int)); - - /* first two elements of the sequence should be [0 (1st server), -1 (failure)] - */ - GPR_ASSERT(sequences->connections[0] == 0); - GPR_ASSERT(sequences->connections[1] == -1); - - /* the next two element must be [3, 0], repeating from that point: the 3 is - * brought forth by servers 1 and 2 disappearing after the intial pick of 0 */ - GPR_ASSERT(sequences->connections[2] == 3); - GPR_ASSERT(sequences->connections[3] == 0); - - /* make sure that the expectation obliges */ - for (i = 2; i < num_iters; i++) { - const int actual = sequences->connections[i]; - const int expected = expected_connection_sequence[i % expected_seq_length]; - if (actual != expected) { - print_failed_expectations(expected_connection_sequence, - sequences->connections, expected_seq_length, - num_iters); - abort(); - } - } - - /* There's always at least one subchannel READY (connected), therefore the - * overall state of the client channel is READY at all times. */ - for (i = 0; i < sequences->n; i++) { - const grpc_connectivity_state actual = - static_cast<grpc_connectivity_state>(sequences->connectivity_states[i]); - const grpc_connectivity_state expected = GRPC_CHANNEL_READY; - if (actual != expected) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " - "at iteration #%d", - grpc_connectivity_state_name(expected), - grpc_connectivity_state_name(actual), (int)i); - abort(); - } - } - - gpr_free(expected_connection_sequence); -} - -static void verify_total_carnage_round_robin(const servers_fixture* f, - grpc_channel* client, - const request_sequences* sequences, - const size_t num_iters) { - for (size_t i = 0; i < num_iters; i++) { - const int actual = sequences->connections[i]; - const int expected = -1; - if (actual != expected) { - gpr_log( - GPR_ERROR, - "CONNECTION SEQUENCE FAILURE: expected %d, got %d at iteration #%d", - expected, actual, (int)i); - abort(); - } - } - - /* No server is ever available. There should be no READY states (or SHUTDOWN). - * Note that all other states (IDLE, CONNECTING, TRANSIENT_FAILURE) are still - * possible, as the policy transitions while attempting to reconnect. */ - for (size_t i = 0; i < sequences->n; i++) { - const grpc_connectivity_state actual = - static_cast<grpc_connectivity_state>(sequences->connectivity_states[i]); - if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state " - "'%s' at iteration #%d.", - grpc_connectivity_state_name(actual), (int)i); - abort(); - } - } -} - -static void verify_partial_carnage_round_robin( - const servers_fixture* f, grpc_channel* client, - const request_sequences* sequences, const size_t num_iters) { - int* expected_connection_sequence; - size_t i; - const size_t expected_seq_length = f->num_servers; - - /* verify conn. seq. expectation */ - /* get the first sequence of "num_servers" elements */ - expected_connection_sequence = - static_cast<int*>(gpr_malloc(sizeof(int) * expected_seq_length)); - memcpy(expected_connection_sequence, sequences->connections, - sizeof(int) * expected_seq_length); - - for (i = 0; i < num_iters / 2; i++) { - const int actual = sequences->connections[i]; - const int expected = expected_connection_sequence[i % expected_seq_length]; - if (actual != expected) { - print_failed_expectations(expected_connection_sequence, - sequences->connections, expected_seq_length, - num_iters); - abort(); - } - } - - /* second half of the iterations go without response */ - for (; i < num_iters; i++) { - GPR_ASSERT(sequences->connections[i] == -1); - } - - /* We can assert that the first client channel state should be READY, when all - * servers were available */ - grpc_connectivity_state actual = - static_cast<grpc_connectivity_state>(sequences->connectivity_states[0]); - grpc_connectivity_state expected = GRPC_CHANNEL_READY; - if (actual != expected) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " - "at iteration #%d", - grpc_connectivity_state_name(expected), - grpc_connectivity_state_name(actual), 0); - abort(); - } - - /* ... and that the last one shouldn't be READY (or SHUTDOWN): all servers are - * gone. It may be all other states (IDLE, CONNECTING, TRANSIENT_FAILURE), as - * the policy transitions while attempting to reconnect. */ - actual = static_cast<grpc_connectivity_state>( - sequences->connectivity_states[num_iters - 1]); - for (i = 0; i < sequences->n; i++) { - if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state " - "'%s' at iteration #%d.", - grpc_connectivity_state_name(actual), (int)i); - abort(); - } - } - gpr_free(expected_connection_sequence); -} - -static void dump_array(const char* desc, const int* data, const size_t count) { - gpr_strvec s; - char* tmp; - size_t i; - gpr_strvec_init(&s); - gpr_strvec_add(&s, gpr_strdup(desc)); - gpr_strvec_add(&s, gpr_strdup(":")); - for (i = 0; i < count; i++) { - gpr_asprintf(&tmp, " %d", data[i]); - gpr_strvec_add(&s, tmp); - } - tmp = gpr_strvec_flatten(&s, nullptr); - gpr_strvec_destroy(&s); - gpr_log(GPR_DEBUG, "%s", tmp); - gpr_free(tmp); -} - -static void verify_rebirth_round_robin(const servers_fixture* f, - grpc_channel* client, - const request_sequences* sequences, - const size_t num_iters) { - dump_array("actual_connection_sequence", sequences->connections, num_iters); - - /* first iteration succeeds */ - GPR_ASSERT(sequences->connections[0] != -1); - /* then we fail for a while... */ - GPR_ASSERT(sequences->connections[1] == -1); - /* ... but should be up eventually */ - size_t first_iter_back_up = ~0ul; - for (size_t i = 2; i < sequences->n; ++i) { - if (sequences->connections[i] != -1) { - first_iter_back_up = i; - break; - } - } - GPR_ASSERT(first_iter_back_up != ~0ul); - - /* We can assert that the first client channel state should be READY, when all - * servers were available; same thing for the last one. In the middle - * somewhere there must exist at least one TRANSIENT_FAILURE */ - grpc_connectivity_state actual = - static_cast<grpc_connectivity_state>(sequences->connectivity_states[0]); - grpc_connectivity_state expected = GRPC_CHANNEL_READY; - if (actual != expected) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " - "at iteration #%d", - grpc_connectivity_state_name(expected), - grpc_connectivity_state_name(actual), 0); - abort(); - } - - actual = static_cast<grpc_connectivity_state>( - sequences->connectivity_states[num_iters - 1]); - expected = GRPC_CHANNEL_READY; - if (actual != expected) { - gpr_log(GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " - "at iteration #%d", - grpc_connectivity_state_name(expected), - grpc_connectivity_state_name(actual), (int)num_iters - 1); - abort(); - } - - bool found_failure_status = false; - for (size_t i = 1; i < sequences->n - 1; i++) { - if (sequences->connectivity_states[i] == GRPC_CHANNEL_TRANSIENT_FAILURE) { - found_failure_status = true; - break; - } - } - if (!found_failure_status) { - gpr_log( - GPR_ERROR, - "CONNECTIVITY STATUS SEQUENCE FAILURE: " - "GRPC_CHANNEL_TRANSIENT_FAILURE status not found. Got the following " - "instead:"); - for (size_t i = 0; i < num_iters; i++) { - gpr_log(GPR_ERROR, "[%d]: %s", (int)i, - grpc_connectivity_state_name(static_cast<grpc_connectivity_state>( - sequences->connectivity_states[i]))); - } - } -} - -int main(int argc, char** argv) { - grpc_core::ExecCtx exec_ctx; - test_spec* spec; - size_t i; - const size_t NUM_ITERS = 10; - const size_t NUM_SERVERS = 4; - - grpc_init(); - grpc_test_init(argc, argv); - grpc_tracer_set_enabled("round_robin", 1); - - GPR_ASSERT(grpc_lb_policy_create("this-lb-policy-does-not-exist", nullptr) == - nullptr); - GPR_ASSERT(grpc_lb_policy_create(nullptr, nullptr) == nullptr); - - spec = test_spec_create(NUM_ITERS, NUM_SERVERS); - /* everything is fine, all servers stay up the whole time and life's peachy - */ - spec->verifier = verify_vanilla_round_robin; - spec->description = "test_all_server_up"; - run_spec(spec); - - /* Kill all servers first thing in the morning */ - test_spec_reset(spec); - spec->verifier = verify_total_carnage_round_robin; - spec->description = "test_kill_all_server"; - for (i = 0; i < NUM_SERVERS; i++) { - spec->kill_at[0][i] = 1; - } - run_spec(spec); - - /* at the start of the 2nd iteration, kill all but the first and last - * servers. - * This should knock down the server bound to be selected next */ - test_spec_reset(spec); - spec->verifier = verify_vanishing_floor_round_robin; - spec->description = "test_kill_middle_servers_at_2nd_iteration"; - for (i = 1; i < NUM_SERVERS - 1; i++) { - spec->kill_at[1][i] = 1; - } - run_spec(spec); - - /* Midway, kill all servers. */ - test_spec_reset(spec); - spec->verifier = verify_partial_carnage_round_robin; - spec->description = "test_kill_all_server_midway"; - for (i = 0; i < NUM_SERVERS; i++) { - spec->kill_at[spec->num_iters / 2][i] = 1; - } - run_spec(spec); - - /* After first iteration, kill all servers. On the third one, bring them all - * back up. */ - test_spec_reset(spec); - spec->verifier = verify_rebirth_round_robin; - spec->description = "test_kill_all_server_after_1st_resurrect_at_3rd"; - for (i = 0; i < NUM_SERVERS; i++) { - spec->kill_at[1][i] = 1; - spec->revive_at[3][i] = 1; - } - run_spec(spec); - test_spec_destroy(spec); - - test_pending_calls(4); - test_ping(); - test_get_channel_info(); - - grpc_shutdown(); - return 0; -} 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 96009aec4a..cd62c3f4e2 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/fling/client.cc b/test/core/fling/client.cc index 28e62e0e83..c623d376f8 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 259e3aa463..6ad0753f7e 100644 --- a/test/core/http/httpcli_test.cc +++ b/test/core/http/httpcli_test.cc @@ -154,10 +154,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("."); } @@ -167,8 +174,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 adf69f1b16..92193bb442 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/subprocess.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/test_config.h" @@ -152,10 +154,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("."); } @@ -165,10 +174,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 bca4486163..f5da3cb791 100644 --- a/test/core/memory_usage/server.cc +++ b/test/core/memory_usage/server.cc @@ -290,6 +290,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 c13ea31b2d..05ef2862b4 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -96,10 +96,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 |