From ea456fc2bf09e1b80a3add3b898175605da3bf60 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Tue, 7 Jul 2015 15:23:30 -0700 Subject: [PATCH 001/117] Server auth metadata processor. - Right now it is a global function: would be better to have this per (secure) port. - Changed the interface of the auth_context slightly to make it more friendly. - Positive tests pass. Still need some work on error case (have a negative case as well). - Fixing cpp auth context tests so that they use the shiny new C API. --- include/grpc/grpc_security.h | 46 ++- src/core/security/credentials.c | 48 +-- src/core/security/credentials.h | 13 +- src/core/security/security_connector.c | 32 +- src/core/security/security_context.c | 101 ++++-- src/core/security/security_context.h | 34 +- src/core/security/server_auth_filter.c | 166 ++++++++- src/core/transport/stream_op.h | 2 +- .../chttp2_simple_ssl_with_oauth2_fullstack.c | 4 +- ...est_response_with_payload_and_call_creds.c | 322 +++++++++++++++++- test/core/security/auth_context_test.c | 73 ++-- test/core/security/credentials_test.c | 8 +- .../cpp/common/auth_property_iterator_test.cc | 15 +- test/cpp/common/secure_auth_context_test.cc | 22 +- 14 files changed, 715 insertions(+), 171 deletions(-) diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 37d66c04ae5..9e193e697f8 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -203,8 +203,6 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call, /* --- Authentication Context. --- */ -/* TODO(jboeuf): Define some well-known property names. */ - #define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type" #define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" #define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl" @@ -260,6 +258,50 @@ grpc_auth_context *grpc_call_auth_context(grpc_call *call); /* Releases the auth context returned from grpc_call_auth_context. */ void grpc_auth_context_release(grpc_auth_context *context); +/* -- + The following auth context methods should only be called by a server metadata + processor that will augment the channel auth context (see below). + -- */ + +/* Creates a new auth context based off a chained context. */ +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); + +/* Add a property. */ +void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, + const char *value, size_t value_length); + +/* Add a C string property. */ +void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, + const char *name, + const char *value); + +/* Sets the property name. Returns 1 if successful or 0 in case of failure + (which means that no property with this name exists). */ +int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, + const char *name); + +/* --- Auth Metadata Processing --- */ + +/* Opaque data structure useful for processors defined in core. */ +typedef struct grpc_auth_ticket grpc_auth_ticket; + +/* Callback function that is called when the metadata processing is done. + success is 1 if processing succeeded, 0 otherwise. */ +typedef void (*grpc_process_auth_metadata_done_cb)( + void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, + int success, grpc_auth_context *result); + +/* Pluggable metadata processing function */ +typedef void (*grpc_process_auth_metadata_func)( + grpc_auth_ticket *ticket, grpc_auth_context *channel_ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, void *user_data); + +/* Registration function for metadata processing. + Should be called before the server is started. */ +void grpc_server_auth_context_register_process_metadata_func( + grpc_process_auth_metadata_func func); + #ifdef __cplusplus } #endif diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 230f0dfb85f..71513bcc25b 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -759,19 +759,19 @@ grpc_credentials *grpc_refresh_token_credentials_create( grpc_auth_refresh_token_create_from_string(json_refresh_token)); } -/* -- Fake Oauth2 credentials. -- */ +/* -- Metadata-only credentials. -- */ -static void fake_oauth2_destroy(grpc_credentials *creds) { - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); +static void md_only_test_destroy(grpc_credentials *creds) { + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; + grpc_credentials_md_store_unref(c->md_store); gpr_free(c); } -static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) { +static int md_only_test_has_request_metadata(const grpc_credentials *creds) { return 1; } -static int fake_oauth2_has_request_metadata_only( +static int md_only_test_has_request_metadata_only( const grpc_credentials *creds) { return 1; } @@ -779,19 +779,19 @@ static int fake_oauth2_has_request_metadata_only( void on_simulated_token_fetch_done(void *user_data, int success) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds; + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; GPR_ASSERT(success); - r->cb(r->user_data, c->access_token_md->entries, - c->access_token_md->num_entries, GRPC_CREDENTIALS_OK); + r->cb(r->user_data, c->md_store->entries, + c->md_store->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_metadata_request_destroy(r); } -static void fake_oauth2_get_request_metadata(grpc_credentials *creds, +static void md_only_test_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; if (c->is_async) { grpc_credentials_metadata_request *cb_arg = @@ -800,26 +800,26 @@ static void fake_oauth2_get_request_metadata(grpc_credentials *creds, on_simulated_token_fetch_done, cb_arg); grpc_iomgr_add_callback(cb_arg->on_simulated_token_fetch_done_closure); } else { - cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); + cb(user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); } } -static grpc_credentials_vtable fake_oauth2_vtable = { - fake_oauth2_destroy, fake_oauth2_has_request_metadata, - fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata, +static grpc_credentials_vtable md_only_test_vtable = { + md_only_test_destroy, md_only_test_has_request_metadata, + md_only_test_has_request_metadata_only, md_only_test_get_request_metadata, NULL}; -grpc_credentials *grpc_fake_oauth2_credentials_create( - const char *token_md_value, int is_async) { - grpc_fake_oauth2_credentials *c = - gpr_malloc(sizeof(grpc_fake_oauth2_credentials)); - memset(c, 0, sizeof(grpc_fake_oauth2_credentials)); +grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, + const char *md_value, + int is_async) { + grpc_md_only_test_credentials *c = + gpr_malloc(sizeof(grpc_md_only_test_credentials)); + memset(c, 0, sizeof(grpc_md_only_test_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &fake_oauth2_vtable; + c->base.vtable = &md_only_test_vtable; gpr_ref_init(&c->base.refcount, 1); - c->access_token_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + c->md_store = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); c->is_async = is_async; return &c->base; } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index d988901cf74..664524522ba 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -182,9 +182,10 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); void grpc_flush_cached_google_default_credentials(void); -/* Simulates an oauth2 token fetch with the specified value for testing. */ -grpc_credentials *grpc_fake_oauth2_credentials_create( - const char *token_md_value, int is_async); +/* Metadata-only credentials with the specified key and value where + asynchronicity can be simulated for testing. */ +grpc_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async); /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ @@ -288,13 +289,13 @@ typedef struct { grpc_credentials_md_store *access_token_md; } grpc_access_token_credentials; -/* -- Fake Oauth2 credentials. -- */ +/* -- Metadata-only Test credentials. -- */ typedef struct { grpc_credentials base; - grpc_credentials_md_store *access_token_md; + grpc_credentials_md_store *md_store; int is_async; -} grpc_fake_oauth2_credentials; +} grpc_md_only_test_credentials; /* -- IAM credentials. -- */ diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c index f6e423eb279..8aee8f3ef49 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -263,9 +263,9 @@ static grpc_security_status fake_check_peer(grpc_security_connector *sc, goto end; } GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); - sc->auth_context = grpc_auth_context_create(NULL, 1); - sc->auth_context->properties[0] = grpc_auth_property_init_from_cstring( - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + sc->auth_context = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + sc->auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); end: @@ -409,31 +409,35 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { size_t i; grpc_auth_context *ctx = NULL; + const char *peer_identity_property_name = NULL; /* The caller has checked the certificate type property. */ GPR_ASSERT(peer->property_count >= 1); - ctx = grpc_auth_context_create(NULL, peer->property_count); - ctx->properties[0] = grpc_auth_property_init_from_cstring( - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + ctx = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_SSL_TRANSPORT_SECURITY_TYPE); - ctx->property_count = 1; for (i = 0; i < peer->property_count; i++) { const tsi_peer_property *prop = &peer->properties[i]; if (prop->name == NULL) continue; if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { /* If there is no subject alt name, have the CN as the identity. */ - if (ctx->peer_identity_property_name == NULL) { - ctx->peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; + if (peer_identity_property_name == NULL) { + peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; } - ctx->properties[ctx->property_count++] = grpc_auth_property_init( - GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length); + grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, + prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { - ctx->peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; - ctx->properties[ctx->property_count++] = grpc_auth_property_init( - GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length); + peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; + grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, + prop->value.data, prop->value.length); } } + if (peer_identity_property_name != NULL) { + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + ctx, peer_identity_property_name) == 1); + } return ctx; } diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 8ce7876bd8f..0015d5b9150 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -42,6 +42,20 @@ #include #include +/* --- grpc_process_auth_metadata_func --- */ + +static grpc_process_auth_metadata_func server_md_func = NULL; + +void grpc_server_auth_context_register_process_metadata_func( + grpc_process_auth_metadata_func func) { + server_md_func = func; +} + +grpc_process_auth_metadata_func +grpc_server_auth_context_get_process_metadata_func(void) { + return server_md_func; +} + /* --- grpc_call --- */ grpc_call_error grpc_call_set_credentials(grpc_call *call, @@ -120,15 +134,15 @@ void grpc_server_security_context_destroy(void *ctx) { static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained, - size_t property_count) { +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); memset(ctx, 0, sizeof(grpc_auth_context)); - ctx->properties = gpr_malloc(property_count * sizeof(grpc_auth_property)); - memset(ctx->properties, 0, property_count * sizeof(grpc_auth_property)); - ctx->property_count = property_count; gpr_ref_init(&ctx->refcount, 1); - if (chained != NULL) ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); + if (chained != NULL) { + ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); + ctx->peer_identity_property_name = + ctx->chained->peer_identity_property_name; + } return ctx; } @@ -162,11 +176,11 @@ void grpc_auth_context_unref(grpc_auth_context *ctx) { if (gpr_unref(&ctx->refcount)) { size_t i; GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); - if (ctx->properties != NULL) { - for (i = 0; i < ctx->property_count; i++) { - grpc_auth_property_reset(&ctx->properties[i]); + if (ctx->properties.array != NULL) { + for (i = 0; i < ctx->properties.count; i++) { + grpc_auth_property_reset(&ctx->properties.array[i]); } - gpr_free(ctx->properties); + gpr_free(ctx->properties.array); } gpr_free(ctx); } @@ -177,6 +191,20 @@ const char *grpc_auth_context_peer_identity_property_name( return ctx->peer_identity_property_name; } +int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, + const char *name) { + grpc_auth_property_iterator it = + grpc_auth_context_find_properties_by_name(ctx, name); + const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); + if (prop == NULL) { + gpr_log(GPR_ERROR, "Property name %s not found in auth context.", + name != NULL ? name : "NULL"); + return 0; + } + ctx->peer_identity_property_name = prop->name; + return 1; +} + int grpc_auth_context_peer_is_authenticated( const grpc_auth_context *ctx) { return ctx->peer_identity_property_name == NULL ? 0 : 1; @@ -193,16 +221,16 @@ grpc_auth_property_iterator grpc_auth_context_property_iterator( const grpc_auth_property *grpc_auth_property_iterator_next( grpc_auth_property_iterator *it) { if (it == NULL || it->ctx == NULL) return NULL; - while (it->index == it->ctx->property_count) { + while (it->index == it->ctx->properties.count) { if (it->ctx->chained == NULL) return NULL; it->ctx = it->ctx->chained; it->index = 0; } if (it->name == NULL) { - return &it->ctx->properties[it->index++]; + return &it->ctx->properties.array[it->index++]; } else { - while (it->index < it->ctx->property_count) { - const grpc_auth_property *prop = &it->ctx->properties[it->index++]; + while (it->index < it->ctx->properties.count) { + const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; GPR_ASSERT(prop->name != NULL); if (strcmp(it->name, prop->name) == 0) { return prop; @@ -229,24 +257,37 @@ grpc_auth_property_iterator grpc_auth_context_peer_identity( ctx, ctx->peer_identity_property_name); } -grpc_auth_property grpc_auth_property_init_from_cstring(const char *name, - const char *value) { - grpc_auth_property prop; - prop.name = gpr_strdup(name); - prop.value = gpr_strdup(value); - prop.value_length = strlen(value); - return prop; +static void ensure_auth_context_capacity(grpc_auth_context *ctx) { + if (ctx->properties.count == ctx->properties.capacity) { + ctx->properties.capacity = + GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); + ctx->properties.array = + gpr_realloc(ctx->properties.array, + ctx->properties.capacity * sizeof(grpc_auth_property)); + } +} + +void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, + const char *value, size_t value_length) { + grpc_auth_property *prop; + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_malloc(value_length + 1); + memcpy(prop->value, value, value_length); + prop->value[value_length] = '\0'; + prop->value_length = value_length; } -grpc_auth_property grpc_auth_property_init(const char *name, const char *value, - size_t value_length) { - grpc_auth_property prop; - prop.name = gpr_strdup(name); - prop.value = gpr_malloc(value_length + 1); - memcpy(prop.value, value, value_length); - prop.value[value_length] = '\0'; - prop.value_length = value_length; - return prop; +void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, + const char *name, + const char *value) { + grpc_auth_property *prop; + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_strdup(value); + prop->value_length = strlen(value); } void grpc_auth_property_reset(grpc_auth_property *property) { diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 76a45910bbd..b5dfae06662 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -34,11 +34,13 @@ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H #define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H +#include "src/core/iomgr/pollset.h" #include "src/core/security/credentials.h" -#ifdef __cplusplus -extern "C" { -#endif +/* --- grpc_auth_ticket --- */ +struct grpc_auth_ticket { + grpc_pollset *pollset; +}; /* --- grpc_auth_context --- @@ -46,18 +48,19 @@ extern "C" { /* Property names are always NULL terminated. */ +typedef struct { + grpc_auth_property *array; + size_t count; + size_t capacity; +} grpc_auth_property_array; + struct grpc_auth_context { struct grpc_auth_context *chained; - grpc_auth_property *properties; - size_t property_count; + grpc_auth_property_array properties; gpr_refcount refcount; const char *peer_identity_property_name; }; -/* Constructor. */ -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained, - size_t property_count); - /* Refcounting. */ #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG #define GRPC_AUTH_CONTEXT_REF(p, r) \ @@ -76,12 +79,6 @@ grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); void grpc_auth_context_unref(grpc_auth_context *policy); #endif -grpc_auth_property grpc_auth_property_init_from_cstring(const char *name, - const char *value); - -grpc_auth_property grpc_auth_property_init(const char *name, const char *value, - size_t value_length); - void grpc_auth_property_reset(grpc_auth_property *property); /* --- grpc_client_security_context --- @@ -107,9 +104,10 @@ typedef struct { grpc_server_security_context *grpc_server_security_context_create(void); void grpc_server_security_context_destroy(void *ctx); -#ifdef __cplusplus -} -#endif +/* --- Auth metadata processing. --- */ + +grpc_process_auth_metadata_func +grpc_server_auth_context_get_process_metadata_func(void); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 10eef6d2378..fe993e50ee9 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -31,20 +31,161 @@ * */ +#include + #include "src/core/security/auth_filters.h" #include "src/core/security/security_connector.h" #include "src/core/security/security_context.h" +#include #include typedef struct call_data { - int unused; /* C89 requires at least one struct element */ + gpr_uint8 got_client_metadata; + gpr_uint8 sent_status; + gpr_uint8 success; + grpc_linked_mdelem status; + grpc_stream_op_buffer *recv_ops; + /* Closure to call when finished with the hs_on_recv hook. */ + grpc_iomgr_closure *on_done_recv; + /* Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member after + handling it. */ + grpc_iomgr_closure auth_on_recv; + const grpc_metadata *consumed_md; + size_t num_consumed_md; + grpc_stream_op *md_op; + grpc_auth_context **call_auth_context; + grpc_auth_ticket ticket; } call_data; typedef struct channel_data { grpc_security_connector *security_connector; + grpc_mdelem *status_auth_failure; } channel_data; +static grpc_metadata_array metadata_batch_to_md_array( + const grpc_metadata_batch *batch) { + grpc_linked_mdelem *l; + grpc_metadata_array result; + grpc_metadata_array_init(&result); + for (l = batch->list.head; l != NULL; l = l->next) { + grpc_metadata *usr_md = NULL; + grpc_mdelem *md = l->md; + grpc_mdstr *key = md->key; + grpc_mdstr *value = md->value; + if (result.count == result.capacity) { + result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); + result.metadata = + gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); + } + usr_md = &result.metadata[result.count++]; + usr_md->key = grpc_mdstr_as_c_string(key); + usr_md->value = grpc_mdstr_as_c_string(value); + usr_md->value_length = GPR_SLICE_LENGTH(value->slice); + } + return result; +} + +static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + size_t i; + for (i = 0; i < calld->num_consumed_md; i++) { + /* Maybe we could do a pointer comparison but we do not have any guarantee + that the metadata processor used the same pointers for consumed_md in the + callback. */ + if (memcmp(GPR_SLICE_START_PTR(md->key->slice), calld->consumed_md[i].key, + GPR_SLICE_LENGTH(md->key->slice)) == 0 && + memcmp(GPR_SLICE_START_PTR(md->value->slice), + calld->consumed_md[i].value, + GPR_SLICE_LENGTH(md->value->slice)) == 0) { + return NULL; /* Delete. */ + } + } + return md; +} + +static void on_md_processing_done(void *user_data, + const grpc_metadata *consumed_md, + size_t num_consumed_md, int success, + grpc_auth_context *result) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + + calld->success = success; + if (success) { + calld->consumed_md = consumed_md; + calld->num_consumed_md = num_consumed_md; + grpc_metadata_batch_filter(&calld->md_op->data.metadata, remove_consumed_md, + elem); + GPR_ASSERT(calld->call_auth_context != NULL); + GRPC_AUTH_CONTEXT_UNREF(*calld->call_auth_context, + "releasing old context."); + *calld->call_auth_context = + GRPC_AUTH_CONTEXT_REF(result, "refing new context."); + } else { + grpc_call_element_send_cancel(elem); + } + + calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); +} + +static void auth_on_recv(void *user_data, int success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (success) { + size_t i; + size_t nops = calld->recv_ops->nops; + grpc_stream_op *ops = calld->recv_ops->ops; + for (i = 0; i < nops; i++) { + grpc_metadata_array md_array; + grpc_process_auth_metadata_func processor = + grpc_server_auth_context_get_process_metadata_func(); + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->got_client_metadata = 1; + if (processor == NULL) continue; + calld->md_op = op; + md_array = metadata_batch_to_md_array(&op->data.metadata); + processor(&calld->ticket, chand->security_connector->auth_context, + md_array.metadata, md_array.count, on_md_processing_done, elem); + grpc_metadata_array_destroy(&md_array); + return; + } + } + calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); +} + +static void set_recv_ops_md_callbacks(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + + if (op->send_ops && !calld->sent_status && !calld->success) { + size_t i; + size_t nops = op->send_ops->nops; + grpc_stream_op *ops = op->send_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->sent_status = 1; + grpc_metadata_batch_add_head( + &op->data.metadata, &calld->status, + GRPC_MDELEM_REF(chand->status_auth_failure)); + break; + } + } + + if (op->recv_ops && !calld->got_client_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_ops = op->recv_ops; + calld->on_done_recv = op->on_done_recv; + op->on_done_recv = &calld->auth_on_recv; + } +} + /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something @@ -52,9 +193,7 @@ typedef struct channel_data { that is being sent or received. */ static void auth_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { - /* TODO(jboeuf): Get the metadata and get a new context from it. */ - - /* pass control down the stack */ + set_recv_ops_md_callbacks(elem, op); grpc_call_next_op(elem, op); } @@ -68,11 +207,18 @@ static void init_call_elem(grpc_call_element *elem, grpc_server_security_context *server_ctx = NULL; /* initialize members */ - calld->unused = 0; + memset(calld, 0, sizeof(*calld)); + grpc_iomgr_closure_init(&calld->auth_on_recv, auth_on_recv, elem); + calld->success = 1; GPR_ASSERT(initial_op && initial_op->context != NULL && initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); + /* Get the pollset for the ticket. */ + if (initial_op->bind_pollset) { + calld->ticket.pollset = initial_op->bind_pollset; + } + /* Create a security context for the call and reference the auth context from the channel. */ if (initial_op->context[GRPC_CONTEXT_SECURITY].value != NULL) { @@ -85,10 +231,15 @@ static void init_call_elem(grpc_call_element *elem, initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx; initial_op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_server_security_context_destroy; + calld->call_auth_context = &server_ctx->auth_context; + + /* Set the metadata callbacks. */ + set_recv_ops_md_callbacks(elem, initial_op); } /* Destructor for call_data */ -static void destroy_call_elem(grpc_call_element *elem) {} +static void destroy_call_elem(grpc_call_element *elem) { +} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, @@ -109,6 +260,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GPR_ASSERT(!sc->is_client_side); chand->security_connector = GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter"); + chand->status_auth_failure = + grpc_mdelem_from_strings(mdctx, ":status", "401"); } /* Destructor for channel data */ @@ -117,6 +270,7 @@ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *chand = elem->channel_data; GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector, "server_auth_filter"); + GRPC_MDELEM_UNREF(chand->status_auth_failure); } const grpc_channel_filter grpc_server_auth_filter = { diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index 964d39d14fc..7d3024da101 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -103,7 +103,7 @@ void grpc_metadata_batch_merge(grpc_metadata_batch *target, grpc_metadata_batch *add); /** Add \a storage to the beginning of \a batch. storage->md is - assumed to be valid. + assumed to be valid. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. */ diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c index de418bf7ee0..da658a0b45a 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c @@ -100,8 +100,8 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { grpc_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL); - grpc_credentials *oauth2_creds = - grpc_fake_oauth2_credentials_create("Bearer aaslkfjs424535asdf", 1); + grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( + "Authorization", "Bearer aaslkfjs424535asdf", 1); grpc_credentials *ssl_oauth2_creds = grpc_composite_credentials_create(ssl_creds, oauth2_creds); grpc_arg ssl_name_override = {GRPC_ARG_STRING, diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index b5c743b4056..c0214081c5d 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -46,6 +46,11 @@ #include "src/core/security/credentials.h" #include "src/core/support/string.h" +static const char *custom_creds_md_name = "custom_creds"; +static const char *custom_creds_md_value = "custom_value"; +static const char *client_identity_property_name = "smurf_name"; +static const char *client_identity = "Brainy Smurf"; + static const char iam_token[] = "token"; static const char iam_selector[] = "selector"; static const char overridden_iam_token[] = "overridden_token"; @@ -57,15 +62,71 @@ enum { TIMEOUT = 200000 }; static void *tag(gpr_intptr t) { return (void *)t; } -static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, - const char *test_name, - grpc_channel_args *client_args, - grpc_channel_args *server_args) { +static const grpc_metadata *find_metadata(const grpc_metadata *md, + size_t md_count, + const char *key, + const char *value) { + size_t i; + for (i = 0; i < md_count; i++) { + if (strcmp(key, md[i].key) == 0 && strlen(value) == md[i].value_length && + memcmp(md[i].value, value, md[i].value_length) == 0) { + return &md[i]; + } + } + return NULL; +} + +static void check_peer_identity(grpc_auth_context *ctx, + const char *expected_identity) { + grpc_auth_property_iterator it = grpc_auth_context_peer_identity(ctx); + const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); + GPR_ASSERT(prop != NULL); + GPR_ASSERT(strcmp(expected_identity, prop->value) == 0); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); +} +static void process_auth_md_success(grpc_auth_ticket *t, + grpc_auth_context *channel_ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + grpc_auth_context *new_auth_ctx = grpc_auth_context_create(channel_ctx); + const grpc_metadata *custom_creds_md = + find_metadata(md, md_count, custom_creds_md_name, custom_creds_md_value); + GPR_ASSERT(custom_creds_md != NULL); + grpc_auth_context_add_cstring_property( + new_auth_ctx, client_identity_property_name, client_identity); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + new_auth_ctx, client_identity_property_name) == 1); + cb(user_data, custom_creds_md, 1, 1, new_auth_ctx); + grpc_auth_context_release(new_auth_ctx); +} + +#if 0 +static void process_auth_md_failure(grpc_auth_ticket *t, + grpc_auth_context *channel_ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + const grpc_metadata *custom_creds_md = + find_metadata(md, md_count, custom_creds_md_name, custom_creds_md_value); + GPR_ASSERT(custom_creds_md != NULL); + cb(user_data, NULL, 0, 0, NULL); /* Fail. */ +} +#endif + +static grpc_end2end_test_fixture begin_test( + grpc_end2end_test_config config, const char *test_name, + grpc_process_auth_metadata_func md_func, override_mode mode) { grpc_end2end_test_fixture f; + if (mode != DESTROY) { + grpc_server_auth_context_register_process_metadata_func(md_func); + } else { + grpc_server_auth_context_register_process_metadata_func(NULL); + } gpr_log(GPR_INFO, "%s/%s", test_name, config.name); - f = config.create_fixture(client_args, server_args); - config.init_client(&f, client_args); - config.init_server(&f, server_args); + f = config.create_fixture(NULL, NULL); + config.init_client(&f, NULL); + config.init_server(&f, NULL); return f; } @@ -124,11 +185,23 @@ static void print_auth_context(int is_client, const grpc_auth_context *ctx) { } } +static grpc_credentials *iam_custom_composite_creds_create( + const char *iam_tok, const char *iam_sel) { + grpc_credentials *iam_creds = grpc_iam_credentials_create(iam_tok, iam_sel); + grpc_credentials *custom_creds = grpc_md_only_test_credentials_create( + custom_creds_md_name, custom_creds_md_value, 1); + grpc_credentials *result = + grpc_composite_credentials_create(iam_creds, custom_creds); + grpc_credentials_release(iam_creds); + grpc_credentials_release(custom_creds); + return result; +} + static void test_call_creds_failure(grpc_end2end_test_config config) { grpc_call *c; grpc_credentials *creds = NULL; grpc_end2end_test_fixture f = - begin_test(config, "test_call_creds_failure", NULL, NULL); + begin_test(config, "test_call_creds_failure", NULL, NONE); gpr_timespec deadline = five_seconds_time(); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); @@ -158,7 +231,8 @@ static void request_response_with_payload_and_call_creds( grpc_raw_byte_buffer_create(&response_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); - grpc_end2end_test_fixture f = begin_test(config, test_name, NULL, NULL); + grpc_end2end_test_fixture f = + begin_test(config, test_name, process_auth_md_success, mode); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_op ops[6]; grpc_op *op; @@ -174,11 +248,12 @@ static void request_response_with_payload_and_call_creds( int was_cancelled = 2; grpc_credentials *creds = NULL; grpc_auth_context *s_auth_context = NULL; + grpc_auth_context *c_auth_context = NULL; c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); - creds = grpc_iam_credentials_create(iam_token, iam_selector); + creds = iam_custom_composite_creds_create(iam_token, iam_selector); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); switch (mode) { @@ -186,8 +261,8 @@ static void request_response_with_payload_and_call_creds( break; case OVERRIDE: grpc_credentials_release(creds); - creds = grpc_iam_credentials_create(overridden_iam_token, - overridden_iam_selector); + creds = iam_custom_composite_creds_create(overridden_iam_token, + overridden_iam_selector); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); break; @@ -241,6 +316,11 @@ static void request_response_with_payload_and_call_creds( print_auth_context(0, s_auth_context); grpc_auth_context_release(s_auth_context); + c_auth_context = grpc_call_auth_context(c); + GPR_ASSERT(c_auth_context != NULL); + print_auth_context(1, c_auth_context); + grpc_auth_context_release(c_auth_context); + /* Cannot set creds on the server call object. */ GPR_ASSERT(grpc_call_set_credentials(s, NULL) != GRPC_CALL_OK); @@ -287,6 +367,10 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world")); GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you")); + /* Has been processed by the auth metadata processor. */ + GPR_ASSERT(!contains_metadata(&request_metadata_recv, custom_creds_md_name, + custom_creds_md_value)); + switch (mode) { case NONE: GPR_ASSERT(contains_metadata(&request_metadata_recv, @@ -295,6 +379,7 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(contains_metadata(&request_metadata_recv, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, iam_selector)); + check_peer_identity(s_auth_context, client_identity); break; case OVERRIDE: GPR_ASSERT(contains_metadata(&request_metadata_recv, @@ -303,6 +388,7 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(contains_metadata(&request_metadata_recv, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, overridden_iam_selector)); + check_peer_identity(s_auth_context, client_identity); break; case DESTROY: GPR_ASSERT(!contains_metadata(&request_metadata_recv, @@ -340,31 +426,237 @@ static void request_response_with_payload_and_call_creds( config.tear_down_data(&f); } -void test_request_response_with_payload_and_call_creds( +static void test_request_response_with_payload_and_call_creds( grpc_end2end_test_config config) { request_response_with_payload_and_call_creds( "test_request_response_with_payload_and_call_creds", config, NONE); } -void test_request_response_with_payload_and_overridden_call_creds( +static void test_request_response_with_payload_and_overridden_call_creds( grpc_end2end_test_config config) { request_response_with_payload_and_call_creds( "test_request_response_with_payload_and_overridden_call_creds", config, OVERRIDE); } -void test_request_response_with_payload_and_deleted_call_creds( +static void test_request_response_with_payload_and_deleted_call_creds( grpc_end2end_test_config config) { request_response_with_payload_and_call_creds( "test_request_response_with_payload_and_deleted_call_creds", config, DESTROY); } +static void test_request_with_bad_creds(void) { +#if 0 + grpc_call *c; + grpc_call *s; + gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); + grpc_byte_buffer *request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + gpr_timespec deadline = five_seconds_time(); + + grpc_end2end_test_fixture f = + begin_test(config, test_name, process_auth_md_failure, NONE); + cq_verifier *cqv = cq_verifier_create(f.cq); + grpc_op ops[6]; + grpc_op *op; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_byte_buffer *request_payload_recv = NULL; + grpc_byte_buffer *response_payload_recv = NULL; + grpc_call_details call_details; + grpc_status_code status; + char *details = NULL; + size_t details_capacity = 0; + int was_cancelled = 2; + grpc_credentials *creds = NULL; + grpc_auth_context *s_auth_context = NULL; + grpc_auth_context *c_auth_context = NULL; + + c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", + deadline); + GPR_ASSERT(c); + creds = iam_custom_composite_creds_create(iam_token, iam_selector); + GPR_ASSERT(creds != NULL); + GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); + switch (mode) { + case NONE: + break; + case OVERRIDE: + grpc_credentials_release(creds); + creds = iam_custom_composite_creds_create(overridden_iam_token, + overridden_iam_selector); + GPR_ASSERT(creds != NULL); + GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); + break; + case DESTROY: + GPR_ASSERT(grpc_call_set_credentials(c, NULL) == GRPC_CALL_OK); + break; + } + grpc_credentials_release(creds); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message = request_payload; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message = &response_payload_recv; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->flags = 0; + op++; + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1))); + + GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( + f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101))); + cq_expect_completion(cqv, tag(101), 1); + cq_verify(cqv); + s_auth_context = grpc_call_auth_context(s); + GPR_ASSERT(s_auth_context != NULL); + print_auth_context(0, s_auth_context); + grpc_auth_context_release(s_auth_context); + + c_auth_context = grpc_call_auth_context(c); + GPR_ASSERT(c_auth_context != NULL); + print_auth_context(1, c_auth_context); + grpc_auth_context_release(c_auth_context); + + /* Cannot set creds on the server call object. */ + GPR_ASSERT(grpc_call_set_credentials(s, NULL) != GRPC_CALL_OK); + + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message = &request_payload_recv; + op->flags = 0; + op++; + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102))); + + cq_expect_completion(cqv, tag(102), 1); + cq_verify(cqv); + + op = ops; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message = response_payload; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = GRPC_STATUS_OK; + op->data.send_status_from_server.status_details = "xyz"; + op->flags = 0; + op++; + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103))); + + cq_expect_completion(cqv, tag(103), 1); + cq_expect_completion(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(status == GRPC_STATUS_OK); + GPR_ASSERT(0 == strcmp(details, "xyz")); + GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); + GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr")); + GPR_ASSERT(was_cancelled == 0); + GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world")); + GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you")); + + /* Has been processed by the auth metadata processor. */ + GPR_ASSERT(!contains_metadata(&request_metadata_recv, custom_creds_md_name, + custom_creds_md_value)); + + switch (mode) { + case NONE: + GPR_ASSERT(contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, + iam_token)); + GPR_ASSERT(contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, + iam_selector)); + check_peer_identity(s_auth_context, client_identity); + break; + case OVERRIDE: + GPR_ASSERT(contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, + overridden_iam_token)); + GPR_ASSERT(contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, + overridden_iam_selector)); + check_peer_identity(s_auth_context, client_identity); + break; + case DESTROY: + GPR_ASSERT(!contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, + iam_token)); + GPR_ASSERT(!contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, + iam_selector)); + GPR_ASSERT(!contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, + overridden_iam_token)); + GPR_ASSERT(!contains_metadata(&request_metadata_recv, + GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, + overridden_iam_selector)); + break; + } + + gpr_free(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_destroy(c); + grpc_call_destroy(s); + + cq_verifier_destroy(cqv); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(request_payload_recv); + grpc_byte_buffer_destroy(response_payload_recv); + + end_test(&f); + config.tear_down_data(&f); +#endif +} + void grpc_end2end_tests(grpc_end2end_test_config config) { if (config.feature_mask & FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS) { test_call_creds_failure(config); test_request_response_with_payload_and_call_creds(config); test_request_response_with_payload_and_overridden_call_creds(config); test_request_response_with_payload_and_deleted_call_creds(config); + test_request_with_bad_creds(); } } diff --git a/test/core/security/auth_context_test.c b/test/core/security/auth_context_test.c index a30505a63ba..d785eb6064d 100644 --- a/test/core/security/auth_context_test.c +++ b/test/core/security/auth_context_test.c @@ -40,7 +40,7 @@ #include static void test_empty_context(void) { - grpc_auth_context *ctx = grpc_auth_context_create(NULL, 0); + grpc_auth_context *ctx = grpc_auth_context_create(NULL); grpc_auth_property_iterator it; gpr_log(GPR_INFO, "test_empty_context"); @@ -52,87 +52,98 @@ static void test_empty_context(void) { GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); it = grpc_auth_context_find_properties_by_name(ctx, "foo"); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "bar") == + 0); + GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx) == NULL); GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); } static void test_simple_context(void) { - grpc_auth_context *ctx = grpc_auth_context_create(NULL, 3); + grpc_auth_context *ctx = grpc_auth_context_create(NULL); grpc_auth_property_iterator it; size_t i; gpr_log(GPR_INFO, "test_simple_context"); GPR_ASSERT(ctx != NULL); - GPR_ASSERT(ctx->property_count == 3); - ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi"); - ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo"); - ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar"); - ctx->peer_identity_property_name = ctx->properties[0].name; + grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); + GPR_ASSERT(ctx->properties.count == 3); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "name") == + 1); GPR_ASSERT( strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0); it = grpc_auth_context_property_iterator(ctx); - for (i = 0; i < ctx->property_count; i++) { + for (i = 0; i < ctx->properties.count; i++) { const grpc_auth_property *p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &ctx->properties[i]); + GPR_ASSERT(p == &ctx->properties.array[i]); } GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); it = grpc_auth_context_find_properties_by_name(ctx, "foo"); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[2]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[2]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); it = grpc_auth_context_peer_identity(ctx); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[0]); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[1]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[0]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[1]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); } static void test_chained_context(void) { - grpc_auth_context *chained = grpc_auth_context_create(NULL, 2); - grpc_auth_context *ctx = grpc_auth_context_create(chained, 3); + grpc_auth_context *chained = grpc_auth_context_create(NULL); + grpc_auth_context *ctx = grpc_auth_context_create(chained); grpc_auth_property_iterator it; size_t i; gpr_log(GPR_INFO, "test_chained_context"); GRPC_AUTH_CONTEXT_UNREF(chained, "chained"); - chained->properties[0] = - grpc_auth_property_init_from_cstring("name", "padapo"); - chained->properties[1] = grpc_auth_property_init_from_cstring("foo", "baz"); - ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi"); - ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo"); - ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar"); - ctx->peer_identity_property_name = ctx->properties[0].name; + grpc_auth_context_add_cstring_property(chained, "name", "padapo"); + grpc_auth_context_add_cstring_property(chained, "foo", "baz"); + grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx, "name", "chap0"); + grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "name") == + 1); GPR_ASSERT( strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0); it = grpc_auth_context_property_iterator(ctx); - for (i = 0; i < ctx->property_count; i++) { + for (i = 0; i < ctx->properties.count; i++) { const grpc_auth_property *p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &ctx->properties[i]); + GPR_ASSERT(p == &ctx->properties.array[i]); } - for (i = 0; i < chained->property_count; i++) { + for (i = 0; i < chained->properties.count; i++) { const grpc_auth_property *p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &chained->properties[i]); + GPR_ASSERT(p == &chained->properties.array[i]); } GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); it = grpc_auth_context_find_properties_by_name(ctx, "foo"); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[2]); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &chained->properties[1]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[2]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &chained->properties.array[1]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); it = grpc_auth_context_peer_identity(ctx); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[0]); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[1]); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &chained->properties[0]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[0]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &ctx->properties.array[1]); + GPR_ASSERT(grpc_auth_property_iterator_next(&it) == + &chained->properties.array[0]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); } - int main(int argc, char **argv) { grpc_test_init(argc, argv); test_empty_context(); diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index d3fea9680a3..96e1e396c64 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -373,8 +373,8 @@ static void test_ssl_oauth2_composite_creds(void) { grpc_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL); const grpc_credentials_array *creds_array; - grpc_credentials *oauth2_creds = - grpc_fake_oauth2_credentials_create(test_oauth2_bearer_token, 0); + grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( + "Authorization", test_oauth2_bearer_token, 0); grpc_credentials *composite_creds = grpc_composite_credentials_create(ssl_creds, oauth2_creds); grpc_credentials_unref(ssl_creds); @@ -424,8 +424,8 @@ static void test_ssl_oauth2_iam_composite_creds(void) { grpc_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL); const grpc_credentials_array *creds_array; - grpc_credentials *oauth2_creds = - grpc_fake_oauth2_credentials_create(test_oauth2_bearer_token, 0); + grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( + "Authorization", test_oauth2_bearer_token, 0); grpc_credentials *aux_creds = grpc_composite_credentials_create(ssl_creds, oauth2_creds); grpc_credentials *iam_creds = grpc_iam_credentials_create( diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc index 3d983fa3109..6443e2fd85c 100644 --- a/test/cpp/common/auth_property_iterator_test.cc +++ b/test/cpp/common/auth_property_iterator_test.cc @@ -31,10 +31,10 @@ * */ +#include #include #include #include "src/cpp/common/secure_auth_context.h" -#include "src/core/security/security_context.h" namespace grpc { namespace { @@ -50,14 +50,15 @@ class TestAuthPropertyIterator : public AuthPropertyIterator { class AuthPropertyIteratorTest : public ::testing::Test { protected: void SetUp() GRPC_OVERRIDE { - ctx_ = grpc_auth_context_create(NULL, 3); - ctx_->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi"); - ctx_->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo"); - ctx_->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar"); - ctx_->peer_identity_property_name = ctx_->properties[0].name; + ctx_ = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property(ctx_, "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx_, "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx_, "foo", "bar"); + EXPECT_EQ(1, + grpc_auth_context_set_peer_identity_property_name(ctx_, "name")); } void TearDown() GRPC_OVERRIDE { - GRPC_AUTH_CONTEXT_UNREF(ctx_, "AuthPropertyIteratorTest"); + grpc_auth_context_release(ctx_); } grpc_auth_context* ctx_; diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index f18a04178ef..b2eeb3fa72f 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -31,10 +31,10 @@ * */ +#include #include #include #include "src/cpp/common/secure_auth_context.h" -#include "src/core/security/security_context.h" namespace grpc { namespace { @@ -52,11 +52,11 @@ TEST_F(SecureAuthContextTest, EmptyContext) { } TEST_F(SecureAuthContextTest, Properties) { - grpc_auth_context* ctx = grpc_auth_context_create(NULL, 3); - ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi"); - ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo"); - ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar"); - ctx->peer_identity_property_name = ctx->properties[0].name; + grpc_auth_context* ctx = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); + EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); SecureAuthContext context(ctx); std::vector peer_identity = context.GetPeerIdentity(); @@ -70,11 +70,11 @@ TEST_F(SecureAuthContextTest, Properties) { } TEST_F(SecureAuthContextTest, Iterators) { - grpc_auth_context* ctx = grpc_auth_context_create(NULL, 3); - ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi"); - ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo"); - ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar"); - ctx->peer_identity_property_name = ctx->properties[0].name; + grpc_auth_context* ctx = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); + EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); SecureAuthContext context(ctx); AuthPropertyIterator iter = context.begin(); From a87d6c2af6a8bbad50d9ad639873357fd824b791 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Fri, 17 Jul 2015 15:51:46 -0700 Subject: [PATCH 002/117] Cannot figure out server filter logic for error in auth md processing. - Positive tests pass even if we will have to change the interface to add the processor to the server credentials (will be done in a separate pull request). - ASAN leaks for the error case. - The client should get a GRPC_STATUS_UNAUTHENTICATED as opposed to GPRC_STATUS_INTERNAL. --- include/grpc/grpc_security.h | 25 +- src/core/security/security_context.c | 13 +- src/core/security/security_context.h | 3 +- src/core/security/server_auth_filter.c | 55 ++-- ...est_response_with_payload_and_call_creds.c | 248 ++++++------------ 5 files changed, 118 insertions(+), 226 deletions(-) diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 9e193e697f8..ead708b2840 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -291,16 +291,23 @@ typedef void (*grpc_process_auth_metadata_done_cb)( void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, int success, grpc_auth_context *result); -/* Pluggable metadata processing function */ -typedef void (*grpc_process_auth_metadata_func)( - grpc_auth_ticket *ticket, grpc_auth_context *channel_ctx, - const grpc_metadata *md, size_t md_count, - grpc_process_auth_metadata_done_cb cb, void *user_data); - -/* Registration function for metadata processing. +/* Pluggable server-side metadata processor object */ +typedef struct { + void (*process)(void *state, grpc_auth_ticket *ticket, + grpc_auth_context *channel_ctx, const grpc_metadata *md, + size_t md_count, grpc_process_auth_metadata_done_cb cb, + void *user_data); + void *state; +} grpc_auth_metadata_processor; + +/* XXXX: this is a temporarty interface. Please do NOT use. + This function will be moved to the server_credentials in a subsequent + pull request. XXXX + + Registration function for metadata processing. Should be called before the server is started. */ -void grpc_server_auth_context_register_process_metadata_func( - grpc_process_auth_metadata_func func); +void grpc_server_register_auth_metadata_processor( + grpc_auth_metadata_processor processor); #ifdef __cplusplus } diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 0015d5b9150..8ccce89ba94 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -44,16 +44,15 @@ /* --- grpc_process_auth_metadata_func --- */ -static grpc_process_auth_metadata_func server_md_func = NULL; +static grpc_auth_metadata_processor server_processor = {NULL, NULL}; -void grpc_server_auth_context_register_process_metadata_func( - grpc_process_auth_metadata_func func) { - server_md_func = func; +grpc_auth_metadata_processor grpc_server_get_auth_metadata_processor(void) { + return server_processor; } -grpc_process_auth_metadata_func -grpc_server_auth_context_get_process_metadata_func(void) { - return server_md_func; +void grpc_server_register_auth_metadata_processor( + grpc_auth_metadata_processor processor) { + server_processor = processor; } /* --- grpc_call --- */ diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index b5dfae06662..d4351cb74c5 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -106,8 +106,7 @@ void grpc_server_security_context_destroy(void *ctx); /* --- Auth metadata processing. --- */ -grpc_process_auth_metadata_func -grpc_server_auth_context_get_process_metadata_func(void); +grpc_auth_metadata_processor grpc_server_get_auth_metadata_processor(void); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index fe993e50ee9..918cb401ebd 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -42,16 +42,14 @@ typedef struct call_data { gpr_uint8 got_client_metadata; - gpr_uint8 sent_status; - gpr_uint8 success; - grpc_linked_mdelem status; grpc_stream_op_buffer *recv_ops; - /* Closure to call when finished with the hs_on_recv hook. */ + /* Closure to call when finished with the auth_on_recv hook. */ grpc_iomgr_closure *on_done_recv; /* Receive closures are chained: we inject this closure as the on_done_recv up-call on transport_op, and remember to call our on_done_recv member after handling it. */ grpc_iomgr_closure auth_on_recv; + grpc_transport_stream_op transport_op; const grpc_metadata *consumed_md; size_t num_consumed_md; grpc_stream_op *md_op; @@ -61,7 +59,7 @@ typedef struct call_data { typedef struct channel_data { grpc_security_connector *security_connector; - grpc_mdelem *status_auth_failure; + grpc_mdctx *mdctx; } channel_data; static grpc_metadata_array metadata_batch_to_md_array( @@ -112,8 +110,8 @@ static void on_md_processing_done(void *user_data, grpc_auth_context *result) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; - calld->success = success; if (success) { calld->consumed_md = consumed_md; calld->num_consumed_md = num_consumed_md; @@ -124,11 +122,14 @@ static void on_md_processing_done(void *user_data, "releasing old context."); *calld->call_auth_context = GRPC_AUTH_CONTEXT_REF(result, "refing new context."); + calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } else { - grpc_call_element_send_cancel(elem); + grpc_transport_stream_op_add_cancellation( + &calld->transport_op, GRPC_STATUS_UNAUTHENTICATED, + grpc_mdstr_from_string(chand->mdctx, + "Authentication metadata processing failed.")); + grpc_call_next_op(elem, &calld->transport_op); } - - calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static void auth_on_recv(void *user_data, int success) { @@ -141,16 +142,18 @@ static void auth_on_recv(void *user_data, int success) { grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_metadata_array md_array; - grpc_process_auth_metadata_func processor = - grpc_server_auth_context_get_process_metadata_func(); + grpc_auth_metadata_processor processor = + grpc_server_get_auth_metadata_processor(); grpc_stream_op *op = &ops[i]; - if (op->type != GRPC_OP_METADATA) continue; + if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue; calld->got_client_metadata = 1; - if (processor == NULL) continue; + if (processor.process == NULL) continue; calld->md_op = op; md_array = metadata_batch_to_md_array(&op->data.metadata); - processor(&calld->ticket, chand->security_connector->auth_context, - md_array.metadata, md_array.count, on_md_processing_done, elem); + processor.process(processor.state, &calld->ticket, + chand->security_connector->auth_context, + md_array.metadata, md_array.count, + on_md_processing_done, elem); grpc_metadata_array_destroy(&md_array); return; } @@ -161,28 +164,13 @@ static void auth_on_recv(void *user_data, int success) { static void set_recv_ops_md_callbacks(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - - if (op->send_ops && !calld->sent_status && !calld->success) { - size_t i; - size_t nops = op->send_ops->nops; - grpc_stream_op *ops = op->send_ops->ops; - for (i = 0; i < nops; i++) { - grpc_stream_op *op = &ops[i]; - if (op->type != GRPC_OP_METADATA) continue; - calld->sent_status = 1; - grpc_metadata_batch_add_head( - &op->data.metadata, &calld->status, - GRPC_MDELEM_REF(chand->status_auth_failure)); - break; - } - } if (op->recv_ops && !calld->got_client_metadata) { /* substitute our callback for the higher callback */ calld->recv_ops = op->recv_ops; calld->on_done_recv = op->on_done_recv; op->on_done_recv = &calld->auth_on_recv; + calld->transport_op = *op; } } @@ -209,7 +197,6 @@ static void init_call_elem(grpc_call_element *elem, /* initialize members */ memset(calld, 0, sizeof(*calld)); grpc_iomgr_closure_init(&calld->auth_on_recv, auth_on_recv, elem); - calld->success = 1; GPR_ASSERT(initial_op && initial_op->context != NULL && initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); @@ -260,8 +247,7 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GPR_ASSERT(!sc->is_client_side); chand->security_connector = GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter"); - chand->status_auth_failure = - grpc_mdelem_from_strings(mdctx, ":status", "401"); + chand->mdctx = mdctx; } /* Destructor for channel data */ @@ -270,7 +256,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *chand = elem->channel_data; GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector, "server_auth_filter"); - GRPC_MDELEM_UNREF(chand->status_auth_failure); } const grpc_channel_filter grpc_server_auth_filter = { diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index c0214081c5d..7facb6997b3 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -84,45 +84,51 @@ static void check_peer_identity(grpc_auth_context *ctx, GPR_ASSERT(strcmp(expected_identity, prop->value) == 0); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); } -static void process_auth_md_success(grpc_auth_ticket *t, +static void process_auth_md_success(void *state, grpc_auth_ticket *t, grpc_auth_context *channel_ctx, const grpc_metadata *md, size_t md_count, grpc_process_auth_metadata_done_cb cb, void *user_data) { - grpc_auth_context *new_auth_ctx = grpc_auth_context_create(channel_ctx); - const grpc_metadata *custom_creds_md = - find_metadata(md, md_count, custom_creds_md_name, custom_creds_md_value); - GPR_ASSERT(custom_creds_md != NULL); - grpc_auth_context_add_cstring_property( - new_auth_ctx, client_identity_property_name, client_identity); - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - new_auth_ctx, client_identity_property_name) == 1); - cb(user_data, custom_creds_md, 1, 1, new_auth_ctx); - grpc_auth_context_release(new_auth_ctx); + override_mode *mode; + GPR_ASSERT(state != NULL); + mode = (override_mode *)state; + if (*mode != DESTROY) { + grpc_auth_context *new_auth_ctx = grpc_auth_context_create(channel_ctx); + const grpc_metadata *custom_creds_md = find_metadata( + md, md_count, custom_creds_md_name, custom_creds_md_value); + GPR_ASSERT(custom_creds_md != NULL); + grpc_auth_context_add_cstring_property( + new_auth_ctx, client_identity_property_name, client_identity); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + new_auth_ctx, client_identity_property_name) == 1); + cb(user_data, custom_creds_md, 1, 1, new_auth_ctx); + grpc_auth_context_release(new_auth_ctx); + } else { + cb(user_data, NULL, 0, 1, channel_ctx); + } } -#if 0 -static void process_auth_md_failure(grpc_auth_ticket *t, +static void process_auth_md_failure(void *state, grpc_auth_ticket *t, grpc_auth_context *channel_ctx, const grpc_metadata *md, size_t md_count, grpc_process_auth_metadata_done_cb cb, void *user_data) { - const grpc_metadata *custom_creds_md = - find_metadata(md, md_count, custom_creds_md_name, custom_creds_md_value); - GPR_ASSERT(custom_creds_md != NULL); + override_mode *mode; + GPR_ASSERT(state != NULL); + mode = (override_mode *)state; + if (*mode != DESTROY) { + const grpc_metadata *custom_creds_md = find_metadata( + md, md_count, custom_creds_md_name, custom_creds_md_value); + GPR_ASSERT(custom_creds_md != NULL); + } cb(user_data, NULL, 0, 0, NULL); /* Fail. */ } -#endif static grpc_end2end_test_fixture begin_test( grpc_end2end_test_config config, const char *test_name, - grpc_process_auth_metadata_func md_func, override_mode mode) { + grpc_auth_metadata_processor processor) { grpc_end2end_test_fixture f; - if (mode != DESTROY) { - grpc_server_auth_context_register_process_metadata_func(md_func); - } else { - grpc_server_auth_context_register_process_metadata_func(NULL); - } + grpc_server_register_auth_metadata_processor(processor); gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(NULL, NULL); config.init_client(&f, NULL); @@ -200,8 +206,9 @@ static grpc_credentials *iam_custom_composite_creds_create( static void test_call_creds_failure(grpc_end2end_test_config config) { grpc_call *c; grpc_credentials *creds = NULL; + grpc_auth_metadata_processor p = {NULL, NULL}; grpc_end2end_test_fixture f = - begin_test(config, "test_call_creds_failure", NULL, NONE); + begin_test(config, "test_call_creds_failure", p); gpr_timespec deadline = five_seconds_time(); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); @@ -230,10 +237,9 @@ static void request_response_with_payload_and_call_creds( grpc_byte_buffer *response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); - - grpc_end2end_test_fixture f = - begin_test(config, test_name, process_auth_md_success, mode); - cq_verifier *cqv = cq_verifier_create(f.cq); + grpc_auth_metadata_processor p; + grpc_end2end_test_fixture f; + cq_verifier *cqv; grpc_op ops[6]; grpc_op *op; grpc_metadata_array initial_metadata_recv; @@ -250,6 +256,11 @@ static void request_response_with_payload_and_call_creds( grpc_auth_context *s_auth_context = NULL; grpc_auth_context *c_auth_context = NULL; + p.process = process_auth_md_success; + p.state = &mode; + f = begin_test(config, test_name, p); + cqv = cq_verifier_create(f.cq); + c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); @@ -446,54 +457,41 @@ static void test_request_response_with_payload_and_deleted_call_creds( DESTROY); } -static void test_request_with_bad_creds(void) { -#if 0 - grpc_call *c; - grpc_call *s; - gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); - gpr_timespec deadline = five_seconds_time(); - - grpc_end2end_test_fixture f = - begin_test(config, test_name, process_auth_md_failure, NONE); - cq_verifier *cqv = cq_verifier_create(f.cq); +static void test_request_with_server_rejecting_client_creds( + grpc_end2end_test_config config) { grpc_op ops[6]; grpc_op *op; + grpc_call *c; + grpc_auth_metadata_processor p; + grpc_end2end_test_fixture f; + gpr_timespec deadline = five_seconds_time(); + cq_verifier *cqv; grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; - grpc_byte_buffer *request_payload_recv = NULL; - grpc_byte_buffer *response_payload_recv = NULL; grpc_call_details call_details; grpc_status_code status; char *details = NULL; size_t details_capacity = 0; - int was_cancelled = 2; - grpc_credentials *creds = NULL; - grpc_auth_context *s_auth_context = NULL; - grpc_auth_context *c_auth_context = NULL; + grpc_byte_buffer *response_payload_recv = NULL; + gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); + grpc_byte_buffer *request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + override_mode mode = NONE; + grpc_credentials *creds; + + p.process = process_auth_md_failure; + p.state = &mode; + f = begin_test(config, "test_request_with_server_rejecting_client_creds", p); + cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); + creds = iam_custom_composite_creds_create(iam_token, iam_selector); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); - switch (mode) { - case NONE: - break; - case OVERRIDE: - grpc_credentials_release(creds); - creds = iam_custom_composite_creds_create(overridden_iam_token, - overridden_iam_selector); - GPR_ASSERT(creds != NULL); - GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); - break; - case DESTROY: - GPR_ASSERT(grpc_call_set_credentials(c, NULL) == GRPC_CALL_OK); - break; - } grpc_credentials_release(creds); grpc_metadata_array_init(&initial_metadata_recv); @@ -502,6 +500,13 @@ static void test_request_with_bad_creds(void) { grpc_call_details_init(&call_details); op = ops; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->flags = 0; + op++; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op->flags = 0; @@ -521,134 +526,31 @@ static void test_request_with_bad_creds(void) { op->data.recv_message = &response_payload_recv; op->flags = 0; op++; - op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; - op->data.recv_status_on_client.status = &status; - op->data.recv_status_on_client.status_details = &details; - op->data.recv_status_on_client.status_details_capacity = &details_capacity; - op->flags = 0; - op++; GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1))); - GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( - f.server, &s, &call_details, - &request_metadata_recv, f.cq, f.cq, tag(101))); - cq_expect_completion(cqv, tag(101), 1); - cq_verify(cqv); - s_auth_context = grpc_call_auth_context(s); - GPR_ASSERT(s_auth_context != NULL); - print_auth_context(0, s_auth_context); - grpc_auth_context_release(s_auth_context); - - c_auth_context = grpc_call_auth_context(c); - GPR_ASSERT(c_auth_context != NULL); - print_auth_context(1, c_auth_context); - grpc_auth_context_release(c_auth_context); - - /* Cannot set creds on the server call object. */ - GPR_ASSERT(grpc_call_set_credentials(s, NULL) != GRPC_CALL_OK); - - op = ops; - op->op = GRPC_OP_SEND_INITIAL_METADATA; - op->data.send_initial_metadata.count = 0; - op->flags = 0; - op++; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message = &request_payload_recv; - op->flags = 0; - op++; - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102))); - - cq_expect_completion(cqv, tag(102), 1); - cq_verify(cqv); - - op = ops; - op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; - op->data.recv_close_on_server.cancelled = &was_cancelled; - op->flags = 0; - op++; - op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message = response_payload; - op->flags = 0; - op++; - op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; - op->data.send_status_from_server.trailing_metadata_count = 0; - op->data.send_status_from_server.status = GRPC_STATUS_OK; - op->data.send_status_from_server.status_details = "xyz"; - op->flags = 0; - op++; - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103))); - - cq_expect_completion(cqv, tag(103), 1); cq_expect_completion(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status == GRPC_STATUS_OK); - GPR_ASSERT(0 == strcmp(details, "xyz")); - GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); - GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr")); - GPR_ASSERT(was_cancelled == 0); - GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world")); - GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you")); - - /* Has been processed by the auth metadata processor. */ - GPR_ASSERT(!contains_metadata(&request_metadata_recv, custom_creds_md_name, - custom_creds_md_value)); - - switch (mode) { - case NONE: - GPR_ASSERT(contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, - iam_token)); - GPR_ASSERT(contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, - iam_selector)); - check_peer_identity(s_auth_context, client_identity); - break; - case OVERRIDE: - GPR_ASSERT(contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, - overridden_iam_token)); - GPR_ASSERT(contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, - overridden_iam_selector)); - check_peer_identity(s_auth_context, client_identity); - break; - case DESTROY: - GPR_ASSERT(!contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, - iam_token)); - GPR_ASSERT(!contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, - iam_selector)); - GPR_ASSERT(!contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, - overridden_iam_token)); - GPR_ASSERT(!contains_metadata(&request_metadata_recv, - GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, - overridden_iam_selector)); - break; - } + /* XXX Should be GRPC_STATUS_UNAUTHENTICATED but it looks like there is a bug + (probably in the server_auth_context.c code) where this error on the server + does not get to the client. The current error code we are getting is + GRPC_STATUS_INTERNAL. */ + GPR_ASSERT(status != GRPC_STATUS_OK); - gpr_free(details); grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_metadata_array_destroy(&request_metadata_recv); grpc_call_details_destroy(&call_details); - grpc_call_destroy(c); - grpc_call_destroy(s); - - cq_verifier_destroy(cqv); - grpc_byte_buffer_destroy(request_payload); - grpc_byte_buffer_destroy(response_payload); - grpc_byte_buffer_destroy(request_payload_recv); grpc_byte_buffer_destroy(response_payload_recv); + gpr_free(details); + grpc_call_destroy(c); + + cq_verifier_destroy(cqv); end_test(&f); config.tear_down_data(&f); -#endif } void grpc_end2end_tests(grpc_end2end_test_config config) { @@ -657,6 +559,6 @@ void grpc_end2end_tests(grpc_end2end_test_config config) { test_request_response_with_payload_and_call_creds(config); test_request_response_with_payload_and_overridden_call_creds(config); test_request_response_with_payload_and_deleted_call_creds(config); - test_request_with_bad_creds(); + test_request_with_server_rejecting_client_creds(config); } } From 6bdc9b47bc6dc5eeb296d66adf2d0789759aba37 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Sun, 19 Jul 2015 21:56:02 -0700 Subject: [PATCH 003/117] Getting started on metadata processor set on server creds. --- include/grpc/grpc_security.h | 10 ++-------- src/core/security/credentials.c | 6 ++++++ src/core/security/credentials.h | 1 + src/core/security/security_context.h | 5 ++++- src/core/security/server_secure_chttp2.c | 3 +++ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index ead708b2840..9b907ea3eba 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -300,14 +300,8 @@ typedef struct { void *state; } grpc_auth_metadata_processor; -/* XXXX: this is a temporarty interface. Please do NOT use. - This function will be moved to the server_credentials in a subsequent - pull request. XXXX - - Registration function for metadata processing. - Should be called before the server is started. */ -void grpc_server_register_auth_metadata_processor( - grpc_auth_metadata_processor processor); +void grpc_server_credentials_set_auth_metadata_processor( + grpc_server_credentials *creds, grpc_auth_metadata_processor processor); #ifdef __cplusplus } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 71513bcc25b..eb178ececba 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -149,6 +149,12 @@ grpc_security_status grpc_server_credentials_create_security_connector( return creds->vtable->create_security_connector(creds, sc); } +void grpc_server_credentials_set_auth_metadata_processor( + grpc_server_credentials *creds, grpc_auth_metadata_processor processor) { + if (creds == NULL) return; + creds->processor = processor; +} + /* -- Ssl credentials. -- */ static void ssl_destroy(grpc_credentials *creds) { diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 664524522ba..cee04b2120c 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -208,6 +208,7 @@ typedef struct { struct grpc_server_credentials { const grpc_server_credentials_vtable *vtable; const char *type; + grpc_auth_metadata_processor processor; }; grpc_security_status grpc_server_credentials_create_security_connector( diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index d4351cb74c5..5df5311d705 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -105,8 +105,11 @@ grpc_server_security_context *grpc_server_security_context_create(void); void grpc_server_security_context_destroy(void *ctx); /* --- Auth metadata processing. --- */ +#define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor" -grpc_auth_metadata_processor grpc_server_get_auth_metadata_processor(void); +grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p); +grpc_auth_metadata_processor grpc_auth_metadata_processor_from_arg( + const grpc_arg *arg); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 3717b8989f4..5dcd7e2f92f 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -60,6 +60,7 @@ typedef struct grpc_server_secure_state { grpc_server *server; grpc_tcp_server *tcp; grpc_security_connector *sc; + grpc_auth_metadata_processor processor; tcp_endpoint_list *handshaking_tcp_endpoints; int is_shutdown; gpr_mu mu; @@ -252,9 +253,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_resolved_addresses_destroy(resolved); state = gpr_malloc(sizeof(*state)); + memset(state, 0, sizeof(*state)); state->server = server; state->tcp = tcp; state->sc = sc; + state->processor = creds->processor; state->handshaking_tcp_endpoints = NULL; state->is_shutdown = 0; gpr_mu_init(&state->mu); From 8c8ecd8da1b81809876105aba2dd48b10e6ba63a Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 20 Jul 2015 16:37:50 -0700 Subject: [PATCH 004/117] Initial draft of a naming proposal. First draft for public review and comments. Some code formatting is still broken. --- doc/naming.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 doc/naming.md diff --git a/doc/naming.md b/doc/naming.md new file mode 100644 index 00000000000..e9101db9913 --- /dev/null +++ b/doc/naming.md @@ -0,0 +1,51 @@ +gRPC Naming and Discovery Support + +Hongwei Yang, Craig Tiller, Eric Anderson, Abhishek Kumar + +# Overview + +gRPC supports DNS as the default name-system. A number of alternative name-systems are used in various deployments. We propose an API that is general enough to support a range of name-systems and the corresponding syntax for names. The gRPC client library in various languages will provide a plugin mechanism so resolvers for different name-systems can be plugged in. + +# Detailed Proposal + + A fully qualified, self contained name used for gRPC channel construction uses the syntax: + +scheme://authority/endpoint_name + +Here, scheme indicates the name-system to be used. Example schemes to be supported include: + +* dns + +* zookeeper + +* etcd + +Authority indicates some scheme-specific bootstrap information, e.g., for DNS, the authority may include the IP[:port] of the DNS server to use. Often, a DNS name may used as the authority, since the ability to resolve DNS names is already built into all gRPC client libraries. + +Finally, the endpoint_name indicates a concrete name to be looked up in a given name-system identified by the scheme and the authority. The syntax of endpoint name is dictated by the scheme in use. + +## Plugins + +The gRPC client library will switch on the scheme to pick the right resolver plugin and pass it the fully qualified name string. + +Resolvers should be able to contact the authority and get a resolution that they return back to the gRPC client library. The returned contents include a list of IP:port, an optional config and optional auth config data to be used for channel authentication. The plugin API allows the resolvers to continuously watch an endpoint_name and return updated resolutions as needed. + +# Zookeeper + +Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as /path/service/instance similar to Apache Curator. + +A fully-qualified ZooKeeper name used to construct a gRPC channel will look as follows: + +zookeeper://host:port/path/service/instance + +Here zookeeper is the scheme identifying the name-system. host:port identifies an authoritative name-server for this scheme (i.e., a Zookeeper server). The host can be an IP address or a DNS name. +Finally /path/service/instance is the Zookeeper name to be resolved. + +## Service Registration + + +Service providers can register their services in Zookeeper by using a Zookeeper client. + +Each service is a zookeeper node, and each instance is a child node of the corresponding service. For example, a MySQL service may have multiple instances, /mysql/1, /mysql/2, /mysql/3. The name of the service or instance, as well as an optional path is specified by the service provider. + +The data in service nodes is empty. Each instance node stores its address in the format of host:port, where host can be either hostname or IP address. From 2d8eeb416ba465c169ce763a0b46f2c7914deaed Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 21 Jul 2015 10:00:36 -0700 Subject: [PATCH 005/117] Formatting fixes Added some formatting fixes . --- doc/naming.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/doc/naming.md b/doc/naming.md index e9101db9913..9294529ea53 100644 --- a/doc/naming.md +++ b/doc/naming.md @@ -1,51 +1,50 @@ -gRPC Naming and Discovery Support +#gRPC Naming and Discovery Support -Hongwei Yang, Craig Tiller, Eric Anderson, Abhishek Kumar - -# Overview +## Overview gRPC supports DNS as the default name-system. A number of alternative name-systems are used in various deployments. We propose an API that is general enough to support a range of name-systems and the corresponding syntax for names. The gRPC client library in various languages will provide a plugin mechanism so resolvers for different name-systems can be plugged in. -# Detailed Proposal +## Detailed Proposal A fully qualified, self contained name used for gRPC channel construction uses the syntax: -scheme://authority/endpoint_name +```scheme://authority/endpoint_name +``` Here, scheme indicates the name-system to be used. Example schemes to be supported include: -* dns +* `dns` -* zookeeper +* `zookeeper` -* etcd +* `etcd` Authority indicates some scheme-specific bootstrap information, e.g., for DNS, the authority may include the IP[:port] of the DNS server to use. Often, a DNS name may used as the authority, since the ability to resolve DNS names is already built into all gRPC client libraries. Finally, the endpoint_name indicates a concrete name to be looked up in a given name-system identified by the scheme and the authority. The syntax of endpoint name is dictated by the scheme in use. -## Plugins +### Plugins The gRPC client library will switch on the scheme to pick the right resolver plugin and pass it the fully qualified name string. Resolvers should be able to contact the authority and get a resolution that they return back to the gRPC client library. The returned contents include a list of IP:port, an optional config and optional auth config data to be used for channel authentication. The plugin API allows the resolvers to continuously watch an endpoint_name and return updated resolutions as needed. -# Zookeeper +## Zookeeper -Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as /path/service/instance similar to Apache Curator. +Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as `/path/service/instance similar` to Apache Curator. A fully-qualified ZooKeeper name used to construct a gRPC channel will look as follows: -zookeeper://host:port/path/service/instance - -Here zookeeper is the scheme identifying the name-system. host:port identifies an authoritative name-server for this scheme (i.e., a Zookeeper server). The host can be an IP address or a DNS name. -Finally /path/service/instance is the Zookeeper name to be resolved. +```zookeeper://host:port/path/service/instance +``` +Here `zookeeper` is the scheme identifying the name-system. `host:port` identifies an authoritative name-server for this scheme (i.e., a Zookeeper server). The host can be an IP address or a DNS name. +Finally `/path/service/instance` is the Zookeeper name to be resolved. ## Service Registration Service providers can register their services in Zookeeper by using a Zookeeper client. -Each service is a zookeeper node, and each instance is a child node of the corresponding service. For example, a MySQL service may have multiple instances, /mysql/1, /mysql/2, /mysql/3. The name of the service or instance, as well as an optional path is specified by the service provider. +Each service is a zookeeper node, and each instance is a child node of the corresponding service. For example, a MySQL service may have multiple instances, `/mysql/1`, `/mysql/2`, `/mysql/3`. The name of the service or instance, as well as an optional path is specified by the service provider. -The data in service nodes is empty. Each instance node stores its address in the format of host:port, where host can be either hostname or IP address. +The data in service nodes is empty. Each instance node stores its address in the format of `host:port`, where host can be either hostname or IP address. From c7e13188fad12bfb590fc0648ace949dcae0abe5 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 21 Jul 2015 14:26:17 -0700 Subject: [PATCH 006/117] Update naming.md Fixed code formatting issues. --- doc/naming.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/naming.md b/doc/naming.md index 9294529ea53..5ad7e6622ed 100644 --- a/doc/naming.md +++ b/doc/naming.md @@ -8,7 +8,8 @@ gRPC supports DNS as the default name-system. A number of alternative name-syste A fully qualified, self contained name used for gRPC channel construction uses the syntax: -```scheme://authority/endpoint_name +``` +scheme://authority/endpoint_name ``` Here, scheme indicates the name-system to be used. Example schemes to be supported include: @@ -31,11 +32,12 @@ Resolvers should be able to contact the authority and get a resolution that they ## Zookeeper -Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as `/path/service/instance similar` to Apache Curator. +Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as `/path/service/instance` similar to Apache Curator. A fully-qualified ZooKeeper name used to construct a gRPC channel will look as follows: -```zookeeper://host:port/path/service/instance +``` +zookeeper://host:port/path/service/instance ``` Here `zookeeper` is the scheme identifying the name-system. `host:port` identifies an authoritative name-server for this scheme (i.e., a Zookeeper server). The host can be an IP address or a DNS name. Finally `/path/service/instance` is the Zookeeper name to be resolved. From 66a27daef6e0acc4ad9d3789580e1d3107670c9d Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Tue, 21 Jul 2015 17:17:35 -0700 Subject: [PATCH 007/117] Putting the auth metadata processor on the server creds. --- src/core/security/security_context.c | 32 +++ src/core/security/security_context.h | 4 +- src/core/security/server_auth_filter.c | 17 +- src/core/security/server_secure_chttp2.c | 11 +- .../chttp2_simple_ssl_with_oauth2_fullstack.c | 42 +++- ...est_response_with_payload_and_call_creds.c | 201 +----------------- 6 files changed, 99 insertions(+), 208 deletions(-) diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 8ccce89ba94..1ef0fc9255b 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -295,3 +295,35 @@ void grpc_auth_property_reset(grpc_auth_property *property) { memset(property, 0, sizeof(grpc_auth_property)); } +grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p) { + grpc_arg arg; + memset(&arg, 0, sizeof(grpc_arg)); + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_AUTH_METADATA_PROCESSOR_ARG; + arg.value.pointer.p = p; + return arg; +} + +grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( + const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_AUTH_METADATA_PROCESSOR_ARG) != 0) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_AUTH_METADATA_PROCESSOR_ARG); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_auth_metadata_processor *p = + grpc_auth_metadata_processor_from_arg(&args->args[i]); + if (p != NULL) return p; + } + return NULL; +} + diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 5df5311d705..ddc0a7afad6 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -108,8 +108,10 @@ void grpc_server_security_context_destroy(void *ctx); #define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor" grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p); -grpc_auth_metadata_processor grpc_auth_metadata_processor_from_arg( +grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( const grpc_arg *arg); +grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( + const grpc_channel_args *args); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 918cb401ebd..cc260554405 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -59,6 +59,7 @@ typedef struct call_data { typedef struct channel_data { grpc_security_connector *security_connector; + grpc_auth_metadata_processor processor; grpc_mdctx *mdctx; } channel_data; @@ -142,18 +143,16 @@ static void auth_on_recv(void *user_data, int success) { grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_metadata_array md_array; - grpc_auth_metadata_processor processor = - grpc_server_get_auth_metadata_processor(); grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue; calld->got_client_metadata = 1; - if (processor.process == NULL) continue; + if (chand->processor.process == NULL) continue; calld->md_op = op; md_array = metadata_batch_to_md_array(&op->data.metadata); - processor.process(processor.state, &calld->ticket, - chand->security_connector->auth_context, - md_array.metadata, md_array.count, - on_md_processing_done, elem); + chand->processor.process(chand->processor.state, &calld->ticket, + chand->security_connector->auth_context, + md_array.metadata, md_array.count, + on_md_processing_done, elem); grpc_metadata_array_destroy(&md_array); return; } @@ -233,6 +232,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { grpc_security_connector *sc = grpc_find_security_connector_in_args(args); + grpc_auth_metadata_processor *processor = + grpc_find_auth_metadata_processor_in_args(args); /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; @@ -242,12 +243,14 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); GPR_ASSERT(sc != NULL); + GPR_ASSERT(processor != NULL); /* initialize members */ GPR_ASSERT(!sc->is_client_side); chand->security_connector = GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter"); chand->mdctx = mdctx; + chand->processor = *processor; } /* Destructor for channel data */ diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 5dcd7e2f92f..8d9d036d808 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -43,6 +43,7 @@ #include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/security_connector.h" +#include "src/core/security/security_context.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/surface/server.h" #include "src/core/transport/chttp2_transport.h" @@ -87,9 +88,13 @@ static void setup_transport(void *statep, grpc_transport *transport, static grpc_channel_filter const *extra_filters[] = { &grpc_server_auth_filter, &grpc_http_server_filter}; grpc_server_secure_state *state = statep; - grpc_arg connector_arg = grpc_security_connector_to_arg(state->sc); - grpc_channel_args *args_copy = grpc_channel_args_copy_and_add( - grpc_server_get_channel_args(state->server), &connector_arg, 1); + grpc_channel_args *args_copy; + grpc_arg args_to_add[2]; + args_to_add[0] = grpc_security_connector_to_arg(state->sc); + args_to_add[1] = grpc_auth_metadata_processor_to_arg(&state->processor); + args_copy = grpc_channel_args_copy_and_add( + grpc_server_get_channel_args(state->server), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); grpc_server_setup_transport(state->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy); grpc_channel_args_destroy(args_copy); diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c index da658a0b45a..c926a4e4b74 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c @@ -46,10 +46,46 @@ #include "test/core/util/port.h" #include "test/core/end2end/data/ssl_test_data.h" +static const char oauth2_md[] = "Bearer aaslkfjs424535asdf"; +static const char *client_identity_property_name = "smurf_name"; +static const char *client_identity = "Brainy Smurf"; + typedef struct fullstack_secure_fixture_data { char *localaddr; } fullstack_secure_fixture_data; +static const grpc_metadata *find_metadata(const grpc_metadata *md, + size_t md_count, + const char *key, + const char *value) { + size_t i; + for (i = 0; i < md_count; i++) { + if (strcmp(key, md[i].key) == 0 && strlen(value) == md[i].value_length && + memcmp(md[i].value, value, md[i].value_length) == 0) { + return &md[i]; + } + } + return NULL; +} + +void process_oauth2(void *state, grpc_auth_ticket *ticket, + grpc_auth_context *channel_ctx, const grpc_metadata *md, + size_t md_count, grpc_process_auth_metadata_done_cb cb, + void *user_data) { + const grpc_metadata *oauth2 = + find_metadata(md, md_count, "Authorization", oauth2_md); + grpc_auth_context *new_ctx; + GPR_ASSERT(state == NULL); + GPR_ASSERT(oauth2 != NULL); + new_ctx = grpc_auth_context_create(channel_ctx); + grpc_auth_context_add_cstring_property(new_ctx, client_identity_property_name, + client_identity); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + new_ctx, client_identity_property_name) == 1); + cb(user_data, oauth2, 1, 1, new_ctx); + grpc_auth_context_release(new_ctx); +} + static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; @@ -100,8 +136,8 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { grpc_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL); - grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( - "Authorization", "Bearer aaslkfjs424535asdf", 1); + grpc_credentials *oauth2_creds = + grpc_md_only_test_credentials_create("Authorization", oauth2_md, 1); grpc_credentials *ssl_oauth2_creds = grpc_composite_credentials_create(ssl_creds, oauth2_creds); grpc_arg ssl_name_override = {GRPC_ARG_STRING, @@ -121,6 +157,8 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1); + grpc_auth_metadata_processor processor = {process_oauth2, NULL}; + grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); } diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index 7facb6997b3..e621fcbed2e 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -46,11 +46,6 @@ #include "src/core/security/credentials.h" #include "src/core/support/string.h" -static const char *custom_creds_md_name = "custom_creds"; -static const char *custom_creds_md_value = "custom_value"; -static const char *client_identity_property_name = "smurf_name"; -static const char *client_identity = "Brainy Smurf"; - static const char iam_token[] = "token"; static const char iam_selector[] = "selector"; static const char overridden_iam_token[] = "overridden_token"; @@ -62,73 +57,9 @@ enum { TIMEOUT = 200000 }; static void *tag(gpr_intptr t) { return (void *)t; } -static const grpc_metadata *find_metadata(const grpc_metadata *md, - size_t md_count, - const char *key, - const char *value) { - size_t i; - for (i = 0; i < md_count; i++) { - if (strcmp(key, md[i].key) == 0 && strlen(value) == md[i].value_length && - memcmp(md[i].value, value, md[i].value_length) == 0) { - return &md[i]; - } - } - return NULL; -} - -static void check_peer_identity(grpc_auth_context *ctx, - const char *expected_identity) { - grpc_auth_property_iterator it = grpc_auth_context_peer_identity(ctx); - const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(prop != NULL); - GPR_ASSERT(strcmp(expected_identity, prop->value) == 0); - GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL); -} -static void process_auth_md_success(void *state, grpc_auth_ticket *t, - grpc_auth_context *channel_ctx, - const grpc_metadata *md, size_t md_count, - grpc_process_auth_metadata_done_cb cb, - void *user_data) { - override_mode *mode; - GPR_ASSERT(state != NULL); - mode = (override_mode *)state; - if (*mode != DESTROY) { - grpc_auth_context *new_auth_ctx = grpc_auth_context_create(channel_ctx); - const grpc_metadata *custom_creds_md = find_metadata( - md, md_count, custom_creds_md_name, custom_creds_md_value); - GPR_ASSERT(custom_creds_md != NULL); - grpc_auth_context_add_cstring_property( - new_auth_ctx, client_identity_property_name, client_identity); - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - new_auth_ctx, client_identity_property_name) == 1); - cb(user_data, custom_creds_md, 1, 1, new_auth_ctx); - grpc_auth_context_release(new_auth_ctx); - } else { - cb(user_data, NULL, 0, 1, channel_ctx); - } -} - -static void process_auth_md_failure(void *state, grpc_auth_ticket *t, - grpc_auth_context *channel_ctx, - const grpc_metadata *md, size_t md_count, - grpc_process_auth_metadata_done_cb cb, - void *user_data) { - override_mode *mode; - GPR_ASSERT(state != NULL); - mode = (override_mode *)state; - if (*mode != DESTROY) { - const grpc_metadata *custom_creds_md = find_metadata( - md, md_count, custom_creds_md_name, custom_creds_md_value); - GPR_ASSERT(custom_creds_md != NULL); - } - cb(user_data, NULL, 0, 0, NULL); /* Fail. */ -} - static grpc_end2end_test_fixture begin_test( - grpc_end2end_test_config config, const char *test_name, - grpc_auth_metadata_processor processor) { + grpc_end2end_test_config config, const char *test_name) { grpc_end2end_test_fixture f; - grpc_server_register_auth_metadata_processor(processor); gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(NULL, NULL); config.init_client(&f, NULL); @@ -191,24 +122,10 @@ static void print_auth_context(int is_client, const grpc_auth_context *ctx) { } } -static grpc_credentials *iam_custom_composite_creds_create( - const char *iam_tok, const char *iam_sel) { - grpc_credentials *iam_creds = grpc_iam_credentials_create(iam_tok, iam_sel); - grpc_credentials *custom_creds = grpc_md_only_test_credentials_create( - custom_creds_md_name, custom_creds_md_value, 1); - grpc_credentials *result = - grpc_composite_credentials_create(iam_creds, custom_creds); - grpc_credentials_release(iam_creds); - grpc_credentials_release(custom_creds); - return result; -} - static void test_call_creds_failure(grpc_end2end_test_config config) { grpc_call *c; grpc_credentials *creds = NULL; - grpc_auth_metadata_processor p = {NULL, NULL}; - grpc_end2end_test_fixture f = - begin_test(config, "test_call_creds_failure", p); + grpc_end2end_test_fixture f = begin_test(config, "test_call_creds_failure"); gpr_timespec deadline = five_seconds_time(); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); @@ -237,7 +154,6 @@ static void request_response_with_payload_and_call_creds( grpc_byte_buffer *response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); - grpc_auth_metadata_processor p; grpc_end2end_test_fixture f; cq_verifier *cqv; grpc_op ops[6]; @@ -256,15 +172,13 @@ static void request_response_with_payload_and_call_creds( grpc_auth_context *s_auth_context = NULL; grpc_auth_context *c_auth_context = NULL; - p.process = process_auth_md_success; - p.state = &mode; - f = begin_test(config, test_name, p); + f = begin_test(config, test_name); cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); - creds = iam_custom_composite_creds_create(iam_token, iam_selector); + creds = grpc_iam_credentials_create(iam_token, iam_selector); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); switch (mode) { @@ -272,8 +186,8 @@ static void request_response_with_payload_and_call_creds( break; case OVERRIDE: grpc_credentials_release(creds); - creds = iam_custom_composite_creds_create(overridden_iam_token, - overridden_iam_selector); + creds = grpc_iam_credentials_create(overridden_iam_token, + overridden_iam_selector); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); break; @@ -378,10 +292,6 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world")); GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you")); - /* Has been processed by the auth metadata processor. */ - GPR_ASSERT(!contains_metadata(&request_metadata_recv, custom_creds_md_name, - custom_creds_md_value)); - switch (mode) { case NONE: GPR_ASSERT(contains_metadata(&request_metadata_recv, @@ -390,7 +300,6 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(contains_metadata(&request_metadata_recv, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, iam_selector)); - check_peer_identity(s_auth_context, client_identity); break; case OVERRIDE: GPR_ASSERT(contains_metadata(&request_metadata_recv, @@ -399,7 +308,6 @@ static void request_response_with_payload_and_call_creds( GPR_ASSERT(contains_metadata(&request_metadata_recv, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, overridden_iam_selector)); - check_peer_identity(s_auth_context, client_identity); break; case DESTROY: GPR_ASSERT(!contains_metadata(&request_metadata_recv, @@ -457,108 +365,11 @@ static void test_request_response_with_payload_and_deleted_call_creds( DESTROY); } -static void test_request_with_server_rejecting_client_creds( - grpc_end2end_test_config config) { - grpc_op ops[6]; - grpc_op *op; - grpc_call *c; - grpc_auth_metadata_processor p; - grpc_end2end_test_fixture f; - gpr_timespec deadline = five_seconds_time(); - cq_verifier *cqv; - grpc_metadata_array initial_metadata_recv; - grpc_metadata_array trailing_metadata_recv; - grpc_metadata_array request_metadata_recv; - grpc_call_details call_details; - grpc_status_code status; - char *details = NULL; - size_t details_capacity = 0; - grpc_byte_buffer *response_payload_recv = NULL; - gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); - override_mode mode = NONE; - grpc_credentials *creds; - - p.process = process_auth_md_failure; - p.state = &mode; - f = begin_test(config, "test_request_with_server_rejecting_client_creds", p); - cqv = cq_verifier_create(f.cq); - - c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", - deadline); - GPR_ASSERT(c); - - creds = iam_custom_composite_creds_create(iam_token, iam_selector); - GPR_ASSERT(creds != NULL); - GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); - grpc_credentials_release(creds); - - grpc_metadata_array_init(&initial_metadata_recv); - grpc_metadata_array_init(&trailing_metadata_recv); - grpc_metadata_array_init(&request_metadata_recv); - grpc_call_details_init(&call_details); - - op = ops; - op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; - op->data.recv_status_on_client.status = &status; - op->data.recv_status_on_client.status_details = &details; - op->data.recv_status_on_client.status_details_capacity = &details_capacity; - op->flags = 0; - op++; - op->op = GRPC_OP_SEND_INITIAL_METADATA; - op->data.send_initial_metadata.count = 0; - op->flags = 0; - op++; - op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message = request_payload; - op->flags = 0; - op++; - op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - op->flags = 0; - op++; - op->op = GRPC_OP_RECV_INITIAL_METADATA; - op->data.recv_initial_metadata = &initial_metadata_recv; - op->flags = 0; - op++; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message = &response_payload_recv; - op->flags = 0; - op++; - GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1))); - - cq_expect_completion(cqv, tag(1), 1); - cq_verify(cqv); - - /* XXX Should be GRPC_STATUS_UNAUTHENTICATED but it looks like there is a bug - (probably in the server_auth_context.c code) where this error on the server - does not get to the client. The current error code we are getting is - GRPC_STATUS_INTERNAL. */ - GPR_ASSERT(status != GRPC_STATUS_OK); - - grpc_metadata_array_destroy(&initial_metadata_recv); - grpc_metadata_array_destroy(&trailing_metadata_recv); - grpc_metadata_array_destroy(&request_metadata_recv); - grpc_call_details_destroy(&call_details); - - grpc_byte_buffer_destroy(request_payload); - grpc_byte_buffer_destroy(response_payload_recv); - gpr_free(details); - - grpc_call_destroy(c); - - cq_verifier_destroy(cqv); - end_test(&f); - config.tear_down_data(&f); -} - void grpc_end2end_tests(grpc_end2end_test_config config) { if (config.feature_mask & FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS) { test_call_creds_failure(config); test_request_response_with_payload_and_call_creds(config); test_request_response_with_payload_and_overridden_call_creds(config); test_request_response_with_payload_and_deleted_call_creds(config); - test_request_with_server_rejecting_client_creds(config); } } From 54b8f0f3a768b9f9eac3fe7a700f7fe25ffcf4c5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jul 2015 16:33:52 -0700 Subject: [PATCH 008/117] Eliminated some redundant checks in the Node interop client --- src/node/interop/interop_client.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index e810e68e450..d2f512968d4 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -69,9 +69,6 @@ function zeroBuffer(size) { function emptyUnary(client, done) { var call = client.emptyCall({}, function(err, resp) { assert.ifError(err); - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } @@ -96,9 +93,6 @@ function largeUnary(client, done) { assert.ifError(err); assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); assert.strictEqual(resp.payload.body.length, 314159); - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } @@ -115,9 +109,6 @@ function clientStreaming(client, done) { var call = client.streamingInputCall(function(err, resp) { assert.ifError(err); assert.strictEqual(resp.aggregated_payload_size, 74922); - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } @@ -308,9 +299,6 @@ function authTest(expected_user, scope, client, done) { assert.strictEqual(resp.payload.body.length, 314159); assert.strictEqual(resp.username, expected_user); assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } @@ -344,9 +332,6 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) { assert.ifError(err); assert.strictEqual(resp.username, expected_user); assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } @@ -358,7 +343,6 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) { client.updateMetadata = updateMetadata; makeTestCall(null, {}); } - }); }); } From 8f4b1b032e886a39f91b6950874a54372bc30efd Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 30 Jul 2015 17:22:10 -0700 Subject: [PATCH 009/117] bump C# version to 0.6.1 and core version to 0.10.1 Conflicts: src/csharp/Grpc.Core/Version.cs --- Makefile | 2 +- build.json | 2 +- src/core/surface/version.c | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages.bat | 4 ++-- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 0a8b5cfaf09..6a5b3836c13 100644 --- a/Makefile +++ b/Makefile @@ -313,7 +313,7 @@ E = @echo Q = @ endif -VERSION = 0.10.0.0 +VERSION = 0.10.1.0 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.json b/build.json index 6e39cb4ea8d..dad8b423378 100644 --- a/build.json +++ b/build.json @@ -7,7 +7,7 @@ "version": { "major": 0, "minor": 10, - "micro": 0, + "micro": 1, "build": 0 } }, diff --git a/src/core/surface/version.c b/src/core/surface/version.c index 4f5d6483710..d7aaba3868e 100644 --- a/src/core/surface/version.c +++ b/src/core/surface/version.c @@ -37,5 +37,5 @@ #include const char *grpc_version_string(void) { - return "0.10.0.0"; + return "0.10.1.0"; } diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 656a3d47bbe..939372e2370 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -8,6 +8,6 @@ namespace Grpc.Core /// /// Current version of gRPC /// - public const string CurrentVersion = "0.6.0"; + public const string CurrentVersion = "0.6.1"; } } diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat index 9e1253bf0bd..8a11d014307 100644 --- a/src/csharp/build_packages.bat +++ b/src/csharp/build_packages.bat @@ -1,8 +1,8 @@ @rem Builds gRPC NuGet packages @rem Current package versions -set VERSION=0.6.0 -set CORE_VERSION=0.10.0 +set VERSION=0.6.1 +set CORE_VERSION=0.10.1 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 785779beb5d..4a17fb73658 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.10.0.0 +PROJECT_NUMBER = 0.10.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5cf6168388e..297a21ae22a 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.10.0.0 +PROJECT_NUMBER = 0.10.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 1bfd7875289..38107b392e1 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.10.0.0 +PROJECT_NUMBER = 0.10.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 9247beb86b8..487b81a93d0 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.10.0.0 +PROJECT_NUMBER = 0.10.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 45ce927c7cf7abbdb452989d6d58c875a800e4ea Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 31 Jul 2015 11:22:35 -0700 Subject: [PATCH 010/117] Properly send GRPC_STATUS_UNAUTHENTICATED from server auth failures --- src/core/channel/compress_filter.c | 10 +- src/core/security/client_auth_filter.c | 6 +- src/core/security/server_auth_filter.c | 10 +- src/core/transport/chttp2/internal.h | 2 + src/core/transport/chttp2_transport.c | 113 ++++++++++++++++++ src/core/transport/metadata.c | 2 + src/core/transport/transport.c | 52 +++++++- src/core/transport/transport.h | 13 +- ...est_response_with_payload_and_call_creds.c | 2 +- 9 files changed, 189 insertions(+), 21 deletions(-) diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c index 9fc8589fbb4..8963c13b0f5 100644 --- a/src/core/channel/compress_filter.c +++ b/src/core/channel/compress_filter.c @@ -204,7 +204,7 @@ static void process_send_ops(grpc_call_element *elem, } grpc_metadata_batch_add_tail( &(sop->data.metadata), &calld->compression_algorithm_storage, - grpc_mdelem_ref(channeld->mdelem_compression_algorithms + GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms [calld->compression_algorithm])); calld->written_initial_metadata = 1; /* GPR_TRUE */ } @@ -295,7 +295,7 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, channeld->mdelem_compression_algorithms[algo_idx] = grpc_mdelem_from_metadata_strings( mdctx, - grpc_mdstr_ref(channeld->mdstr_outgoing_compression_algorithm_key), + GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key), grpc_mdstr_from_string(mdctx, algorithm_name, 0)); } @@ -307,11 +307,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *channeld = elem->channel_data; grpc_compression_algorithm algo_idx; - grpc_mdstr_unref(channeld->mdstr_request_compression_algorithm_key); - grpc_mdstr_unref(channeld->mdstr_outgoing_compression_algorithm_key); + GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key); + GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key); for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { - grpc_mdelem_unref(channeld->mdelem_compression_algorithms[algo_idx]); + GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]); } } diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index e86b5430b2c..e2d1b6fce91 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -77,10 +77,8 @@ typedef struct { static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_transport_stream_op_add_cancellation( - &calld->op, GRPC_STATUS_UNAUTHENTICATED, - grpc_mdstr_from_string(chand->md_ctx, error_msg, 0)); + grpc_transport_stream_op_add_cancellation(&calld->op, + GRPC_STATUS_UNAUTHENTICATED); grpc_call_next_op(elem, &calld->op); } diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 10dfb09926a..fd0f94b19c3 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -110,7 +110,6 @@ static void on_md_processing_done(void *user_data, grpc_auth_context *result) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; if (success) { calld->consumed_md = consumed_md; @@ -124,10 +123,11 @@ static void on_md_processing_done(void *user_data, GRPC_AUTH_CONTEXT_REF(result, "refing new context."); calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } else { - grpc_transport_stream_op_add_cancellation( - &calld->transport_op, GRPC_STATUS_UNAUTHENTICATED, - grpc_mdstr_from_string(chand->mdctx, - "Authentication metadata processing failed.")); + gpr_slice message = gpr_slice_from_copied_string( + "Authentication metadata processing failed."); + grpc_sopb_reset(calld->recv_ops); + grpc_transport_stream_op_add_close(&calld->transport_op, + GRPC_STATUS_UNAUTHENTICATED, &message); grpc_call_next_op(elem, &calld->transport_op); } } diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index f0eeb6de505..74b3a591d56 100644 --- a/src/core/transport/chttp2/internal.h +++ b/src/core/transport/chttp2/internal.h @@ -384,6 +384,8 @@ typedef struct { gpr_uint8 in_stream_map; /** is this stream actively being written? */ gpr_uint8 writing_now; + /** has anything been written to this stream? */ + gpr_uint8 written_anything; /** stream state already published to the upper layer */ grpc_stream_state published_state; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 1ea4a82c16f..c8c4207208b 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -107,6 +107,11 @@ static void cancel_from_api(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_status_code status); +static void close_from_api(grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status, + gpr_slice *optional_message); + /** Add endpoint from this transport to pollset */ static void add_to_pollset_locked(grpc_chttp2_transport *t, grpc_pollset *pollset); @@ -602,10 +607,16 @@ static void perform_stream_op_locked( cancel_from_api(transport_global, stream_global, op->cancel_with_status); } + if (op->close_with_status != GRPC_STATUS_OK) { + close_from_api(transport_global, stream_global, op->close_with_status, + op->optional_close_message); + } + if (op->send_ops) { GPR_ASSERT(stream_global->outgoing_sopb == NULL); stream_global->send_done_closure = op->on_done_send; if (!stream_global->cancelled) { + stream_global->written_anything = 1; stream_global->outgoing_sopb = op->send_ops; if (op->is_last_send && stream_global->write_state == GRPC_WRITE_STATE_OPEN) { @@ -894,6 +905,108 @@ static void cancel_from_api(grpc_chttp2_transport_global *transport_global, stream_global); } +static void close_from_api(grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status, + gpr_slice *optional_message) { + gpr_slice hdr; + gpr_slice status_hdr; + gpr_slice message_pfx; + gpr_uint8 *p; + gpr_uint32 len = 0; + + GPR_ASSERT(status >= 0 && (int)status < 100); + + stream_global->cancelled = 1; + stream_global->cancelled_status = status; + GPR_ASSERT(stream_global->id != 0); + GPR_ASSERT(!stream_global->written_anything); + + /* Hand roll a header block. + This is unnecessarily ugly - at some point we should find a more elegant + solution. + It's complicated by the fact that our send machinery would be dead by the + time we got around to sending this, so instead we ignore HPACK compression + and just write the uncompressed bytes onto the wire. */ + status_hdr = gpr_slice_malloc(15 + (status >= 10)); + p = GPR_SLICE_START_PTR(status_hdr); + *p++ = 0x40; /* literal header */ + *p++ = 11; /* len(grpc-status) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 's'; + *p++ = 't'; + *p++ = 'a'; + *p++ = 't'; + *p++ = 'u'; + *p++ = 's'; + if (status < 10) { + *p++ = 1; + *p++ = '0' + status; + } else { + *p++ = 2; + *p++ = '0' + (status / 10); + *p++ = '0' + (status % 10); + } + GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr)); + len += GPR_SLICE_LENGTH(status_hdr); + + if (optional_message) { + GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127); + message_pfx = gpr_slice_malloc(15); + p = GPR_SLICE_START_PTR(message_pfx); + *p++ = 0x40; + *p++ = 12; /* len(grpc-message) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 'm'; + *p++ = 'e'; + *p++ = 's'; + *p++ = 's'; + *p++ = 'a'; + *p++ = 'g'; + *p++ = 'e'; + *p++ = GPR_SLICE_LENGTH(*optional_message); + GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx)); + len += GPR_SLICE_LENGTH(message_pfx); + len += GPR_SLICE_LENGTH(*optional_message); + } + + hdr = gpr_slice_malloc(9); + p = GPR_SLICE_START_PTR(hdr); + *p++ = len >> 16; + *p++ = len >> 8; + *p++ = len; + *p++ = GRPC_CHTTP2_FRAME_HEADER; + *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; + *p++ = stream_global->id >> 24; + *p++ = stream_global->id >> 16; + *p++ = stream_global->id >> 8; + *p++ = stream_global->id; + GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr)); + + gpr_slice_buffer_add(&transport_global->qbuf, hdr); + gpr_slice_buffer_add(&transport_global->qbuf, status_hdr); + if (optional_message) { + gpr_slice_buffer_add(&transport_global->qbuf, message_pfx); + gpr_slice_buffer_add(&transport_global->qbuf, + gpr_slice_ref(*optional_message)); + } + + gpr_slice_buffer_add( + &transport_global->qbuf, + grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR)); + + grpc_chttp2_list_add_read_write_state_changed(transport_global, + stream_global); +} + static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, void *user_data, grpc_chttp2_stream_global *stream_global) { diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index 967fd4898c5..44d32b6cb2b 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -135,7 +135,9 @@ static void unlock(grpc_mdctx *ctx) { if (ctx->refs == 0) { /* uncomment if you're having trouble diagnosing an mdelem leak to make things clearer (slows down destruction a lot, however) */ +#ifdef GRPC_METADATA_REFCOUNT_DEBUG gc_mdtab(ctx); +#endif if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) { discard_metadata(ctx); } diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index 69c00b6a4fd..c0d92cf93f6 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -32,6 +32,8 @@ */ #include "src/core/transport/transport.h" +#include +#include #include "src/core/transport/transport_impl.h" size_t grpc_transport_stream_size(grpc_transport *transport) { @@ -83,12 +85,54 @@ void grpc_transport_stream_op_finish_with_failure( } void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status, - grpc_mdstr *message) { + grpc_status_code status) { + GPR_ASSERT(status != GRPC_STATUS_OK); if (op->cancel_with_status == GRPC_STATUS_OK) { op->cancel_with_status = status; } - if (message) { - GRPC_MDSTR_UNREF(message); + if (op->close_with_status != GRPC_STATUS_OK) { + op->close_with_status = GRPC_STATUS_OK; + if (op->optional_close_message != NULL) { + gpr_slice_unref(*op->optional_close_message); + op->optional_close_message = NULL; + } } } + +typedef struct { + gpr_slice message; + grpc_iomgr_closure *then_call; + grpc_iomgr_closure closure; +} close_message_data; + +static void free_message(void *p, int iomgr_success) { + close_message_data *cmd = p; + gpr_slice_unref(cmd->message); + if (cmd->then_call != NULL) { + cmd->then_call->cb(cmd->then_call->cb_arg, iomgr_success); + } + gpr_free(cmd); +} + +void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, + grpc_status_code status, + gpr_slice *optional_message) { + close_message_data *cmd; + GPR_ASSERT(status != GRPC_STATUS_OK); + if (op->cancel_with_status != GRPC_STATUS_OK || + op->close_with_status != GRPC_STATUS_OK) { + if (optional_message) { + gpr_slice_unref(*optional_message); + } + return; + } + if (optional_message) { + cmd = gpr_malloc(sizeof(*cmd)); + cmd->message = *optional_message; + cmd->then_call = op->on_consumed; + grpc_iomgr_closure_init(&cmd->closure, free_message, cmd); + op->on_consumed = &cmd->closure; + op->optional_close_message = &cmd->message; + } + op->close_with_status = status; +} diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 7efcfcf970c..92c1f38c5ea 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -80,8 +80,14 @@ typedef struct grpc_transport_stream_op { grpc_pollset *bind_pollset; + /** If != GRPC_STATUS_OK, cancel this stream */ grpc_status_code cancel_with_status; + /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this + stream for both reading and writing */ + grpc_status_code close_with_status; + gpr_slice *optional_close_message; + /* Indexes correspond to grpc_context_index enum values */ grpc_call_context_element *context; } grpc_transport_stream_op; @@ -148,8 +154,11 @@ void grpc_transport_destroy_stream(grpc_transport *transport, void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op); void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status, - grpc_mdstr *message); + grpc_status_code status); + +void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, + grpc_status_code status, + gpr_slice *optional_message); char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index 7facb6997b3..48ea0a29d4b 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -535,7 +535,7 @@ static void test_request_with_server_rejecting_client_creds( (probably in the server_auth_context.c code) where this error on the server does not get to the client. The current error code we are getting is GRPC_STATUS_INTERNAL. */ - GPR_ASSERT(status != GRPC_STATUS_OK); + GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED); grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv); From 4e03be38da1705fc8b232b5e69b9b99941c2c7d6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Aug 2015 10:56:00 -0700 Subject: [PATCH 011/117] Disabled deprecation warnings in Node build --- src/node/binding.gyp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/binding.gyp b/src/node/binding.gyp index 6ba233388ae..734dc8410b5 100644 --- a/src/node/binding.gyp +++ b/src/node/binding.gyp @@ -11,7 +11,8 @@ '-pedantic', '-g', '-zdefs', - '-Werror' + '-Werror', + '-Wno-error=deprecated-declarations' ], 'ldflags': [ '-g' From 3f507d074c1f44494717282bf294764ff96e239d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Aug 2015 15:17:53 -0700 Subject: [PATCH 012/117] Exposed host parameter in Call constructor, don't save it in Channel object --- src/node/ext/call.cc | 14 ++++++++++++-- src/node/ext/channel.cc | 25 ++++++------------------- src/node/ext/channel.h | 6 +----- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index dc45c8d8aec..ab177e85137 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -510,9 +510,19 @@ NAN_METHOD(Call::New) { NanUtf8String method(args[1]); double deadline = args[2]->NumberValue(); grpc_channel *wrapped_channel = channel->GetWrappedChannel(); - grpc_call *wrapped_call = grpc_channel_create_call( + grpc_call *wrapped_call; + if (args[3]->IsString()) { + NanUtf8String host_override(args[3]); + wrapped_call = grpc_channel_create_call( wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method, - channel->GetHost(), MillisecondsToTimespec(deadline)); + *host_override, MillisecondsToTimespec(deadline)); + } else if (args[3]->IsUndefined() || args[3]->IsNull()) { + wrapped_call = grpc_channel_create_call( + wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method, + NULL, MillisecondsToTimespec(deadline)); + } else { + return NanThrowTypeError("Call's fourth argument must be a string"); + } call = new Call(wrapped_call); args.This()->SetHiddenValue(NanNew("channel_"), channel_object); } diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index d02ed956724..457a58c0577 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -59,14 +59,12 @@ using v8::Value; NanCallback *Channel::constructor; Persistent Channel::fun_tpl; -Channel::Channel(grpc_channel *channel, NanUtf8String *host) - : wrapped_channel(channel), host(host) {} +Channel::Channel(grpc_channel *channel) : wrapped_channel(channel) {} Channel::~Channel() { if (wrapped_channel != NULL) { grpc_channel_destroy(wrapped_channel); } - delete host; } void Channel::Init(Handle exports) { @@ -91,8 +89,6 @@ bool Channel::HasInstance(Handle val) { grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } -char *Channel::GetHost() { return **this->host; } - NAN_METHOD(Channel::New) { NanScope(); @@ -103,8 +99,7 @@ NAN_METHOD(Channel::New) { } grpc_channel *wrapped_channel; // Owned by the Channel object - NanUtf8String *host = new NanUtf8String(args[0]); - NanUtf8String *host_override = NULL; + NanUtf8String host(args[0]); grpc_credentials *creds; if (!Credentials::HasInstance(args[1])) { return NanThrowTypeError( @@ -116,12 +111,9 @@ NAN_METHOD(Channel::New) { grpc_channel_args *channel_args_ptr; if (args[2]->IsUndefined()) { channel_args_ptr = NULL; - wrapped_channel = grpc_insecure_channel_create(**host, NULL); + wrapped_channel = grpc_insecure_channel_create(*host, NULL); } else if (args[2]->IsObject()) { Handle args_hash(args[2]->ToObject()->Clone()); - if (args_hash->HasOwnProperty(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))) { - host_override = new NanUtf8String(args_hash->Get(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))); - } Handle keys(args_hash->GetOwnPropertyNames()); grpc_channel_args channel_args; channel_args.num_args = keys->Length(); @@ -153,20 +145,15 @@ NAN_METHOD(Channel::New) { return NanThrowTypeError("Channel expects a string and an object"); } if (creds == NULL) { - wrapped_channel = grpc_insecure_channel_create(**host, channel_args_ptr); + wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr); } else { wrapped_channel = - grpc_secure_channel_create(creds, **host, channel_args_ptr); + grpc_secure_channel_create(creds, *host, channel_args_ptr); } if (channel_args_ptr != NULL) { free(channel_args_ptr->args); } - Channel *channel; - if (host_override == NULL) { - channel = new Channel(wrapped_channel, host); - } else { - channel = new Channel(wrapped_channel, host_override); - } + Channel *channel = new Channel(wrapped_channel); channel->Wrap(args.This()); NanReturnValue(args.This()); } else { diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h index 6725ebb03f0..e2182cb45c9 100644 --- a/src/node/ext/channel.h +++ b/src/node/ext/channel.h @@ -53,11 +53,8 @@ class Channel : public ::node::ObjectWrap { /* Returns the grpc_channel struct that this object wraps */ grpc_channel *GetWrappedChannel(); - /* Return the hostname that this channel connects to */ - char *GetHost(); - private: - explicit Channel(grpc_channel *channel, NanUtf8String *host); + explicit Channel(grpc_channel *channel); ~Channel(); // Prevent copying @@ -71,7 +68,6 @@ class Channel : public ::node::ObjectWrap { static v8::Persistent fun_tpl; grpc_channel *wrapped_channel; - NanUtf8String *host; }; } // namespace node From a16b5ef455c63a18929b4ef90945e90f01c1fd58 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Aug 2015 15:18:23 -0700 Subject: [PATCH 013/117] Added host override option for RPCs. Added optional params object --- src/node/examples/perf_test.js | 2 +- src/node/interop/interop_client.js | 3 +- src/node/src/client.js | 59 ++++++++++++++++-------------- src/node/test/call_test.js | 5 +++ src/node/test/end_to_end_test.js | 8 ---- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/node/examples/perf_test.js b/src/node/examples/perf_test.js index 0f38725f72c..214b9384d55 100644 --- a/src/node/examples/perf_test.js +++ b/src/node/examples/perf_test.js @@ -63,7 +63,7 @@ function runTest(iterations, callback) { var timeDiff = process.hrtime(startTime); intervals[i] = timeDiff[0] * 1000000 + timeDiff[1] / 1000; next(i+1); - }, {}, deadline); + }, {}, {deadline: deadline}); } } next(0); diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 236b36616cb..68f474777da 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -268,7 +268,7 @@ function cancelAfterFirstResponse(client, done) { function timeoutOnSleepingServer(client, done) { var deadline = new Date(); deadline.setMilliseconds(deadline.getMilliseconds() + 1); - var call = client.fullDuplexCall(null, deadline); + var call = client.fullDuplexCall(null, {deadline: deadline}); call.write({ payload: {body: zeroBuffer(27182)} }); @@ -409,6 +409,7 @@ function runTest(address, host_override, test_case, tls, test_ca, done) { creds = grpc.Credentials.createSsl(ca_data); if (host_override) { options['grpc.ssl_target_name_override'] = host_override; + options['grpc.default_authority'] = host_override; } } else { creds = grpc.Credentials.createInsecure(); diff --git a/src/node/src/client.js b/src/node/src/client.js index b2b44237074..87c7690dc07 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -207,6 +207,25 @@ ClientReadableStream.prototype.getPeer = getPeer; ClientWritableStream.prototype.getPeer = getPeer; ClientDuplexStream.prototype.getPeer = getPeer; +/** + * Get a call object built with the provided options. Keys for options are + * 'deadline', which takes a date or number, and 'host', which takes a string + * and overrides the hostname to connect to. + * @param {Object} options Options map. + */ +function getCall(channel, method, options) { + var deadline; + var host; + if (options) { + deadline = options.deadline; + host = options.host; + } + if (deadline === undefined) { + deadline = Infinity; + } + return new grpc.Call(channel, method, deadline, host); +} + /** * Get a function that can make unary requests to the specified method. * @param {string} method The name of the method to request @@ -226,17 +245,13 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { * response is received * @param {array=} metadata Array of metadata key/value pairs to add to the * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future + * @param {Object=} options Options map * @return {EventEmitter} An event emitter for stream related events */ - function makeUnaryRequest(argument, callback, metadata, deadline) { + function makeUnaryRequest(argument, callback, metadata, options) { /* jshint validthis: true */ - if (deadline === undefined) { - deadline = Infinity; - } var emitter = new EventEmitter(); - var call = new grpc.Call(this.channel, method, deadline); + var call = getCall(this.channel, method, options); if (metadata === null || metadata === undefined) { metadata = {}; } @@ -300,16 +315,12 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) { * response is received * @param {array=} metadata Array of metadata key/value pairs to add to the * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future + * @param {Object=} options Options map * @return {EventEmitter} An event emitter for stream related events */ - function makeClientStreamRequest(callback, metadata, deadline) { + function makeClientStreamRequest(callback, metadata, options) { /* jshint validthis: true */ - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(this.channel, method, deadline); + var call = getCall(this.channel, method, options); if (metadata === null || metadata === undefined) { metadata = {}; } @@ -374,16 +385,12 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { * serialize * @param {array=} metadata Array of metadata key/value pairs to add to the * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future + * @param {Object} options Options map * @return {EventEmitter} An event emitter for stream related events */ - function makeServerStreamRequest(argument, metadata, deadline) { + function makeServerStreamRequest(argument, metadata, options) { /* jshint validthis: true */ - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(this.channel, method, deadline); + var call = getCall(this.channel, method, options); if (metadata === null || metadata === undefined) { metadata = {}; } @@ -446,16 +453,12 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) { * @this {SurfaceClient} Client object. Must have a channel member. * @param {array=} metadata Array of metadata key/value pairs to add to the * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future + * @param {Options} options Options map * @return {EventEmitter} An event emitter for stream related events */ - function makeBidiStreamRequest(metadata, deadline) { + function makeBidiStreamRequest(metadata, options) { /* jshint validthis: true */ - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(this.channel, method, deadline); + var call = getCall(this.channel, method, options); if (metadata === null || metadata === undefined) { metadata = {}; } diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 48d859a8ece..8d0f20b0747 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -84,6 +84,11 @@ describe('call', function() { new grpc.Call(channel, 'method', 0); }); }); + it('should accept an optional fourth string parameter', function() { + assert.doesNotThrow(function() { + new grpc.Call(channel, 'method', new Date(), 'host_override'); + }); + }); it('should fail with a closed channel', function() { var local_channel = new grpc.Channel('hostname', insecureCreds); local_channel.close(); diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js index ea41dfc28cd..7574d98b8af 100644 --- a/src/node/test/end_to_end_test.js +++ b/src/node/test/end_to_end_test.js @@ -74,8 +74,6 @@ describe('end-to-end', function() { }); it('should start and end a request without error', function(complete) { var done = multiDone(complete, 2); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', @@ -126,8 +124,6 @@ describe('end-to-end', function() { }); it('should successfully send and receive metadata', function(complete) { var done = multiDone(complete, 2); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', @@ -184,8 +180,6 @@ describe('end-to-end', function() { var req_text = 'client_request'; var reply_text = 'server_response'; var done = multiDone(complete, 2); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'success'; var call = new grpc.Call(channel, 'dummy_method', @@ -241,8 +235,6 @@ describe('end-to-end', function() { it('should send multiple messages', function(complete) { var done = multiDone(complete, 2); var requests = ['req1', 'req2']; - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', From 8e9ff222999199f88344bbb9b4cee3bfc7de433f Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Mon, 3 Aug 2015 15:49:14 -0700 Subject: [PATCH 014/117] Removing obsolete comment. --- .../tests/request_response_with_payload_and_call_creds.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index 48ea0a29d4b..2166bd41f71 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -531,10 +531,6 @@ static void test_request_with_server_rejecting_client_creds( cq_expect_completion(cqv, tag(1), 1); cq_verify(cqv); - /* XXX Should be GRPC_STATUS_UNAUTHENTICATED but it looks like there is a bug - (probably in the server_auth_context.c code) where this error on the server - does not get to the client. The current error code we are getting is - GRPC_STATUS_INTERNAL. */ GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED); grpc_metadata_array_destroy(&initial_metadata_recv); From f53d9c8d0d7264d9f2f591153670dddf92d9b4a6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 4 Aug 2015 14:19:43 -0700 Subject: [PATCH 015/117] Testing port server run_tests.py will start a server (if it's not running, or if the running port server mismatches the 'current' one) that serves ports to use for tests. The server is left running after run_tests.py finishes, so that in environments such as Mac and Windows where tests run unshielded from each other, we don't start jumping on already used ports. --- BUILD | 32 +++--- Makefile | 12 +- build.json | 13 +-- gRPC.podspec | 20 ++-- src/core/httpcli/httpcli.c | 71 +++++------- src/core/httpcli/httpcli.h | 14 ++- src/core/httpcli/httpcli_security_connector.c | 49 +++++++- src/core/httpcli/httpcli_security_connector.h | 43 ------- src/core/security/credentials.c | 4 +- src/core/security/jwt_verifier.c | 4 +- test/core/httpcli/httpcli_test.c | 4 +- test/core/security/credentials_test.c | 6 +- test/core/security/jwt_verifier_test.c | 10 +- test/core/util/port_posix.c | 66 +++++++++++ tools/doxygen/Doxyfile.core.internal | 13 +-- tools/run_tests/jobset.py | 28 ++--- tools/run_tests/port_server.py | 105 ++++++++++++++++++ tools/run_tests/run_tests.py | 46 +++++++- tools/run_tests/sources_and_headers.json | 11 +- vsprojects/grpc/grpc.vcxproj | 19 ++-- vsprojects/grpc/grpc.vcxproj.filters | 39 +++---- .../grpc_unsecure/grpc_unsecure.vcxproj | 9 ++ .../grpc_unsecure.vcxproj.filters | 21 ++++ 23 files changed, 442 insertions(+), 197 deletions(-) delete mode 100644 src/core/httpcli/httpcli_security_connector.h create mode 100755 tools/run_tests/port_server.py diff --git a/BUILD b/BUILD index 9c170f1d5eb..8672d7f9423 100644 --- a/BUILD +++ b/BUILD @@ -132,10 +132,6 @@ cc_library( cc_library( name = "grpc", srcs = [ - "src/core/httpcli/format_request.h", - "src/core/httpcli/httpcli.h", - "src/core/httpcli/httpcli_security_connector.h", - "src/core/httpcli/parser.h", "src/core/security/auth_filters.h", "src/core/security/base64.h", "src/core/security/credentials.h", @@ -175,6 +171,9 @@ cc_library( "src/core/client_config/uri_parser.h", "src/core/compression/message_compress.h", "src/core/debug/trace.h", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", "src/core/iomgr/alarm_internal.h", @@ -248,10 +247,7 @@ cc_library( "src/core/transport/transport_impl.h", "src/core/census/context.h", "src/core/census/rpc_stat_id.h", - "src/core/httpcli/format_request.c", - "src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli_security_connector.c", - "src/core/httpcli/parser.c", "src/core/security/base64.c", "src/core/security/client_auth_filter.c", "src/core/security/credentials.c", @@ -298,6 +294,9 @@ cc_library( "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", "src/core/debug/trace.c", + "src/core/httpcli/format_request.c", + "src/core/httpcli/httpcli.c", + "src/core/httpcli/parser.c", "src/core/iomgr/alarm.c", "src/core/iomgr/alarm_heap.c", "src/core/iomgr/endpoint.c", @@ -437,6 +436,9 @@ cc_library( "src/core/client_config/uri_parser.h", "src/core/compression/message_compress.h", "src/core/debug/trace.h", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", "src/core/iomgr/alarm_internal.h", @@ -537,6 +539,9 @@ cc_library( "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", "src/core/debug/trace.c", + "src/core/httpcli/format_request.c", + "src/core/httpcli/httpcli.c", + "src/core/httpcli/parser.c", "src/core/iomgr/alarm.c", "src/core/iomgr/alarm_heap.c", "src/core/iomgr/endpoint.c", @@ -973,10 +978,7 @@ objc_library( objc_library( name = "grpc_objc", srcs = [ - "src/core/httpcli/format_request.c", - "src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli_security_connector.c", - "src/core/httpcli/parser.c", "src/core/security/base64.c", "src/core/security/client_auth_filter.c", "src/core/security/credentials.c", @@ -1023,6 +1025,9 @@ objc_library( "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", "src/core/debug/trace.c", + "src/core/httpcli/format_request.c", + "src/core/httpcli/httpcli.c", + "src/core/httpcli/parser.c", "src/core/iomgr/alarm.c", "src/core/iomgr/alarm_heap.c", "src/core/iomgr/endpoint.c", @@ -1121,10 +1126,6 @@ objc_library( "include/grpc/grpc.h", "include/grpc/status.h", "include/grpc/census.h", - "src/core/httpcli/format_request.h", - "src/core/httpcli/httpcli.h", - "src/core/httpcli/httpcli_security_connector.h", - "src/core/httpcli/parser.h", "src/core/security/auth_filters.h", "src/core/security/base64.h", "src/core/security/credentials.h", @@ -1164,6 +1165,9 @@ objc_library( "src/core/client_config/uri_parser.h", "src/core/compression/message_compress.h", "src/core/debug/trace.h", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", "src/core/iomgr/alarm_internal.h", diff --git a/Makefile b/Makefile index 8a38a689f99..0042ffa056a 100644 --- a/Makefile +++ b/Makefile @@ -3698,10 +3698,7 @@ endif LIBGRPC_SRC = \ - src/core/httpcli/format_request.c \ - src/core/httpcli/httpcli.c \ src/core/httpcli/httpcli_security_connector.c \ - src/core/httpcli/parser.c \ src/core/security/base64.c \ src/core/security/client_auth_filter.c \ src/core/security/credentials.c \ @@ -3748,6 +3745,9 @@ LIBGRPC_SRC = \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ src/core/debug/trace.c \ + src/core/httpcli/format_request.c \ + src/core/httpcli/httpcli.c \ + src/core/httpcli/parser.c \ src/core/iomgr/alarm.c \ src/core/iomgr/alarm_heap.c \ src/core/iomgr/endpoint.c \ @@ -4016,6 +4016,9 @@ LIBGRPC_UNSECURE_SRC = \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ src/core/debug/trace.c \ + src/core/httpcli/format_request.c \ + src/core/httpcli/httpcli.c \ + src/core/httpcli/parser.c \ src/core/iomgr/alarm.c \ src/core/iomgr/alarm_heap.c \ src/core/iomgr/endpoint.c \ @@ -18680,10 +18683,7 @@ ifneq ($(OPENSSL_DEP),) # This is to ensure the embedded OpenSSL is built beforehand, properly # installing headers to their final destination on the drive. We need this # otherwise parallel compilation will fail if a source is compiled first. -src/core/httpcli/format_request.c: $(OPENSSL_DEP) -src/core/httpcli/httpcli.c: $(OPENSSL_DEP) src/core/httpcli/httpcli_security_connector.c: $(OPENSSL_DEP) -src/core/httpcli/parser.c: $(OPENSSL_DEP) src/core/security/base64.c: $(OPENSSL_DEP) src/core/security/client_auth_filter.c: $(OPENSSL_DEP) src/core/security/credentials.c: $(OPENSSL_DEP) diff --git a/build.json b/build.json index deb86404226..d1405054add 100644 --- a/build.json +++ b/build.json @@ -140,6 +140,9 @@ "src/core/client_config/uri_parser.h", "src/core/compression/message_compress.h", "src/core/debug/trace.h", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", "src/core/iomgr/alarm_internal.h", @@ -239,6 +242,9 @@ "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", "src/core/debug/trace.c", + "src/core/httpcli/format_request.c", + "src/core/httpcli/httpcli.c", + "src/core/httpcli/parser.c", "src/core/iomgr/alarm.c", "src/core/iomgr/alarm_heap.c", "src/core/iomgr/endpoint.c", @@ -461,10 +467,6 @@ "include/grpc/grpc_security.h" ], "headers": [ - "src/core/httpcli/format_request.h", - "src/core/httpcli/httpcli.h", - "src/core/httpcli/httpcli_security_connector.h", - "src/core/httpcli/parser.h", "src/core/security/auth_filters.h", "src/core/security/base64.h", "src/core/security/credentials.h", @@ -480,10 +482,7 @@ "src/core/tsi/transport_security_interface.h" ], "src": [ - "src/core/httpcli/format_request.c", - "src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli_security_connector.c", - "src/core/httpcli/parser.c", "src/core/security/base64.c", "src/core/security/client_auth_filter.c", "src/core/security/credentials.c", diff --git a/gRPC.podspec b/gRPC.podspec index 632f1ad4e4c..31c8ee40744 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -134,10 +134,6 @@ Pod::Spec.new do |s| 'src/core/support/time_posix.c', 'src/core/support/time_win32.c', 'src/core/support/tls_pthread.c', - 'src/core/httpcli/format_request.h', - 'src/core/httpcli/httpcli.h', - 'src/core/httpcli/httpcli_security_connector.h', - 'src/core/httpcli/parser.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', @@ -177,6 +173,9 @@ Pod::Spec.new do |s| 'src/core/client_config/uri_parser.h', 'src/core/compression/message_compress.h', 'src/core/debug/trace.h', + 'src/core/httpcli/format_request.h', + 'src/core/httpcli/httpcli.h', + 'src/core/httpcli/parser.h', 'src/core/iomgr/alarm.h', 'src/core/iomgr/alarm_heap.h', 'src/core/iomgr/alarm_internal.h', @@ -257,10 +256,7 @@ Pod::Spec.new do |s| 'grpc/grpc.h', 'grpc/status.h', 'grpc/census.h', - 'src/core/httpcli/format_request.c', - 'src/core/httpcli/httpcli.c', 'src/core/httpcli/httpcli_security_connector.c', - 'src/core/httpcli/parser.c', 'src/core/security/base64.c', 'src/core/security/client_auth_filter.c', 'src/core/security/credentials.c', @@ -307,6 +303,9 @@ Pod::Spec.new do |s| 'src/core/compression/algorithm.c', 'src/core/compression/message_compress.c', 'src/core/debug/trace.c', + 'src/core/httpcli/format_request.c', + 'src/core/httpcli/httpcli.c', + 'src/core/httpcli/parser.c', 'src/core/iomgr/alarm.c', 'src/core/iomgr/alarm_heap.c', 'src/core/iomgr/endpoint.c', @@ -404,10 +403,6 @@ Pod::Spec.new do |s| 'src/core/support/string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', - 'src/core/httpcli/format_request.h', - 'src/core/httpcli/httpcli.h', - 'src/core/httpcli/httpcli_security_connector.h', - 'src/core/httpcli/parser.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', @@ -447,6 +442,9 @@ Pod::Spec.new do |s| 'src/core/client_config/uri_parser.h', 'src/core/compression/message_compress.h', 'src/core/debug/trace.h', + 'src/core/httpcli/format_request.h', + 'src/core/httpcli/httpcli.h', + 'src/core/httpcli/parser.h', 'src/core/iomgr/alarm.h', 'src/core/iomgr/alarm_heap.h', 'src/core/iomgr/alarm_internal.h', diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index 65997d5f44b..bf5cbfcfba1 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -40,7 +40,6 @@ #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/httpcli/format_request.h" -#include "src/core/httpcli/httpcli_security_connector.h" #include "src/core/httpcli/parser.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" @@ -57,7 +56,7 @@ typedef struct { char *host; gpr_timespec deadline; int have_read_byte; - int use_ssl; + const grpc_httpcli_handshaker *handshaker; grpc_httpcli_response_cb on_response; void *user_data; grpc_httpcli_context *context; @@ -68,6 +67,16 @@ typedef struct { static grpc_httpcli_get_override g_get_override = NULL; static grpc_httpcli_post_override g_post_override = NULL; +static void plaintext_handshake(void *arg, grpc_endpoint *endpoint, + const char *host, + void (*on_done)(void *arg, + grpc_endpoint *endpoint)) { + on_done(arg, endpoint); +} + +const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", + plaintext_handshake}; + void grpc_httpcli_context_init(grpc_httpcli_context *context) { grpc_pollset_set_init(&context->pollset_set); } @@ -163,18 +172,16 @@ static void start_write(internal_request *req) { } } -static void on_secure_transport_setup_done(void *rp, - grpc_security_status status, - grpc_endpoint *wrapped_endpoint, - grpc_endpoint *secure_endpoint) { - internal_request *req = rp; - if (status != GRPC_SECURITY_OK) { - gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); - finish(req, 0); - } else { - req->ep = secure_endpoint; - start_write(req); +static void on_handshake_done(void *arg, grpc_endpoint *ep) { + internal_request *req = arg; + + if (!ep) { + next_address(req); + return; } + + req->ep = ep; + start_write(req); } static void on_connected(void *arg, grpc_endpoint *tcp) { @@ -184,25 +191,7 @@ static void on_connected(void *arg, grpc_endpoint *tcp) { next_address(req); return; } - req->ep = tcp; - if (req->use_ssl) { - grpc_channel_security_connector *sc = NULL; - const unsigned char *pem_root_certs = NULL; - size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { - gpr_log(GPR_ERROR, "Could not get default pem root certs."); - finish(req, 0); - return; - } - GPR_ASSERT(grpc_httpcli_ssl_channel_security_connector_create( - pem_root_certs, pem_root_certs_size, req->host, &sc) == - GRPC_SECURITY_OK); - grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done, - req); - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); - } else { - start_write(req); - } + req->handshaker->handshake(req, tcp, req->host, on_handshake_done); } static void next_address(internal_request *req) { @@ -245,18 +234,17 @@ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset, req->on_response = on_response; req->user_data = user_data; req->deadline = deadline; - req->use_ssl = request->use_ssl; + req->handshaker = + request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); - if (req->use_ssl) { - req->host = gpr_strdup(request->host); - } + req->host = gpr_strdup(request->host); grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset); - grpc_resolve_address(request->host, req->use_ssl ? "https" : "http", + grpc_resolve_address(request->host, req->handshaker->default_port, on_resolved, req); } @@ -279,18 +267,17 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset, req->on_response = on_response; req->user_data = user_data; req->deadline = deadline; - req->use_ssl = request->use_ssl; + req->handshaker = + request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); - if (req->use_ssl) { - req->host = gpr_strdup(request->host); - } + req->host = gpr_strdup(request->host); grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset); - grpc_resolve_address(request->host, req->use_ssl ? "https" : "http", + grpc_resolve_address(request->host, req->handshaker->default_port, on_resolved, req); } diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h index ab98178f8a4..c45966714cd 100644 --- a/src/core/httpcli/httpcli.h +++ b/src/core/httpcli/httpcli.h @@ -38,6 +38,7 @@ #include +#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/pollset_set.h" /* User agent this library reports */ @@ -58,6 +59,15 @@ typedef struct grpc_httpcli_context { grpc_pollset_set pollset_set; } grpc_httpcli_context; +typedef struct { + const char *default_port; + void (*handshake)(void *arg, grpc_endpoint *endpoint, const char *host, + void (*on_done)(void *arg, grpc_endpoint *endpoint)); +} grpc_httpcli_handshaker; + +extern const grpc_httpcli_handshaker grpc_httpcli_plaintext; +extern const grpc_httpcli_handshaker grpc_httpcli_ssl; + /* A request */ typedef struct grpc_httpcli_request { /* The host name to connect to */ @@ -69,8 +79,8 @@ typedef struct grpc_httpcli_request { Host, Connection, User-Agent */ size_t hdr_count; grpc_httpcli_header *hdrs; - /* whether to use ssl for the request */ - int use_ssl; + /* handshaker to use ssl for the request */ + const grpc_httpcli_handshaker *handshaker; } grpc_httpcli_request; /* A response */ diff --git a/src/core/httpcli/httpcli_security_connector.c b/src/core/httpcli/httpcli_security_connector.c index ce0d3d5a709..7887f9d5304 100644 --- a/src/core/httpcli/httpcli_security_connector.c +++ b/src/core/httpcli/httpcli_security_connector.c @@ -31,7 +31,7 @@ * */ -#include "src/core/httpcli/httpcli_security_connector.h" +#include "src/core/httpcli/httpcli.h" #include @@ -96,7 +96,7 @@ static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc, static grpc_security_connector_vtable httpcli_ssl_vtable = { httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer}; -grpc_security_status grpc_httpcli_ssl_channel_security_connector_create( +static grpc_security_status httpcli_ssl_channel_security_connector_create( const unsigned char *pem_root_certs, size_t pem_root_certs_size, const char *secure_peer_name, grpc_channel_security_connector **sc) { tsi_result result = TSI_OK; @@ -130,3 +130,48 @@ grpc_security_status grpc_httpcli_ssl_channel_security_connector_create( *sc = &c->base; return GRPC_SECURITY_OK; } + +/* handshaker */ + +typedef struct { + void (*func)(void *arg, grpc_endpoint *endpoint); + void *arg; +} on_done_closure; + +static void on_secure_transport_setup_done(void *rp, + grpc_security_status status, + grpc_endpoint *wrapped_endpoint, + grpc_endpoint *secure_endpoint) { + on_done_closure *c = rp; + if (status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); + c->func(c->arg, NULL); + } else { + c->func(c->arg, secure_endpoint); + } + gpr_free(c); +} + +static void ssl_handshake(void *arg, grpc_endpoint *tcp, const char *host, + void (*on_done)(void *arg, grpc_endpoint *endpoint)) { + grpc_channel_security_connector *sc = NULL; + const unsigned char *pem_root_certs = NULL; + on_done_closure *c = gpr_malloc(sizeof(*c)); + size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); + if (pem_root_certs == NULL || pem_root_certs_size == 0) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + on_done(arg, NULL); + gpr_free(c); + return; + } + c->func = on_done; + c->arg = arg; + GPR_ASSERT(httpcli_ssl_channel_security_connector_create( + pem_root_certs, pem_root_certs_size, host, &sc) == + GRPC_SECURITY_OK); + grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done, + c); + GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); +} + +const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; diff --git a/src/core/httpcli/httpcli_security_connector.h b/src/core/httpcli/httpcli_security_connector.h deleted file mode 100644 index c50f25905e6..00000000000 --- a/src/core/httpcli/httpcli_security_connector.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H -#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H - -#include "src/core/security/security_connector.h" - -grpc_security_status grpc_httpcli_ssl_channel_security_connector_create( - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *secure_peer_name, grpc_channel_security_connector **sc); - -#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H */ diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 15268cefbe2..c45b5c065d1 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -679,7 +679,7 @@ static void service_account_fetch_oauth2( request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; - request.use_ssl = 1; + request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); gpr_free(body); @@ -738,7 +738,7 @@ static void refresh_token_fetch_oauth2( request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; - request.use_ssl = 1; + request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); gpr_free(body); diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c index 1276693da7f..38ad134a6ab 100644 --- a/src/core/security/jwt_verifier.c +++ b/src/core/security/jwt_verifier.c @@ -628,7 +628,7 @@ static void on_openid_config_retrieved(void *user_data, goto error; } jwks_uri += 8; - req.use_ssl = 1; + req.handshaker = &grpc_httpcli_ssl; req.host = gpr_strdup(jwks_uri); req.path = strchr(jwks_uri, '/'); if (req.path == NULL) { @@ -685,7 +685,7 @@ static void retrieve_key_and_verify(verifier_cb_ctx *ctx) { const char *iss; grpc_httpcli_request req; memset(&req, 0, sizeof(grpc_httpcli_request)); - req.use_ssl = 1; + req.handshaker = &grpc_httpcli_ssl; GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL); iss = ctx->claims->iss; diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c index 4801eb3e39a..034501ee696 100644 --- a/test/core/httpcli/httpcli_test.c +++ b/test/core/httpcli/httpcli_test.c @@ -81,7 +81,7 @@ static void test_get(int use_ssl, int port) { memset(&req, 0, sizeof(req)); req.host = host; req.path = "/get"; - req.use_ssl = use_ssl; + req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; grpc_httpcli_get(&g_context, &g_pollset, &req, n_seconds_time(15), on_finish, (void *)42); @@ -106,7 +106,7 @@ static void test_post(int use_ssl, int port) { memset(&req, 0, sizeof(req)); req.host = host; req.path = "/post"; - req.use_ssl = use_ssl; + req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; grpc_httpcli_post(&g_context, &g_pollset, &req, "hello", 5, n_seconds_time(15), on_finish, (void *)42); diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index dd6e0d7bb3c..a0c9445f195 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -477,7 +477,7 @@ static void on_oauth2_creds_get_metadata_failure( static void validate_compute_engine_http_request( const grpc_httpcli_request *request) { - GPR_ASSERT(!request->use_ssl); + GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, "metadata") == 0); GPR_ASSERT( strcmp(request->path, @@ -573,7 +573,7 @@ static void validate_refresh_token_http_request( GPR_ASSERT(strlen(expected_body) == body_size); GPR_ASSERT(memcmp(expected_body, body, body_size) == 0); gpr_free(expected_body); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0); GPR_ASSERT(strcmp(request->path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0); GPR_ASSERT(request->hdr_count == 1); @@ -697,7 +697,7 @@ static void validate_service_account_http_request( GPR_ASSERT(strlen(expected_body) == body_size); GPR_ASSERT(memcmp(expected_body, body, body_size) == 0); gpr_free(expected_body); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0); GPR_ASSERT(strcmp(request->path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0); GPR_ASSERT(request->hdr_count == 1); diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c index 98db56c0efd..440286ea1a6 100644 --- a/test/core/security/jwt_verifier_test.c +++ b/test/core/security/jwt_verifier_test.c @@ -286,7 +286,7 @@ static int httpcli_get_google_keys_for_email( const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data) { grpc_httpcli_response response = http_response(200, good_google_email_keys()); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); GPR_ASSERT(strcmp(request->path, "/robot/v1/metadata/x509/" @@ -331,7 +331,7 @@ static int httpcli_get_custom_keys_for_email( const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data) { grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set)); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0); GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0); on_response(user_data, &response); @@ -363,7 +363,7 @@ static int httpcli_get_jwk_set( const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data) { grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set)); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0); on_response(user_data, &response); @@ -377,7 +377,7 @@ static int httpcli_get_openid_config(const grpc_httpcli_request *request, void *user_data) { grpc_httpcli_response response = http_response(200, gpr_strdup(good_openid_config)); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0); GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0); grpc_httpcli_set_override(httpcli_get_jwk_set, @@ -421,7 +421,7 @@ static int httpcli_get_bad_json(const grpc_httpcli_request *request, void *user_data) { grpc_httpcli_response response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}")); - GPR_ASSERT(request->use_ssl); + GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); on_response(user_data, &response); gpr_free(response.body); return 1; diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c index b07df391f9a..715e4582628 100644 --- a/test/core/util/port_posix.c +++ b/test/core/util/port_posix.c @@ -44,9 +44,13 @@ #include #include +#include #include #include +#include "src/core/httpcli/httpcli.h" +#include "src/core/support/env.h" + #define NUM_RANDOM_PORTS_TO_PICK 100 static int *chosen_ports = NULL; @@ -126,6 +130,59 @@ static int is_port_available(int *port, int is_tcp) { return 1; } +typedef struct portreq { + grpc_pollset pollset; + int port; +} portreq; + +static void got_port_from_server(void *arg, + const grpc_httpcli_response *response) { + size_t i; + int port = 0; + portreq *pr = arg; + GPR_ASSERT(response); + GPR_ASSERT(response->status == 200); + for (i = 0; i < response->body_length; i++) { + GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9'); + port = port * 10 + response->body[i] - '0'; + } + GPR_ASSERT(port > 1024); + gpr_mu_lock(GRPC_POLLSET_MU(&pr->pollset)); + pr->port = port; + grpc_pollset_kick(&pr->pollset); + gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset)); +} + +static int pick_port_using_server(char *server) { + grpc_httpcli_context context; + grpc_httpcli_request req; + portreq pr; + + grpc_init(); + + memset(&pr, 0, sizeof(pr)); + memset(&req, 0, sizeof(req)); + grpc_pollset_init(&pr.pollset); + pr.port = -1; + + req.host = server; + req.path = "/get"; + + grpc_httpcli_context_init(&context); + grpc_httpcli_get(&context, &pr.pollset, &req, + GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server, + &pr); + gpr_mu_lock(GRPC_POLLSET_MU(&pr.pollset)); + while (pr.port == -1) { + grpc_pollset_work(&pr.pollset, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1)); + } + gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset)); + + grpc_shutdown(); + + return pr.port; +} + int grpc_pick_unused_port(void) { /* We repeatedly pick a port and then see whether or not it is available for use both as a TCP socket and a UDP socket. First, we @@ -143,6 +200,15 @@ int grpc_pick_unused_port(void) { int is_tcp = 1; int try = 0; + char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); + if (env) { + int port = pick_port_using_server(env); + gpr_free(env); + if (port != 0) { + return port; + } + } + for (;;) { int port; try++; diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index cce0b6fed08..abe1f72d361 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -767,10 +767,6 @@ include/grpc/compression.h \ include/grpc/grpc.h \ include/grpc/status.h \ include/grpc/census.h \ -src/core/httpcli/format_request.h \ -src/core/httpcli/httpcli.h \ -src/core/httpcli/httpcli_security_connector.h \ -src/core/httpcli/parser.h \ src/core/security/auth_filters.h \ src/core/security/base64.h \ src/core/security/credentials.h \ @@ -810,6 +806,9 @@ src/core/client_config/subchannel_factory_decorators/merge_channel_args.h \ src/core/client_config/uri_parser.h \ src/core/compression/message_compress.h \ src/core/debug/trace.h \ +src/core/httpcli/format_request.h \ +src/core/httpcli/httpcli.h \ +src/core/httpcli/parser.h \ src/core/iomgr/alarm.h \ src/core/iomgr/alarm_heap.h \ src/core/iomgr/alarm_internal.h \ @@ -883,10 +882,7 @@ src/core/transport/transport.h \ src/core/transport/transport_impl.h \ src/core/census/context.h \ src/core/census/rpc_stat_id.h \ -src/core/httpcli/format_request.c \ -src/core/httpcli/httpcli.c \ src/core/httpcli/httpcli_security_connector.c \ -src/core/httpcli/parser.c \ src/core/security/base64.c \ src/core/security/client_auth_filter.c \ src/core/security/credentials.c \ @@ -933,6 +929,9 @@ src/core/client_config/uri_parser.c \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ src/core/debug/trace.c \ +src/core/httpcli/format_request.c \ +src/core/httpcli/httpcli.c \ +src/core/httpcli/parser.c \ src/core/iomgr/alarm.c \ src/core/iomgr/alarm_heap.c \ src/core/iomgr/endpoint.c \ diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py index ec25b476102..0318e357b8d 100755 --- a/tools/run_tests/jobset.py +++ b/tools/run_tests/jobset.py @@ -162,13 +162,15 @@ class JobSpec(object): class Job(object): """Manages one job.""" - def __init__(self, spec, bin_hash, newline_on_success, travis, xml_report): + def __init__(self, spec, bin_hash, newline_on_success, travis, add_env, xml_report): self._spec = spec self._bin_hash = bin_hash self._tempfile = tempfile.TemporaryFile() env = os.environ.copy() for k, v in spec.environ.iteritems(): env[k] = v + for k, v in add_env.iteritems(): + env[k] = v self._start = time.time() self._process = subprocess.Popen(args=spec.cmdline, stderr=subprocess.STDOUT, @@ -227,7 +229,7 @@ class Jobset(object): """Manages one run of jobs.""" def __init__(self, check_cancelled, maxjobs, newline_on_success, travis, - stop_on_failure, cache, xml_report): + stop_on_failure, add_env, cache, xml_report): self._running = set() self._check_cancelled = check_cancelled self._cancelled = False @@ -240,6 +242,7 @@ class Jobset(object): self._stop_on_failure = stop_on_failure self._hashes = {} self._xml_report = xml_report + self._add_env = add_env def start(self, spec): """Start a job. Return True on success, False on failure.""" @@ -262,16 +265,12 @@ class Jobset(object): bin_hash = None should_run = True if should_run: - try: - self._running.add(Job(spec, - bin_hash, - self._newline_on_success, - self._travis, - self._xml_report)) - except: - message('FAILED', spec.shortname) - self._cancelled = True - return False + self._running.add(Job(spec, + bin_hash, + self._newline_on_success, + self._travis, + self._add_env, + self._xml_report)) return True def reap(self): @@ -342,10 +341,11 @@ def run(cmdlines, infinite_runs=False, stop_on_failure=False, cache=None, - xml_report=None): + xml_report=None, + add_env={}): js = Jobset(check_cancelled, maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS, - newline_on_success, travis, stop_on_failure, + newline_on_success, travis, stop_on_failure, add_env, cache if cache is not None else NoCache(), xml_report) for cmdline in cmdlines: diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py new file mode 100755 index 00000000000..41f862ad887 --- /dev/null +++ b/tools/run_tests/port_server.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Manage TCP ports for unit tests; started by run_tests.py""" + +import argparse +import BaseHTTPServer +import hashlib +import os +import socket +import sys +import time + +argp = argparse.ArgumentParser(description='Server for httpcli_test') +argp.add_argument('-p', '--port', default=12345, type=int) +args = argp.parse_args() + +print 'port server running on port %d' % args.port + +pool = [] +in_use = {} + +with open(sys.argv[0]) as f: + _MY_VERSION = hashlib.sha1(f.read()).hexdigest() + + +def refill_pool(): + """Scan for ports not marked for being in use""" + for i in range(10000, 65000): + if len(pool) > 100: break + if i in in_use: + age = time.time() - in_use[i] + if age < 600: + continue + del in_use[i] + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.bind(('localhost', i)) + pool.append(i) + except: + pass # we really don't care about failures + finally: + s.close() + + +def allocate_port(): + global pool + global in_use + if not pool: + refill_pool() + port = pool[0] + pool = pool[1:] + in_use[port] = time.time() + return port + + +class Handler(BaseHTTPServer.BaseHTTPRequestHandler): + + def do_GET(self): + if self.path == '/get': + # allocate a new port, it will stay bound for ten minutes and until + # it's unused + self.send_response(200) + self.send_header('Content-Type', 'text/plain') + self.end_headers() + p = allocate_port() + self.log_message('allocated port %d' % p) + self.wfile.write('%d' % p) + elif self.path == '/version_and_pid': + # fetch a version string and the current process pid + self.send_response(200) + self.send_header('Content-Type', 'text/plain') + self.end_headers() + self.wfile.write('%s+%d' % (_MY_VERSION, os.getpid())) + + +BaseHTTPServer.HTTPServer(('', args.port), Handler).serve_forever() + diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index fa749498d2f..653b98d57d3 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -32,17 +32,20 @@ import argparse import glob +import hashlib import itertools import json import multiprocessing import os import platform +import psutil import random import re import subprocess import sys import time import xml.etree.cElementTree as ET +import urllib2 import jobset import watch_dirs @@ -522,7 +525,43 @@ class TestCache(object): self.parse(json.loads(f.read())) -def _build_and_run(check_cancelled, newline_on_success, travis, cache, xml_report=None): +def _start_port_server(port_server_port): + # check if a compatible port server is running + # if incompatible (version mismatch) ==> start a new one + # if not running ==> start a new one + # otherwise, leave it up + try: + version, _, pid = urllib2.urlopen( + 'http://localhost:%d/version_and_pid' % port_server_port).read().partition('+') + running = True + except Exception: + running = False + if running: + with open('tools/run_tests/port_server.py') as f: + current_version = hashlib.sha1(f.read()).hexdigest() + running = (version == current_version) + if not running: + psutil.Process(int(pid)).terminate() + if not running: + port_log = open('portlog.txt', 'w') + port_server = subprocess.Popen( + ['tools/run_tests/port_server.py', '-p', '%d' % port_server_port], + stderr=subprocess.STDOUT, + stdout=port_log) + # ensure port server is up + while True: + try: + urllib2.urlopen('http://localhost:%d/get' % port_server_port).read() + break + except urllib2.URLError: + time.sleep(0.5) + except: + port_server.kill() + raise + + +def _build_and_run( + check_cancelled, newline_on_success, travis, cache, xml_report=None): """Do one pass of building & running tests.""" # build latest sequentially if not jobset.run(build_steps, maxjobs=1, @@ -532,6 +571,8 @@ def _build_and_run(check_cancelled, newline_on_success, travis, cache, xml_repor # start antagonists antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py']) for _ in range(0, args.antagonists)] + port_server_port = 9999 + _start_port_server(port_server_port) try: infinite_runs = runs_per_test == 0 # When running on travis, we want out test runs to be as similar as possible @@ -558,7 +599,8 @@ def _build_and_run(check_cancelled, newline_on_success, travis, cache, xml_repor maxjobs=args.jobs, stop_on_failure=args.stop_on_failure, cache=cache if not xml_report else None, - xml_report=testsuite): + xml_report=testsuite, + add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port}): return 2 finally: for antagonist in antagonists: diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index d2cf07f197d..a8bc1a615c7 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -10955,7 +10955,6 @@ "src/core/debug/trace.h", "src/core/httpcli/format_request.h", "src/core/httpcli/httpcli.h", - "src/core/httpcli/httpcli_security_connector.h", "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", @@ -11114,7 +11113,6 @@ "src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli.h", "src/core/httpcli/httpcli_security_connector.c", - "src/core/httpcli/httpcli_security_connector.h", "src/core/httpcli/parser.c", "src/core/httpcli/parser.h", "src/core/iomgr/alarm.c", @@ -11423,6 +11421,9 @@ "src/core/client_config/uri_parser.h", "src/core/compression/message_compress.h", "src/core/debug/trace.h", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.h", "src/core/iomgr/alarm_internal.h", @@ -11561,6 +11562,12 @@ "src/core/compression/message_compress.h", "src/core/debug/trace.c", "src/core/debug/trace.h", + "src/core/httpcli/format_request.c", + "src/core/httpcli/format_request.h", + "src/core/httpcli/httpcli.c", + "src/core/httpcli/httpcli.h", + "src/core/httpcli/parser.c", + "src/core/httpcli/parser.h", "src/core/iomgr/alarm.c", "src/core/iomgr/alarm.h", "src/core/iomgr/alarm_heap.c", diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj index 4f28ed922e8..a6986126065 100644 --- a/vsprojects/grpc/grpc.vcxproj +++ b/vsprojects/grpc/grpc.vcxproj @@ -229,10 +229,6 @@ - - - - @@ -272,6 +268,9 @@ + + + @@ -347,14 +346,8 @@ - - - - - - @@ -447,6 +440,12 @@ + + + + + + diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters index 2f2c5936d10..d87fef92505 100644 --- a/vsprojects/grpc/grpc.vcxproj.filters +++ b/vsprojects/grpc/grpc.vcxproj.filters @@ -1,18 +1,9 @@ - - src\core\httpcli - - - src\core\httpcli - src\core\httpcli - - src\core\httpcli - src\core\security @@ -151,6 +142,15 @@ src\core\debug + + src\core\httpcli + + + src\core\httpcli + + + src\core\httpcli + src\core\iomgr @@ -443,18 +443,6 @@ - - src\core\httpcli - - - src\core\httpcli - - - src\core\httpcli - - - src\core\httpcli - src\core\security @@ -572,6 +560,15 @@ src\core\debug + + src\core\httpcli + + + src\core\httpcli + + + src\core\httpcli + src\core\iomgr diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj index 004858d0701..2be0d1792b5 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj @@ -251,6 +251,9 @@ + + + @@ -380,6 +383,12 @@ + + + + + + diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters index b0c62b07c36..03b4fb5bd92 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -82,6 +82,15 @@ src\core\debug + + src\core\httpcli + + + src\core\httpcli + + + src\core\httpcli + src\core\iomgr @@ -449,6 +458,15 @@ src\core\debug + + src\core\httpcli + + + src\core\httpcli + + + src\core\httpcli + src\core\iomgr @@ -707,6 +725,9 @@ {6d8d5774-7291-554d-fafa-583463cd3fd9} + + {1ba3a245-47e7-89b5-b0c9-aca758bd0277} + {a9df8b24-ecea-ff6d-8999-d8fa54cd70bf} From ed96983e22a32abd533733f3cc04f6f3b1e2ef47 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 3 Aug 2015 14:54:44 -0700 Subject: [PATCH 016/117] Move Python protoc plugin tests to grpcio_test --- .../grpc_protoc_plugin/__init__.py | 30 +++++++++++++++++++ .../grpc_protoc_plugin}/python_plugin_test.py | 20 ++++++++----- .../grpc_protoc_plugin}/test.proto | 0 src/python/grpcio_test/setup.py | 11 +++++-- tools/run_tests/run_python.sh | 1 + 5 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/python/grpcio_test/grpc_protoc_plugin/__init__.py rename {test/compiler => src/python/grpcio_test/grpc_protoc_plugin}/python_plugin_test.py (97%) rename {test/compiler => src/python/grpcio_test/grpc_protoc_plugin}/test.proto (100%) diff --git a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py b/src/python/grpcio_test/grpc_protoc_plugin/__init__.py new file mode 100644 index 00000000000..70865191060 --- /dev/null +++ b/src/python/grpcio_test/grpc_protoc_plugin/__init__.py @@ -0,0 +1,30 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/test/compiler/python_plugin_test.py b/src/python/grpcio_test/grpc_protoc_plugin/python_plugin_test.py similarity index 97% rename from test/compiler/python_plugin_test.py rename to src/python/grpcio_test/grpc_protoc_plugin/python_plugin_test.py index 0e58d912b9a..b200d129a9c 100644 --- a/test/compiler/python_plugin_test.py +++ b/src/python/grpcio_test/grpc_protoc_plugin/python_plugin_test.py @@ -29,9 +29,11 @@ import argparse import contextlib +import distutils.spawn import errno import itertools import os +import pkg_resources import shutil import subprocess import sys @@ -58,9 +60,6 @@ SHORT_TIMEOUT = 2 LONG_TIMEOUT = 600 NO_DELAY = 0 -# Build mode environment variable set by tools/run_tests/run_tests.py. -_build_mode = os.environ['CONFIG'] - class _ServicerMethods(object): @@ -228,9 +227,13 @@ class PythonPluginTest(unittest.TestCase): """ def setUp(self): - protoc_command = '../../bins/%s/protobuf/protoc' % _build_mode - protoc_plugin_filename = '../../bins/%s/grpc_python_plugin' % _build_mode - test_proto_filename = './test.proto' + # Assume that the appropriate protoc and grpc_python_plugins are on the + # path. + protoc_command = 'protoc' + protoc_plugin_filename = distutils.spawn.find_executable( + 'grpc_python_plugin') + test_proto_filename = pkg_resources.resource_filename( + 'grpc_protoc_plugin', 'test.proto') if not os.path.isfile(protoc_command): # Assume that if we haven't built protoc that it's on the system. protoc_command = 'protoc' @@ -242,12 +245,13 @@ class PythonPluginTest(unittest.TestCase): cmd = [ protoc_command, '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename, - '-I %s' % os.path.dirname(test_proto_filename), + '-I .', '--python_out=%s' % self.outdir, '--python-grpc_out=%s' % self.outdir, os.path.basename(test_proto_filename), ] - subprocess.call(' '.join(cmd), shell=True) + subprocess.check_call(' '.join(cmd), shell=True, env=os.environ, + cwd=os.path.dirname(test_proto_filename)) sys.path.append(self.outdir) def tearDown(self): diff --git a/test/compiler/test.proto b/src/python/grpcio_test/grpc_protoc_plugin/test.proto similarity index 100% rename from test/compiler/test.proto rename to src/python/grpcio_test/grpc_protoc_plugin/test.proto diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py index 925c32720fe..a6203cae2da 100644 --- a/src/python/grpcio_test/setup.py +++ b/src/python/grpcio_test/setup.py @@ -48,8 +48,13 @@ _PACKAGE_DIRECTORIES = { _PACKAGE_DATA = { 'grpc_interop': [ - 'credentials/ca.pem', 'credentials/server1.key', - 'credentials/server1.pem',] + 'credentials/ca.pem', + 'credentials/server1.key', + 'credentials/server1.pem', + ], + 'grpc_protoc_plugin': [ + 'test.proto', + ], } _SETUP_REQUIRES = ( @@ -75,5 +80,5 @@ setuptools.setup( package_data=_PACKAGE_DATA, install_requires=_INSTALL_REQUIRES + _SETUP_REQUIRES, setup_requires=_SETUP_REQUIRES, - cmdclass=_COMMAND_CLASS + cmdclass=_COMMAND_CLASS, ) diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh index 5ffd4460b94..6f80219b0e7 100755 --- a/tools/run_tests/run_python.sh +++ b/tools/run_tests/run_python.sh @@ -37,5 +37,6 @@ ROOT=`pwd` GRPCIO_TEST=$ROOT/src/python/grpcio_test export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG +export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH source "python"$PYVER"_virtual_environment"/bin/activate "python"$PYVER $GRPCIO_TEST/setup.py test -a "-n8 --cov=grpc --junitxml=./report.xml" From ce898834f9166db4d106f982ab31e2f813b0f297 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 5 Aug 2015 07:22:18 -0700 Subject: [PATCH 017/117] Revert "Fixing environments where pkg-config isn't installed." This reverts commit 2ed6878412d54ad1a6509de45d6351a3f697bb48. --- Makefile | 62 +++++++++++++------------------------ templates/Makefile.template | 62 +++++++++++++------------------------ 2 files changed, 42 insertions(+), 82 deletions(-) diff --git a/Makefile b/Makefile index 728e00073dd..81eee1474be 100644 --- a/Makefile +++ b/Makefile @@ -268,21 +268,34 @@ INCLUDES = . include $(GENDIR) LDFLAGS += -Llibs/$(CONFIG) ifeq ($(SYSTEM),Darwin) -LIBS += m +ifneq ($(wildcard /usr/local/ssl/include),) +INCLUDES += /usr/local/ssl/include +endif +ifneq ($(wildcard /opt/local/include),) +INCLUDES += /opt/local/include +endif +ifneq ($(wildcard /usr/local/include),) +INCLUDES += /usr/local/include +endif +LIBS = m z +ifneq ($(wildcard /usr/local/ssl/lib),) +LDFLAGS += -L/usr/local/ssl/lib +endif +ifneq ($(wildcard /opt/local/lib),) +LDFLAGS += -L/opt/local/lib +endif +ifneq ($(wildcard /usr/local/lib),) +LDFLAGS += -L/usr/local/lib +endif endif ifeq ($(SYSTEM),Linux) -LIBS += rt m pthread +LIBS = rt m z pthread LDFLAGS += -pthread endif ifeq ($(SYSTEM),MINGW32) -LIBS += m pthread -LDFLAGS += -pthread -endif - -ifeq ($(SYSTEM),FreeBSD) -LIBS += pthread +LIBS = m z pthread LDFLAGS += -pthread endif @@ -374,39 +387,6 @@ ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf else # HAS_PKG_CONFIG -ifeq ($(SYSTEM),Darwin) -ifneq ($(wildcard /usr/local/ssl/include),) -INCLUDES += /usr/local/ssl/include -endif -ifneq ($(wildcard /opt/local/include),) -INCLUDES += /opt/local/include -endif -ifneq ($(wildcard /usr/local/include),) -INCLUDES += /usr/local/include -endif -ifneq ($(wildcard /usr/local/ssl/lib),) -LDFLAGS += -L/usr/local/ssl/lib -endif -ifneq ($(wildcard /opt/local/lib),) -LDFLAGS += -L/opt/local/lib -endif -ifneq ($(wildcard /usr/local/lib),) -LDFLAGS += -L/usr/local/lib -endif -endif - -ifeq ($(SYSTEM),Linux) -LIBS += z -endif - -ifeq ($(SYSTEM),MINGW32) -LIBS += z -endif - -ifeq ($(SYSTEM),FreeBSD) -LIBS += z -endif - ifeq ($(SYSTEM),MINGW32) OPENSSL_LIBS = ssl32 eay32 else diff --git a/templates/Makefile.template b/templates/Makefile.template index 2670e1b1d71..6530ea5eb23 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -282,21 +282,34 @@ INCLUDES = . include $(GENDIR) LDFLAGS += -Llibs/$(CONFIG) ifeq ($(SYSTEM),Darwin) -LIBS += m +ifneq ($(wildcard /usr/local/ssl/include),) +INCLUDES += /usr/local/ssl/include +endif +ifneq ($(wildcard /opt/local/include),) +INCLUDES += /opt/local/include +endif +ifneq ($(wildcard /usr/local/include),) +INCLUDES += /usr/local/include +endif +LIBS = m z +ifneq ($(wildcard /usr/local/ssl/lib),) +LDFLAGS += -L/usr/local/ssl/lib +endif +ifneq ($(wildcard /opt/local/lib),) +LDFLAGS += -L/opt/local/lib +endif +ifneq ($(wildcard /usr/local/lib),) +LDFLAGS += -L/usr/local/lib +endif endif ifeq ($(SYSTEM),Linux) -LIBS += rt m pthread +LIBS = rt m z pthread LDFLAGS += -pthread endif ifeq ($(SYSTEM),MINGW32) -LIBS += m pthread -LDFLAGS += -pthread -endif - -ifeq ($(SYSTEM),FreeBSD) -LIBS += pthread +LIBS = m z pthread LDFLAGS += -pthread endif @@ -399,39 +412,6 @@ ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf else # HAS_PKG_CONFIG -ifeq ($(SYSTEM),Darwin) -ifneq ($(wildcard /usr/local/ssl/include),) -INCLUDES += /usr/local/ssl/include -endif -ifneq ($(wildcard /opt/local/include),) -INCLUDES += /opt/local/include -endif -ifneq ($(wildcard /usr/local/include),) -INCLUDES += /usr/local/include -endif -ifneq ($(wildcard /usr/local/ssl/lib),) -LDFLAGS += -L/usr/local/ssl/lib -endif -ifneq ($(wildcard /opt/local/lib),) -LDFLAGS += -L/opt/local/lib -endif -ifneq ($(wildcard /usr/local/lib),) -LDFLAGS += -L/usr/local/lib -endif -endif - -ifeq ($(SYSTEM),Linux) -LIBS += z -endif - -ifeq ($(SYSTEM),MINGW32) -LIBS += z -endif - -ifeq ($(SYSTEM),FreeBSD) -LIBS += z -endif - ifeq ($(SYSTEM),MINGW32) OPENSSL_LIBS = ssl32 eay32 else From ef12559f0f641a1f3858b793338a96e61b2ca97c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 5 Aug 2015 07:41:35 -0700 Subject: [PATCH 018/117] Rework restart facility to be more portable --- tools/run_tests/port_server.py | 18 +++++++++++++++--- tools/run_tests/run_tests.py | 7 +++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py index 41f862ad887..660928fbe79 100755 --- a/tools/run_tests/port_server.py +++ b/tools/run_tests/port_server.py @@ -81,9 +81,13 @@ def allocate_port(): return port +keep_running = True + + class Handler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): + global keep_running if self.path == '/get': # allocate a new port, it will stay bound for ten minutes and until # it's unused @@ -93,13 +97,21 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler): p = allocate_port() self.log_message('allocated port %d' % p) self.wfile.write('%d' % p) - elif self.path == '/version_and_pid': + elif self.path == '/version': # fetch a version string and the current process pid self.send_response(200) self.send_header('Content-Type', 'text/plain') self.end_headers() - self.wfile.write('%s+%d' % (_MY_VERSION, os.getpid())) + self.wfile.write(_MY_VERSION) + elif self.path == '/quit': + self.send_response(200) + self.end_headers() + keep_running = False + +httpd = BaseHTTPServer.HTTPServer(('', args.port), Handler) +while keep_running: + httpd.handle_request() -BaseHTTPServer.HTTPServer(('', args.port), Handler).serve_forever() +print 'done' diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 9cf52a191e3..28512a847c5 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -38,7 +38,6 @@ import json import multiprocessing import os import platform -import psutil import random import re import subprocess @@ -532,8 +531,7 @@ def _start_port_server(port_server_port): # if not running ==> start a new one # otherwise, leave it up try: - version, _, pid = urllib2.urlopen( - 'http://localhost:%d/version_and_pid' % port_server_port).read().partition('+') + version = urllib2.urlopen('http://localhost:%d/version' % port_server_port).read() running = True except Exception: running = False @@ -542,7 +540,8 @@ def _start_port_server(port_server_port): current_version = hashlib.sha1(f.read()).hexdigest() running = (version == current_version) if not running: - psutil.Process(int(pid)).terminate() + urllib2.urlopen('http://localhost:%d/quit' % port_server_port).read() + time.sleep(1) if not running: port_log = open('portlog.txt', 'w') port_server = subprocess.Popen( From dcd45cf30601b83faf634f5fdc6e85a22f1b6069 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 5 Aug 2015 07:53:25 -0700 Subject: [PATCH 019/117] Cleanup includes --- src/core/httpcli/httpcli.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index bf5cbfcfba1..9012070e8ea 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -41,7 +41,6 @@ #include "src/core/iomgr/tcp_client.h" #include "src/core/httpcli/format_request.h" #include "src/core/httpcli/parser.h" -#include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" #include #include From 72d796f2bcdc5b7f6185f47a0192e2c79bc7d2e7 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 10:19:46 -0700 Subject: [PATCH 020/117] health checking protocol --- doc/health-checking.md | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 doc/health-checking.md diff --git a/doc/health-checking.md b/doc/health-checking.md new file mode 100644 index 00000000000..106c00922bf --- /dev/null +++ b/doc/health-checking.md @@ -0,0 +1,72 @@ +GRPC Health Checking Protocol +================================ + +Health checks are used to probe whether the server is able to handle rpcs. The +client-to-server health checking can happen from point to point or via some +load balancing mechanism. A server may choose to reply “unhealthy” because it +has not been ready to take requests, it is shutting down or some other reason. +The client can act accordingly if the response is not received within some time +window or the response says unhealthy in it. + + +A GRPC service is used as the health checking mechanism for both simple +client-to-server scenario and other systems such as load-balancing. Being a high +level service provides some benefits. Firstly, since it is a GRPC service +itself, doing a health check is in the same format as a normal rpc. Secondly, +it has rich semantics such as per-service health status. Thirdly, as a GRPC +service, it is able reuse all the existing billing, quota infrastructure, etc, +and thus the server has full control over the access of the health checking +service. + +## Service Definition + +The server should export a service defined in the following proto: + +``` +syntax = "proto3"; + +package grpc.health.v1alpha; + +message HealthCheckRequest { + string host = 1; + string service = 2; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + } + ServingStatus status = 1; +} + +service Health { + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); +} +``` + +A client can query the server’s health status by calling the `Check` method, and +a deadline should be set on the rpc. The client can optionally set the host +string. The client can optionally set the service name it wants to query for +health status. The suggested format of service name is +`grpc.health.v1alpha.Health`. + +The server should register all the services for all the hosts manually and set +the individual status, including an empty service name and its status. For each +request received, if the (host, service_name) pair can be found in the registry, +a response must be sent back with an `OK` status and the status field should be +set to `SERVING` or `NOT_SERVING` accordingly. If the service name is not +registered, the server returns a `NOT_FOUND` GRPC status. + +It is recommended that the server use an empty string as the default host string +and create a (“”, “”) pair as the key for server’s health status as a whole. The +server can just do exact matching of the (host, service_name) pair and does not +support any kind of wildcard matching. However, the service owner has the +freedom to implement more complicated matching semantics that both the client +and server agree upon. + + +A client can declare the server as unhealthy if the rpc is not finished after +some amount of time. The client should be able to handle the case where server +does not have the Health service. From 1ae0afccb58e494ad8574527894fd35a3c5c9324 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 13:20:33 -0700 Subject: [PATCH 021/117] api --- include/grpc++/channel_interface.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 10fb9538bcd..740d4c0180e 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -36,6 +36,7 @@ #include +#include #include #include @@ -57,6 +58,17 @@ class ChannelInterface : public CallHook, virtual void* RegisterMethod(const char* method_name) = 0; virtual Call CreateCall(const RpcMethod& method, ClientContext* context, CompletionQueue* cq) = 0; + + virtual grpc_connectivity_state GetState(bool try_to_connect) = 0; + + template + virtual void NotifyOnStateChange(grpc_connectivity_state last_observed, + grpc_connectivity_state* optional_new_state, + const T& deadline, + CompletionQueue* cq, void* tag) = 0; + template + virtual bool WaitForStateChange(grpc_connectivity_state* new_state, + const T& deadline) = 0; }; } // namespace grpc From 88d772c5b8e177afd571b7c68467fa428951f2d8 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 13:23:38 -0700 Subject: [PATCH 022/117] sync api needs last_observed state too --- include/grpc++/channel_interface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 740d4c0180e..0ca94dd484b 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -67,7 +67,8 @@ class ChannelInterface : public CallHook, const T& deadline, CompletionQueue* cq, void* tag) = 0; template - virtual bool WaitForStateChange(grpc_connectivity_state* new_state, + virtual bool WaitForStateChange(grpc_connectivity_state last_observed, + grpc_connectivity_state* new_state, const T& deadline) = 0; }; From c0f32791754a7892078c4388ded9bd057c2d2e73 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 13:27:46 -0700 Subject: [PATCH 023/117] remove new state ptr --- include/grpc++/channel_interface.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 0ca94dd484b..c5a5072298f 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -59,16 +59,21 @@ class ChannelInterface : public CallHook, virtual Call CreateCall(const RpcMethod& method, ClientContext* context, CompletionQueue* cq) = 0; + // Get the current channel state. If the channel is in IDLE and try_to_connect + // is set to true, try to connect. virtual grpc_connectivity_state GetState(bool try_to_connect) = 0; + // Return the tag on cq when the channel state is changed or deadline expires. + // GetState needs to called to get the current state. template virtual void NotifyOnStateChange(grpc_connectivity_state last_observed, - grpc_connectivity_state* optional_new_state, const T& deadline, CompletionQueue* cq, void* tag) = 0; + + // Blocking wait for channel state change or deadline expires. + // GetState needs to called to get the current state. template virtual bool WaitForStateChange(grpc_connectivity_state last_observed, - grpc_connectivity_state* new_state, const T& deadline) = 0; }; From a73dc1c708baf06e746f7a3f13fa14958a4ee2a1 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 14:24:00 -0700 Subject: [PATCH 024/117] specialize deadline type and implementation --- include/grpc++/channel_interface.h | 16 ++++++++--- src/cpp/client/channel.cc | 45 ++++++++++++++++++++++++++++++ src/cpp/client/channel.h | 24 ++++++++++++++-- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index c5a5072298f..65161275c65 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -65,16 +65,24 @@ class ChannelInterface : public CallHook, // Return the tag on cq when the channel state is changed or deadline expires. // GetState needs to called to get the current state. - template virtual void NotifyOnStateChange(grpc_connectivity_state last_observed, - const T& deadline, + gpr_timespec deadline, CompletionQueue* cq, void* tag) = 0; // Blocking wait for channel state change or deadline expires. // GetState needs to called to get the current state. - template virtual bool WaitForStateChange(grpc_connectivity_state last_observed, - const T& deadline) = 0; + gpr_timespec deadline) = 0; +#ifndef GRPC_CXX0X_NO_CHRONO + virtual void NotifyOnStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline, + CompletionQueue* cq, void* tag) = 0; + virtual bool WaitForStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline) = 0; +#endif // !GRPC_CXX0X_NO_CHRONO + }; } // namespace grpc diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index ee143d68a0f..6696f19d76c 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -48,6 +48,7 @@ #include #include #include +#include namespace grpc { @@ -93,4 +94,48 @@ void* Channel::RegisterMethod(const char* method) { host_.empty() ? NULL : host_.c_str()); } +grpc_connectivity_state Channel::GetState(bool try_to_connect) { + return grpc_channel_check_connectivity_state(c_channel_, try_to_connect); +} + +void Channel::NotifyOnStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline, + CompletionQueue* cq, void* tag) { + grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline, + cq->cq(), tag); +} + +bool Channel::WaitForStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline) { + CompletionQueue cq; + bool ok = false; + void* tag = NULL; + NotifyOnStateChange(last_observed, deadline, &cq, NULL); + cq.Next(&tag, &ok); + GPR_ASSERT(tag == NULL); + return ok; +} + +#ifndef GRPC_CXX0X_NO_CHRONO +void Channel::NotifyOnStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline, + CompletionQueue* cq, void* tag) { + TimePoint deadline_tp(deadline); + grpc_channel_watch_connectivity_state(c_channel_, last_observed, + deadline_tp.raw_time(), cq->cq(), tag); +} + +bool Channel::WaitForStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline) { + CompletionQueue cq; + bool ok = false; + void* tag = NULL; + NotifyOnStateChange(last_observed, deadline, &cq, NULL); + cq.Next(&tag, &ok); + GPR_ASSERT(tag == NULL); + return ok; +} +#endif // !GRPC_CXX0X_NO_CHRONO } // namespace grpc diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index 8660146856c..fa3aedc9eb7 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -56,12 +56,30 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface { Channel(const grpc::string& host, grpc_channel* c_channel); ~Channel() GRPC_OVERRIDE; - virtual void* RegisterMethod(const char* method) GRPC_OVERRIDE; - virtual Call CreateCall(const RpcMethod& method, ClientContext* context, + void* RegisterMethod(const char* method) GRPC_OVERRIDE; + Call CreateCall(const RpcMethod& method, ClientContext* context, CompletionQueue* cq) GRPC_OVERRIDE; - virtual void PerformOpsOnCall(CallOpSetInterface* ops, + void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE; + grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE; + + void NotifyOnStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline, + CompletionQueue* cq, void* tag) GRPC_OVERRIDE; + + bool WaitForStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline) GRPC_OVERRIDE; + +#ifndef GRPC_CXX0X_NO_CHRONO + void NotifyOnStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline, + CompletionQueue* cq, void* tag) GRPC_OVERRIDE; + bool WaitForStateChange( + grpc_connectivity_state last_observed, + const std::chrono::system_clock::time_point& deadline) GRPC_OVERRIDE; +#endif // !GRPC_CXX0X_NO_CHRONO private: const grpc::string host_; grpc_channel* const c_channel_; // owned From 93c3b3f7eaaabf50493df1e26b05a6de2f7e7f21 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Wed, 5 Aug 2015 13:33:15 -0700 Subject: [PATCH 025/117] Use common timeouts in Python face-layer test-cases --- ...ing_invocation_inline_service_test_case.py | 34 +++++----- ...ion_synchronous_event_service_test_case.py | 64 +++++++++++-------- ...on_asynchronous_event_service_test_case.py | 45 +++++++------ 3 files changed, 80 insertions(+), 63 deletions(-) diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py index 7e1158f96be..251e1eb68e2 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py +++ b/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py @@ -34,15 +34,13 @@ import abc import unittest # pylint: disable=unused-import from grpc.framework.face import exceptions +from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case -_TIMEOUT = 3 -_LONG_TIMEOUT = 45 - class BlockingInvocationInlineServiceTestCase( test_case.FaceTestCase, coverage.BlockingCoverage): @@ -79,7 +77,7 @@ class BlockingInvocationInlineServiceTestCase( request = test_messages.request() response = self.stub.blocking_value_in_value_out( - name, request, _LONG_TIMEOUT) + name, request, test_constants.LONG_TIMEOUT) test_messages.verify(request, response, self) @@ -90,7 +88,7 @@ class BlockingInvocationInlineServiceTestCase( request = test_messages.request() response_iterator = self.stub.inline_value_in_stream_out( - name, request, _LONG_TIMEOUT) + name, request, test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) @@ -102,7 +100,7 @@ class BlockingInvocationInlineServiceTestCase( requests = test_messages.requests() response = self.stub.blocking_stream_in_value_out( - name, iter(requests), _LONG_TIMEOUT) + name, iter(requests), test_constants.LONG_TIMEOUT) test_messages.verify(requests, response, self) @@ -113,7 +111,7 @@ class BlockingInvocationInlineServiceTestCase( requests = test_messages.requests() response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _LONG_TIMEOUT) + name, iter(requests), test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) @@ -126,12 +124,12 @@ class BlockingInvocationInlineServiceTestCase( second_request = test_messages.request() first_response = self.stub.blocking_value_in_value_out( - name, first_request, _TIMEOUT) + name, first_request, test_constants.SHORT_TIMEOUT) test_messages.verify(first_request, first_response, self) second_response = self.stub.blocking_value_in_value_out( - name, second_request, _TIMEOUT) + name, second_request, test_constants.SHORT_TIMEOUT) test_messages.verify(second_request, second_response, self) @@ -144,7 +142,7 @@ class BlockingInvocationInlineServiceTestCase( with self.control.pause(), self.assertRaises( exceptions.ExpirationError): multi_callable = self.stub.unary_unary_multi_callable(name) - multi_callable(request, _TIMEOUT) + multi_callable(request, test_constants.SHORT_TIMEOUT) def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -155,7 +153,7 @@ class BlockingInvocationInlineServiceTestCase( with self.control.pause(), self.assertRaises( exceptions.ExpirationError): response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): @@ -167,7 +165,7 @@ class BlockingInvocationInlineServiceTestCase( with self.control.pause(), self.assertRaises( exceptions.ExpirationError): multi_callable = self.stub.stream_unary_multi_callable(name) - multi_callable(iter(requests), _TIMEOUT) + multi_callable(iter(requests), test_constants.SHORT_TIMEOUT) def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -178,7 +176,7 @@ class BlockingInvocationInlineServiceTestCase( with self.control.pause(), self.assertRaises( exceptions.ExpirationError): response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): @@ -188,7 +186,8 @@ class BlockingInvocationInlineServiceTestCase( request = test_messages.request() with self.control.fail(), self.assertRaises(exceptions.ServicerError): - self.stub.blocking_value_in_value_out(name, request, _TIMEOUT) + self.stub.blocking_value_in_value_out(name, request, + test_constants.SHORT_TIMEOUT) def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -198,7 +197,7 @@ class BlockingInvocationInlineServiceTestCase( with self.control.fail(), self.assertRaises(exceptions.ServicerError): response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): @@ -208,7 +207,8 @@ class BlockingInvocationInlineServiceTestCase( requests = test_messages.requests() with self.control.fail(), self.assertRaises(exceptions.ServicerError): - self.stub.blocking_stream_in_value_out(name, iter(requests), _TIMEOUT) + self.stub.blocking_stream_in_value_out(name, iter(requests), + test_constants.SHORT_TIMEOUT) def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -218,5 +218,5 @@ class BlockingInvocationInlineServiceTestCase( with self.control.fail(), self.assertRaises(exceptions.ServicerError): response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py index 18eed53d6ee..9df77678eb9 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py +++ b/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py @@ -33,6 +33,7 @@ import abc import unittest from grpc.framework.face import interfaces +from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import callback as testing_callback from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage @@ -40,8 +41,6 @@ from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case -_TIMEOUT = 3 - class EventInvocationSynchronousEventServiceTestCase( test_case.FaceTestCase, coverage.FullCoverage): @@ -79,7 +78,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() self.stub.event_value_in_value_out( - name, request, callback.complete, callback.abort, _TIMEOUT) + name, request, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() response = callback.response() @@ -93,7 +93,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() self.stub.event_value_in_stream_out( - name, request, callback, callback.abort, _TIMEOUT) + name, request, callback, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() responses = callback.responses() @@ -107,7 +108,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_value_out( - name, callback.complete, callback.abort, _TIMEOUT) + name, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() @@ -124,7 +126,7 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_stream_out( - name, callback, callback.abort, _TIMEOUT) + name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() @@ -147,11 +149,11 @@ class EventInvocationSynchronousEventServiceTestCase( first_callback.complete(first_response) self.stub.event_value_in_value_out( name, second_request, second_callback.complete, - second_callback.abort, _TIMEOUT) + second_callback.abort, test_constants.SHORT_TIMEOUT) self.stub.event_value_in_value_out( name, first_request, make_second_invocation, first_callback.abort, - _TIMEOUT) + test_constants.SHORT_TIMEOUT) second_callback.block_until_terminated() first_response = first_callback.response() @@ -168,7 +170,8 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.pause(): self.stub.event_value_in_value_out( - name, request, callback.complete, callback.abort, _TIMEOUT) + name, request, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) @@ -182,7 +185,8 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.pause(): self.stub.event_value_in_stream_out( - name, request, callback, callback.abort, _TIMEOUT) + name, request, callback, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) @@ -194,7 +198,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() self.stub.event_stream_in_value_out( - name, callback.complete, callback.abort, _TIMEOUT) + name, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) @@ -207,7 +212,7 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_stream_out( - name, callback, callback.abort, _TIMEOUT) + name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) callback.block_until_terminated() @@ -223,10 +228,12 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.fail(): self.stub.event_value_in_value_out( - name, request, callback.complete, callback.abort, _TIMEOUT) + name, request, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() - self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) + self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, + callback.abortion()) def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -237,10 +244,12 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.fail(): self.stub.event_value_in_stream_out( - name, request, callback, callback.abort, _TIMEOUT) + name, request, callback, callback.abort, + test_constants.SHORT_TIMEOUT) callback.block_until_terminated() - self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) + self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, + callback.abortion()) def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( @@ -251,13 +260,15 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.fail(): unused_call, request_consumer = self.stub.event_stream_in_value_out( - name, callback.complete, callback.abort, _TIMEOUT) + name, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() callback.block_until_terminated() - self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) + self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, + callback.abortion()) def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( @@ -268,7 +279,7 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.fail(): unused_call, request_consumer = self.stub.event_stream_in_stream_out( - name, callback, callback.abort, _TIMEOUT) + name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() @@ -287,10 +298,10 @@ class EventInvocationSynchronousEventServiceTestCase( self.stub.event_value_in_value_out( name, first_request, first_callback.complete, first_callback.abort, - _TIMEOUT) + test_constants.SHORT_TIMEOUT) self.stub.event_value_in_value_out( name, second_request, second_callback.complete, - second_callback.abort, _TIMEOUT) + second_callback.abort, test_constants.SHORT_TIMEOUT) first_callback.block_until_terminated() second_callback.block_until_terminated() @@ -312,7 +323,8 @@ class EventInvocationSynchronousEventServiceTestCase( with self.control.pause(): call = self.stub.event_value_in_value_out( - name, request, callback.complete, callback.abort, _TIMEOUT) + name, request, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() @@ -326,7 +338,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() call = self.stub.event_value_in_stream_out( - name, request, callback, callback.abort, _TIMEOUT) + name, request, callback, callback.abort, + test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() @@ -340,7 +353,8 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() call, request_consumer = self.stub.event_stream_in_value_out( - name, callback.complete, callback.abort, _TIMEOUT) + name, callback.complete, callback.abort, + test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) call.cancel() @@ -355,7 +369,7 @@ class EventInvocationSynchronousEventServiceTestCase( callback = testing_callback.Callback() call, unused_request_consumer = self.stub.event_stream_in_stream_out( - name, callback, callback.abort, _TIMEOUT) + name, callback, callback.abort, test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py index 3b42914342c..70d86a04220 100644 --- a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py +++ b/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py @@ -37,13 +37,13 @@ import unittest from grpc.framework.face import exceptions from grpc.framework.foundation import future from grpc.framework.foundation import logging_pool +from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case -_TIMEOUT = 3 _MAXIMUM_POOL_SIZE = 10 @@ -110,7 +110,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( request = test_messages.request() response_future = self.stub.future_value_in_value_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) response = response_future.result() test_messages.verify(request, response, self) @@ -122,7 +122,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( request = test_messages.request() response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) @@ -138,7 +138,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_future = self.stub.future_stream_in_value_out( - name, request_iterator, _TIMEOUT) + name, request_iterator, test_constants.SHORT_TIMEOUT) response = response_future.result() test_messages.verify(requests, response, self) @@ -154,7 +154,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_iterator = self.stub.inline_stream_in_stream_out( - name, request_iterator, _TIMEOUT) + name, request_iterator, test_constants.SHORT_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) @@ -167,13 +167,13 @@ class FutureInvocationAsynchronousEventServiceTestCase( second_request = test_messages.request() first_response_future = self.stub.future_value_in_value_out( - name, first_request, _TIMEOUT) + name, first_request, test_constants.SHORT_TIMEOUT) first_response = first_response_future.result() test_messages.verify(first_request, first_response, self) second_response_future = self.stub.future_value_in_value_out( - name, second_request, _TIMEOUT) + name, second_request, test_constants.SHORT_TIMEOUT) second_response = second_response_future.result() test_messages.verify(second_request, second_response, self) @@ -186,7 +186,8 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): multi_callable = self.stub.unary_unary_multi_callable(name) - response_future = multi_callable.future(request, _TIMEOUT) + response_future = multi_callable.future(request, + test_constants.SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): @@ -200,7 +201,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(response_iterator) @@ -212,7 +213,8 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): multi_callable = self.stub.stream_unary_multi_callable(name) - response_future = multi_callable.future(iter(requests), _TIMEOUT) + response_future = multi_callable.future(iter(requests), + test_constants.SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): @@ -226,7 +228,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(response_iterator) @@ -238,7 +240,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.fail(): response_future = self.stub.future_value_in_value_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -261,7 +263,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( # expiration of the RPC. with self.control.fail(), self.assertRaises(exceptions.ExpirationError): response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): @@ -272,7 +274,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.fail(): response_future = self.stub.future_stream_in_value_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -295,7 +297,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( # expiration of the RPC. with self.control.fail(), self.assertRaises(exceptions.ExpirationError): response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) def testParallelInvocations(self): @@ -305,10 +307,11 @@ class FutureInvocationAsynchronousEventServiceTestCase( first_request = test_messages.request() second_request = test_messages.request() + # TODO(bug 2039): use LONG_TIMEOUT instead first_response_future = self.stub.future_value_in_value_out( - name, first_request, _TIMEOUT) + name, first_request, test_constants.SHORT_TIMEOUT) second_response_future = self.stub.future_value_in_value_out( - name, second_request, _TIMEOUT) + name, second_request, test_constants.SHORT_TIMEOUT) first_response = first_response_future.result() second_response = second_response_future.result() @@ -327,7 +330,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_future = self.stub.future_value_in_value_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) cancel_method_return_value = response_future.cancel() self.assertFalse(cancel_method_return_value) @@ -341,7 +344,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_iterator = self.stub.inline_value_in_stream_out( - name, request, _TIMEOUT) + name, request, test_constants.SHORT_TIMEOUT) response_iterator.cancel() with self.assertRaises(future.CancelledError): @@ -355,7 +358,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_future = self.stub.future_stream_in_value_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) cancel_method_return_value = response_future.cancel() self.assertFalse(cancel_method_return_value) @@ -369,7 +372,7 @@ class FutureInvocationAsynchronousEventServiceTestCase( with self.control.pause(): response_iterator = self.stub.inline_stream_in_stream_out( - name, iter(requests), _TIMEOUT) + name, iter(requests), test_constants.SHORT_TIMEOUT) response_iterator.cancel() with self.assertRaises(future.CancelledError): From 36f59652470a63b488c78669c96a5351f22e8867 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 15:15:18 -0700 Subject: [PATCH 026/117] clean up and add a test --- src/cpp/client/channel.cc | 61 ++++++++++++++++++++++---------- test/cpp/end2end/end2end_test.cc | 24 ++++++++++++- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index 6696f19d76c..1bdb9ae0de9 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -98,44 +98,69 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) { return grpc_channel_check_connectivity_state(c_channel_, try_to_connect); } -void Channel::NotifyOnStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline, - CompletionQueue* cq, void* tag) { - grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline, - cq->cq(), tag); +namespace { +class TagSaver GRPC_FINAL : public CompletionQueueTag { + public: + explicit TagSaver(void* tag) : tag_(tag) {} + ~TagSaver() GRPC_OVERRIDE {} + bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE { + *tag = tag_; + delete this; + return true; + } + private: + void* tag_; +}; + +template +void NotifyOnStateChangeShared(grpc_channel* channel, + grpc_connectivity_state last_observed, + const T& deadline, + CompletionQueue* cq, void* tag) { + TimePoint deadline_tp(deadline); + TagSaver* tag_saver = new TagSaver(tag); + grpc_channel_watch_connectivity_state( + channel, last_observed, deadline_tp.raw_time(), cq->cq(), tag_saver); } -bool Channel::WaitForStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline) { +template +bool WaitForStateChangeShared(grpc_channel* channel, + grpc_connectivity_state last_observed, + const T& deadline) { CompletionQueue cq; bool ok = false; void* tag = NULL; - NotifyOnStateChange(last_observed, deadline, &cq, NULL); + NotifyOnStateChangeShared(channel, last_observed, deadline, &cq, NULL); cq.Next(&tag, &ok); GPR_ASSERT(tag == NULL); return ok; } +} // namespace + +void Channel::NotifyOnStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline, + CompletionQueue* cq, void* tag) { + NotifyOnStateChangeShared(c_channel_, last_observed, deadline, cq, tag); +} + +bool Channel::WaitForStateChange(grpc_connectivity_state last_observed, + gpr_timespec deadline) { + return WaitForStateChangeShared(c_channel_, last_observed, deadline); +} + #ifndef GRPC_CXX0X_NO_CHRONO void Channel::NotifyOnStateChange( grpc_connectivity_state last_observed, const std::chrono::system_clock::time_point& deadline, CompletionQueue* cq, void* tag) { - TimePoint deadline_tp(deadline); - grpc_channel_watch_connectivity_state(c_channel_, last_observed, - deadline_tp.raw_time(), cq->cq(), tag); + NotifyOnStateChangeShared(c_channel_, last_observed, deadline, cq, tag); } bool Channel::WaitForStateChange( grpc_connectivity_state last_observed, const std::chrono::system_clock::time_point& deadline) { - CompletionQueue cq; - bool ok = false; - void* tag = NULL; - NotifyOnStateChange(last_observed, deadline, &cq, NULL); - cq.Next(&tag, &ok); - GPR_ASSERT(tag == NULL); - return ok; + return WaitForStateChangeShared(c_channel_, last_observed, deadline); } #endif // !GRPC_CXX0X_NO_CHRONO } // namespace grpc diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 3144ca4dc71..8963382a87a 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -831,7 +831,8 @@ TEST_F(End2endTest, HugeResponse) { } namespace { -void ReaderThreadFunc(ClientReaderWriter* stream, gpr_event *ev) { +void ReaderThreadFunc(ClientReaderWriter* stream, + gpr_event *ev) { EchoResponse resp; gpr_event_set(ev, (void*)1); while (stream->Read(&resp)) { @@ -870,6 +871,27 @@ TEST_F(End2endTest, Peer) { EXPECT_TRUE(CheckIsLocalhost(context.peer())); } +TEST_F(End2endTest, ChannelState) { + ResetStub(); + // Start IDLE + EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false)); + + CompletionQueue cq; + std::chrono::system_clock::time_point deadline = + std::chrono::system_clock::now() + std::chrono::milliseconds(10); + // No state change. + channel_->NotifyOnStateChange(GRPC_CHANNEL_IDLE, deadline, &cq, NULL); + void* tag; + bool ok = true; + cq.Next(&tag, &ok); + EXPECT_FALSE(ok); + + EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(true)); + EXPECT_TRUE(channel_->WaitForStateChange( + GRPC_CHANNEL_IDLE, gpr_inf_future(GPR_CLOCK_REALTIME))); + EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false)); +} + } // namespace testing } // namespace grpc From a5af2be96479a2d5f2db0309d9ab4c0b9dd10f29 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 5 Aug 2015 15:31:02 -0700 Subject: [PATCH 027/117] Fix integration breakage --- test/core/util/port_posix.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c index 715e4582628..62d5e7df20a 100644 --- a/test/core/util/port_posix.c +++ b/test/core/util/port_posix.c @@ -149,7 +149,7 @@ static void got_port_from_server(void *arg, GPR_ASSERT(port > 1024); gpr_mu_lock(GRPC_POLLSET_MU(&pr->pollset)); pr->port = port; - grpc_pollset_kick(&pr->pollset); + grpc_pollset_kick(&pr->pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset)); } @@ -174,7 +174,9 @@ static int pick_port_using_server(char *server) { &pr); gpr_mu_lock(GRPC_POLLSET_MU(&pr.pollset)); while (pr.port == -1) { - grpc_pollset_work(&pr.pollset, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1)); + grpc_pollset_worker worker; + grpc_pollset_work(&pr.pollset, &worker, + GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1)); } gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset)); From 8708dd76c1c851329e3da68156497d828d64dcbf Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 5 Aug 2015 15:57:14 -0700 Subject: [PATCH 028/117] Add WaitForState --- include/grpc++/channel_interface.h | 10 ++++++++- src/cpp/client/channel.cc | 36 ++++++++++++++++++++++++++++++ src/cpp/client/channel.h | 9 ++++++++ test/cpp/end2end/end2end_test.cc | 4 +++- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 65161275c65..335b6ccaaee 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -69,10 +69,15 @@ class ChannelInterface : public CallHook, gpr_timespec deadline, CompletionQueue* cq, void* tag) = 0; - // Blocking wait for channel state change or deadline expires. + // Blocking wait for channel state change or deadline expiration. // GetState needs to called to get the current state. virtual bool WaitForStateChange(grpc_connectivity_state last_observed, gpr_timespec deadline) = 0; + + // Blocking wait for target state or deadline expriration. + virtual bool WaitForState(grpc_connectivity_state target_state, + gpr_timespec deadline) = 0; + #ifndef GRPC_CXX0X_NO_CHRONO virtual void NotifyOnStateChange( grpc_connectivity_state last_observed, @@ -81,6 +86,9 @@ class ChannelInterface : public CallHook, virtual bool WaitForStateChange( grpc_connectivity_state last_observed, const std::chrono::system_clock::time_point& deadline) = 0; + virtual bool WaitForState( + grpc_connectivity_state target_state, + const std::chrono::system_clock::time_point& deadline) = 0; #endif // !GRPC_CXX0X_NO_CHRONO }; diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index 1bdb9ae0de9..ccd30c0f460 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -136,6 +136,30 @@ bool WaitForStateChangeShared(grpc_channel* channel, return ok; } +template +bool WaitForStateShared(grpc_channel* channel, + grpc_connectivity_state target_state, + const T& deadline) { + grpc_connectivity_state current_state = + grpc_channel_check_connectivity_state(channel, 0); + if (current_state == target_state) { + return true; + } + TimePoint deadline_tp(deadline); + CompletionQueue cq; + bool ok = false; + void* tag = NULL; + while (current_state != target_state) { + NotifyOnStateChangeShared(channel, current_state, deadline_tp.raw_time(), + &cq, NULL); + cq.Next(&tag, &ok); + if (!ok) { + return false; + } + current_state = grpc_channel_check_connectivity_state(channel, 0); + } + return true; +} } // namespace void Channel::NotifyOnStateChange(grpc_connectivity_state last_observed, @@ -149,6 +173,11 @@ bool Channel::WaitForStateChange(grpc_connectivity_state last_observed, return WaitForStateChangeShared(c_channel_, last_observed, deadline); } +bool Channel::WaitForState(grpc_connectivity_state target_state, + gpr_timespec deadline) { + return WaitForStateShared(c_channel_, target_state, deadline); +} + #ifndef GRPC_CXX0X_NO_CHRONO void Channel::NotifyOnStateChange( grpc_connectivity_state last_observed, @@ -162,5 +191,12 @@ bool Channel::WaitForStateChange( const std::chrono::system_clock::time_point& deadline) { return WaitForStateChangeShared(c_channel_, last_observed, deadline); } + +bool Channel::WaitForState( + grpc_connectivity_state target_state, + const std::chrono::system_clock::time_point& deadline) { + return WaitForStateShared(c_channel_, target_state, deadline); +} + #endif // !GRPC_CXX0X_NO_CHRONO } // namespace grpc diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index fa3aedc9eb7..4dc67237786 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -71,15 +71,24 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface { bool WaitForStateChange(grpc_connectivity_state last_observed, gpr_timespec deadline) GRPC_OVERRIDE; + bool WaitForState(grpc_connectivity_state target_state, + gpr_timespec deadline) GRPC_OVERRIDE; + #ifndef GRPC_CXX0X_NO_CHRONO void NotifyOnStateChange( grpc_connectivity_state last_observed, const std::chrono::system_clock::time_point& deadline, CompletionQueue* cq, void* tag) GRPC_OVERRIDE; + bool WaitForStateChange( grpc_connectivity_state last_observed, const std::chrono::system_clock::time_point& deadline) GRPC_OVERRIDE; + + bool WaitForState(grpc_connectivity_state target_state, + const std::chrono::system_clock::time_point& deadline) + GRPC_OVERRIDE; #endif // !GRPC_CXX0X_NO_CHRONO + private: const grpc::string host_; grpc_channel* const c_channel_; // owned diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 8963382a87a..12ac25c6dff 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -876,10 +876,10 @@ TEST_F(End2endTest, ChannelState) { // Start IDLE EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false)); + // Did not ask to connect, no state change. CompletionQueue cq; std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(10); - // No state change. channel_->NotifyOnStateChange(GRPC_CHANNEL_IDLE, deadline, &cq, NULL); void* tag; bool ok = true; @@ -890,6 +890,8 @@ TEST_F(End2endTest, ChannelState) { EXPECT_TRUE(channel_->WaitForStateChange( GRPC_CHANNEL_IDLE, gpr_inf_future(GPR_CLOCK_REALTIME))); EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false)); + EXPECT_TRUE(channel_->WaitForState(GRPC_CHANNEL_READY, + gpr_inf_future(GPR_CLOCK_REALTIME))); } } // namespace testing From 77a7b870c3e4259cc8f5cffc2b59876b42c0624a Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Wed, 5 Aug 2015 20:11:02 -0700 Subject: [PATCH 029/117] Fixing API (thanks Craig for the comments) and associated tests. --- include/grpc/grpc_security.h | 26 ++--- src/core/security/security_context.h | 11 +- src/core/security/server_auth_filter.c | 26 ++--- test/core/end2end/end2end_tests.h | 2 + .../end2end/fixtures/chttp2_fake_security.c | 25 ++++ .../fixtures/chttp2_simple_ssl_fullstack.c | 24 ++++ .../chttp2_simple_ssl_fullstack_with_poll.c | 24 ++++ .../chttp2_simple_ssl_with_oauth2_fullstack.c | 48 ++++++-- ...est_response_with_payload_and_call_creds.c | 110 +++++++++++++++++- 9 files changed, 242 insertions(+), 54 deletions(-) diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 65887d86ba1..640c1fda986 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -255,12 +255,9 @@ void grpc_auth_context_release(grpc_auth_context *context); /* -- The following auth context methods should only be called by a server metadata - processor that will augment the channel auth context (see below). + processor to set properties extracted from auth metadata. -- */ -/* Creates a new auth context based off a chained context. */ -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); - /* Add a property. */ void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, const char *value, size_t value_length); @@ -277,21 +274,22 @@ int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, /* --- Auth Metadata Processing --- */ -/* Opaque data structure useful for processors defined in core. */ -typedef struct grpc_auth_ticket grpc_auth_ticket; - /* Callback function that is called when the metadata processing is done. - success is 1 if processing succeeded, 0 otherwise. */ + success is 1 if processing succeeded, 0 otherwise. + Consumed metadata will be removed from the set of metadata available on the + call. */ typedef void (*grpc_process_auth_metadata_done_cb)( void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, - int success, grpc_auth_context *result); + int success); -/* Pluggable server-side metadata processor object */ +/* Pluggable server-side metadata processor object. */ typedef struct { - void (*process)(void *state, grpc_auth_ticket *ticket, - grpc_auth_context *channel_ctx, const grpc_metadata *md, - size_t md_count, grpc_process_auth_metadata_done_cb cb, - void *user_data); + /* The context object is read/write: it contains the properties of the + channel peer and it is the job of the process function to augment it with + properties derived from the passed-in metadata. */ + void (*process)(void *state, grpc_auth_context *context, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, void *user_data); void *state; } grpc_auth_metadata_processor; diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index ddc0a7afad6..3ad57cadea6 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -37,11 +37,6 @@ #include "src/core/iomgr/pollset.h" #include "src/core/security/credentials.h" -/* --- grpc_auth_ticket --- */ -struct grpc_auth_ticket { - grpc_pollset *pollset; -}; - /* --- grpc_auth_context --- High level authentication context object. Can optionally be chained. */ @@ -59,8 +54,12 @@ struct grpc_auth_context { grpc_auth_property_array properties; gpr_refcount refcount; const char *peer_identity_property_name; + grpc_pollset *pollset; }; +/* Creation. */ +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); + /* Refcounting. */ #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG #define GRPC_AUTH_CONTEXT_REF(p, r) \ @@ -79,6 +78,8 @@ grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); void grpc_auth_context_unref(grpc_auth_context *policy); #endif +/* Get the pollset. */ + void grpc_auth_property_reset(grpc_auth_property *property); /* --- grpc_client_security_context --- diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 41d31100016..2fc689caecd 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -53,8 +53,7 @@ typedef struct call_data { const grpc_metadata *consumed_md; size_t num_consumed_md; grpc_stream_op *md_op; - grpc_auth_context **call_auth_context; - grpc_auth_ticket ticket; + grpc_auth_context *auth_context; } call_data; typedef struct channel_data { @@ -107,8 +106,7 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { static void on_md_processing_done(void *user_data, const grpc_metadata *consumed_md, - size_t num_consumed_md, int success, - grpc_auth_context *result) { + size_t num_consumed_md, int success) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; @@ -117,11 +115,6 @@ static void on_md_processing_done(void *user_data, calld->num_consumed_md = num_consumed_md; grpc_metadata_batch_filter(&calld->md_op->data.metadata, remove_consumed_md, elem); - GPR_ASSERT(calld->call_auth_context != NULL); - GRPC_AUTH_CONTEXT_UNREF(*calld->call_auth_context, - "releasing old context."); - *calld->call_auth_context = - GRPC_AUTH_CONTEXT_REF(result, "refing new context."); calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } else { gpr_slice message = gpr_slice_from_copied_string( @@ -149,8 +142,7 @@ static void auth_on_recv(void *user_data, int success) { if (chand->processor.process == NULL) continue; calld->md_op = op; md_array = metadata_batch_to_md_array(&op->data.metadata); - chand->processor.process(chand->processor.state, &calld->ticket, - chand->security_connector->auth_context, + chand->processor.process(chand->processor.state, calld->auth_context, md_array.metadata, md_array.count, on_md_processing_done, elem); grpc_metadata_array_destroy(&md_array); @@ -200,11 +192,6 @@ static void init_call_elem(grpc_call_element *elem, GPR_ASSERT(initial_op && initial_op->context != NULL && initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); - /* Get the pollset for the ticket. */ - if (initial_op->bind_pollset) { - calld->ticket.pollset = initial_op->bind_pollset; - } - /* Create a security context for the call and reference the auth context from the channel. */ if (initial_op->context[GRPC_CONTEXT_SECURITY].value != NULL) { @@ -212,12 +199,13 @@ static void init_call_elem(grpc_call_element *elem, initial_op->context[GRPC_CONTEXT_SECURITY].value); } server_ctx = grpc_server_security_context_create(); - server_ctx->auth_context = GRPC_AUTH_CONTEXT_REF( - chand->security_connector->auth_context, "server_security_context"); + server_ctx->auth_context = + grpc_auth_context_create(chand->security_connector->auth_context); + server_ctx->auth_context->pollset = initial_op->bind_pollset; initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx; initial_op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_server_security_context_destroy; - calld->call_auth_context = &server_ctx->auth_context; + calld->auth_context = server_ctx->auth_context; /* Set the metadata callbacks. */ set_recv_ops_md_callbacks(elem, initial_op); diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index a18c7029514..3f1665613c6 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -43,6 +43,8 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config; #define FEATURE_MASK_SUPPORTS_HOSTNAME_VERIFICATION 2 #define FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS 4 +#define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check" + struct grpc_end2end_test_fixture { grpc_completion_queue *cq; grpc_server *server; diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c index f879b43f794..78b692a45dd 100644 --- a/test/core/end2end/fixtures/chttp2_fake_security.c +++ b/test/core/end2end/fixtures/chttp2_fake_security.c @@ -65,6 +65,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( return f; } +static void process_auth_failure(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + GPR_ASSERT(state == NULL); + cb(user_data, NULL, 0, 0); +} + static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { @@ -102,10 +110,27 @@ static void chttp2_init_client_fake_secure_fullstack( chttp2_init_client_secure_fullstack(f, client_args, fake_ts_creds); } +static int fail_server_auth_check(grpc_channel_args *server_args) { + size_t i; + if (server_args == NULL) return 0; + for (i = 0; i < server_args->num_args; i++) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == + 0) { + return 1; + } + } + return 0; +} + static void chttp2_init_server_fake_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_server_credentials *fake_ts_creds = grpc_fake_transport_security_server_credentials_create(); + if (fail_server_auth_check(server_args)) { + grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; + grpc_server_credentials_set_auth_metadata_processor(fake_ts_creds, + processor); + } chttp2_init_server_secure_fullstack(f, server_args, fake_ts_creds); } diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c index 6d5669d05a8..9850aac69b0 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c @@ -68,6 +68,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( return f; } +static void process_auth_failure(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + GPR_ASSERT(state == NULL); + cb(user_data, NULL, 0, 0); +} + static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { @@ -110,12 +118,28 @@ static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_channel_args_destroy(new_client_args); } +static int fail_server_auth_check(grpc_channel_args *server_args) { + size_t i; + if (server_args == NULL) return 0; + for (i = 0; i < server_args->num_args; i++) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == + 0) { + return 1; + } + } + return 0; +} + static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + if (fail_server_auth_check(server_args)) { + grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; + grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); + } chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); } diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c index d0cc3dd74a2..3df2acd296b 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c @@ -68,6 +68,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( return f; } +static void process_auth_failure(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + GPR_ASSERT(state == NULL); + cb(user_data, NULL, 0, 0); +} + static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { @@ -110,12 +118,28 @@ static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_channel_args_destroy(new_client_args); } +static int fail_server_auth_check(grpc_channel_args *server_args) { + size_t i; + if (server_args == NULL) return 0; + for (i = 0; i < server_args->num_args; i++) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == + 0) { + return 1; + } + } + return 0; +} + static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + if (fail_server_auth_check(server_args)) { + grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; + grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); + } chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); } diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c index 1fc988c98e5..284d5f07ae9 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c @@ -68,22 +68,30 @@ static const grpc_metadata *find_metadata(const grpc_metadata *md, return NULL; } -void process_oauth2(void *state, grpc_auth_ticket *ticket, - grpc_auth_context *channel_ctx, const grpc_metadata *md, - size_t md_count, grpc_process_auth_metadata_done_cb cb, - void *user_data) { +static void process_oauth2_success(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { const grpc_metadata *oauth2 = find_metadata(md, md_count, "Authorization", oauth2_md); - grpc_auth_context *new_ctx; GPR_ASSERT(state == NULL); GPR_ASSERT(oauth2 != NULL); - new_ctx = grpc_auth_context_create(channel_ctx); - grpc_auth_context_add_cstring_property(new_ctx, client_identity_property_name, + grpc_auth_context_add_cstring_property(ctx, client_identity_property_name, client_identity); GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - new_ctx, client_identity_property_name) == 1); - cb(user_data, oauth2, 1, 1, new_ctx); - grpc_auth_context_release(new_ctx); + ctx, client_identity_property_name) == 1); + cb(user_data, oauth2, 1, 1); +} + +static void process_oauth2_failure(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + const grpc_metadata *oauth2 = + find_metadata(md, md_count, "Authorization", oauth2_md); + GPR_ASSERT(state == NULL); + GPR_ASSERT(oauth2 != NULL); + cb(user_data, oauth2, 1, 0); } static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( @@ -151,13 +159,31 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_credentials_release(oauth2_creds); } +static int fail_server_auth_check(grpc_channel_args *server_args) { + size_t i; + if (server_args == NULL) return 0; + for (i = 0; i < server_args->num_args; i++) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == + 0) { + return 1; + } + } + return 0; +} + static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0); - grpc_auth_metadata_processor processor = {process_oauth2, NULL}; + grpc_auth_metadata_processor processor; + processor.state = NULL; + if (fail_server_auth_check(server_args)) { + processor.process = process_oauth2_failure; + } else { + processor.process = process_oauth2_success; + } grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); } diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index e621fcbed2e..b4ccaf82164 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -57,13 +57,23 @@ enum { TIMEOUT = 200000 }; static void *tag(gpr_intptr t) { return (void *)t; } -static grpc_end2end_test_fixture begin_test( - grpc_end2end_test_config config, const char *test_name) { +static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, + const char *test_name, + int fail_server_auth_check) { grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(NULL, NULL); config.init_client(&f, NULL); - config.init_server(&f, NULL); + if (fail_server_auth_check) { + grpc_arg fail_auth_arg = { + GRPC_ARG_STRING, FAIL_AUTH_CHECK_SERVER_ARG_NAME, {NULL}}; + grpc_channel_args args; + args.num_args= 1; + args.args = &fail_auth_arg; + config.init_server(&f, &args); + } else { + config.init_server(&f, NULL); + } return f; } @@ -125,7 +135,8 @@ static void print_auth_context(int is_client, const grpc_auth_context *ctx) { static void test_call_creds_failure(grpc_end2end_test_config config) { grpc_call *c; grpc_credentials *creds = NULL; - grpc_end2end_test_fixture f = begin_test(config, "test_call_creds_failure"); + grpc_end2end_test_fixture f = + begin_test(config, "test_call_creds_failure", 0); gpr_timespec deadline = five_seconds_time(); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", deadline); @@ -172,7 +183,7 @@ static void request_response_with_payload_and_call_creds( grpc_auth_context *s_auth_context = NULL; grpc_auth_context *c_auth_context = NULL; - f = begin_test(config, test_name); + f = begin_test(config, test_name, 0); cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", @@ -365,11 +376,100 @@ static void test_request_response_with_payload_and_deleted_call_creds( DESTROY); } +static void test_request_with_server_rejecting_client_creds( + grpc_end2end_test_config config) { + grpc_op ops[6]; + grpc_op *op; + grpc_call *c; + grpc_end2end_test_fixture f; + gpr_timespec deadline = five_seconds_time(); + cq_verifier *cqv; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_call_details call_details; + grpc_status_code status; + char *details = NULL; + size_t details_capacity = 0; + grpc_byte_buffer *response_payload_recv = NULL; + gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world"); + grpc_byte_buffer *request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_credentials *creds; + + f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1); + cqv = cq_verifier_create(f.cq); + + c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", + deadline); + GPR_ASSERT(c); + + creds = grpc_iam_credentials_create(iam_token, iam_selector); + GPR_ASSERT(creds != NULL); + GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); + grpc_credentials_release(creds); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + op = ops; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message = request_payload; + op->flags = 0; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message = &response_payload_recv; + op->flags = 0; + op++; + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1))); + + cq_expect_completion(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED); + + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload_recv); + gpr_free(details); + + grpc_call_destroy(c); + + cq_verifier_destroy(cqv); + end_test(&f); + config.tear_down_data(&f); +} + void grpc_end2end_tests(grpc_end2end_test_config config) { if (config.feature_mask & FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS) { test_call_creds_failure(config); test_request_response_with_payload_and_call_creds(config); test_request_response_with_payload_and_overridden_call_creds(config); test_request_response_with_payload_and_deleted_call_creds(config); + test_request_with_server_rejecting_client_creds(config); } } From 7c8d255527cbec8b261300296d61361ce94e9d18 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Wed, 5 Aug 2015 20:16:01 -0700 Subject: [PATCH 030/117] Cleanup. --- src/core/security/security_context.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 3ad57cadea6..7fcd438cf6f 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -78,8 +78,6 @@ grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); void grpc_auth_context_unref(grpc_auth_context *policy); #endif -/* Get the pollset. */ - void grpc_auth_property_reset(grpc_auth_property *property); /* --- grpc_client_security_context --- From 54b5018dd889cbc5059ff77ba083ff7020c63a9b Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Wed, 5 Aug 2015 21:40:49 -0700 Subject: [PATCH 031/117] Fixing cpp tests. --- test/cpp/common/auth_property_iterator_test.cc | 4 ++++ test/cpp/common/secure_auth_context_test.cc | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc index 6443e2fd85c..74b18ced0d5 100644 --- a/test/cpp/common/auth_property_iterator_test.cc +++ b/test/cpp/common/auth_property_iterator_test.cc @@ -36,6 +36,10 @@ #include #include "src/cpp/common/secure_auth_context.h" +extern "C" { +#include "src/core/security/security_context.h" +} + namespace grpc { namespace { diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index bdc5cf73bb6..075d4ce8c98 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -36,6 +36,10 @@ #include #include "src/cpp/common/secure_auth_context.h" +extern "C" { +#include "src/core/security/security_context.h" +} + namespace grpc { namespace { From b2bd06775e255ebf7de96eb00a5b1738311c682e Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sat, 1 Aug 2015 23:19:11 -0700 Subject: [PATCH 032/117] Require very explicit registration of non-SSL hosts. --- src/objective-c/GRPCClient/GRPCCall+Tests.h | 4 ++ src/objective-c/GRPCClient/GRPCCall+Tests.m | 8 +++- src/objective-c/GRPCClient/private/GRPCHost.m | 37 +++++++------------ src/objective-c/tests/GRPCClientTests.m | 7 +++- src/objective-c/tests/InteropTests.h | 2 +- src/objective-c/tests/InteropTests.m | 10 ++++- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h index 3d617b05d99..981b154b406 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.h +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h @@ -33,6 +33,8 @@ #import "GRPCCall.h" +// Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be +// used in releases, but are sometimes needed for testing. @interface GRPCCall (Tests) // Establish all SSL connections to the provided host using the passed SSL target name and the root @@ -42,4 +44,6 @@ testName:(NSString *)testName forHost:(NSString *)host; +// Establish all connections to the provided host using cleartext instead of SSL. ++ (void)useInsecureConnectionsForHost:(NSString *)host; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m index 7c5b81d661d..bade0b29208 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.m +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m @@ -36,12 +36,18 @@ #import "private/GRPCHost.h" @implementation GRPCCall (Tests) + + (void)useTestCertsPath:(NSString *)certsPath testName:(NSString *)testName forHost:(NSString *)host { GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; - hostConfig.secure = YES; hostConfig.pathToCertificates = certsPath; hostConfig.hostNameOverride = testName; } + ++ (void)useInsecureConnectionsForHost:(NSString *)host { + GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; + hostConfig.secure = NO; +} + @end diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 5d9c48a5245..14bde92d984 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -58,22 +58,12 @@ // Default initializer. - (instancetype)initWithAddress:(NSString *)address { - // Verify and normalize the address, and decide whether to use SSL. - if (![address rangeOfString:@"://"].length) { - // No scheme provided; assume https. - address = [@"https://" stringByAppendingString:address]; + // To provide a default port, we try to interpret the address. + // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass through. + NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; + if (hostURL && !hostURL.port) { + address = [hostURL.host stringByAppendingString:@":443"]; } - NSURL *hostURL = [NSURL URLWithString:address]; - if (!hostURL) { - [NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", address]; - } - NSString *scheme = hostURL.scheme; - if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) { - [NSException raise:NSInvalidArgumentException format:@"URL scheme %@ isn't supported.", scheme]; - } - // If the user didn't specify a port (hostURL.port is nil), provide a default one. - NSNumber *port = hostURL.port ?: [scheme isEqualToString:@"https"] ? @443 : @80; - address = [@[hostURL.host, port] componentsJoinedByString:@":"]; // Look up the GRPCHost in the cache. static NSMutableDictionary *hostCache; @@ -84,19 +74,15 @@ @synchronized(hostCache) { GRPCHost *cachedHost = hostCache[address]; if (cachedHost) { - // We could verify here that the cached host uses the same protocol that we're expecting. But - // creating non-SSL channels by adding "http://" to the address is going away (to make the use - // of insecure channels less subtle), so it's not worth it now. return cachedHost; } - if ((self = [super init])) { - _address = address; - _secure = [scheme isEqualToString:@"https"]; - hostCache[address] = self; - } - return self; + if ((self = [super init])) { + _address = address; + _secure = YES; + hostCache[address] = self; } + return self; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue { @@ -131,4 +117,7 @@ return _hostNameOverride ?: _address; } +// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride| +// have been set. Don't let set either of the latter if |secure| has been set to |NO|. + @end diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 103e5ca3d49..e5d7e43ed92 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -35,6 +35,7 @@ #import #import +#import #import #import #import @@ -43,8 +44,7 @@ // These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) // rather than a generated proto library on top of it. -// grpc-test.sandbox.google.com -static NSString * const kHostAddress = @"http://localhost:5050"; +static NSString * const kHostAddress = @"localhost:5050"; static NSString * const kPackage = @"grpc.testing"; static NSString * const kService = @"TestService"; @@ -58,6 +58,9 @@ static ProtoMethod *kUnaryCallMethod; @implementation GRPCClientTests - (void)setUp { + // Register test server as non-SSL. + [GRPCCall useInsecureConnectionsForHost:kHostAddress]; + // This method isn't implemented by the remote server. kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage service:kService diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h index c675c8d2410..4eb97e9e06e 100644 --- a/src/objective-c/tests/InteropTests.h +++ b/src/objective-c/tests/InteropTests.h @@ -37,7 +37,7 @@ // https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md @interface InteropTests : XCTestCase -// Returns @"http://localhost:5050". +// Returns @"localhost:5050". // Override in a subclass to perform the same tests against a different address. // For interop tests, use @"grpc-test.sandbox.google.com". + (NSString *)host; diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index a6611d27be6..b61d5674649 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -35,6 +35,7 @@ #include +#import #import #import #import @@ -75,15 +76,22 @@ } @end +#pragma mark Tests + +static NSString * const kLocalCleartextHost = @"localhost:5050"; + @implementation InteropTests { RMTTestService *_service; } + (NSString *)host { - return @"http://localhost:5050"; + return kLocalCleartextHost; } - (void)setUp { + // Register test server as non-SSL. + [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost]; + _service = [[RMTTestService alloc] initWithHost:self.class.host]; } From 1116b0b4fb538e68044cf42ed8307ce1db96a6b8 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Thu, 6 Aug 2015 12:37:05 -0700 Subject: [PATCH 033/117] Fix debug annotation typo in Python --- src/python/grpcio/grpc/_adapter/_c/types/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c index c2190ea672d..2a11d09d218 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/server.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/server.c @@ -96,7 +96,7 @@ Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *py_args; grpc_channel_args c_args; char *keywords[] = {"cq", "args", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Channel", keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Server", keywords, &pygrpc_CompletionQueue_type, &cq, &py_args)) { return NULL; } From 55fcf504b9d5da7c4144a0d2a60bea748a1d8757 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Thu, 6 Aug 2015 12:41:04 -0700 Subject: [PATCH 034/117] Document that methods in GRPCCall+Tests can only be called once per host --- src/objective-c/GRPCClient/GRPCCall+Tests.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h index 981b154b406..cca16146063 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.h +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h @@ -39,11 +39,16 @@ // Establish all SSL connections to the provided host using the passed SSL target name and the root // certificates found in the file at |certsPath|. -// Must be called before any gRPC call to that host is made. +// +// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to +// more than one invocation of the methods of this category. + (void)useTestCertsPath:(NSString *)certsPath testName:(NSString *)testName forHost:(NSString *)host; // Establish all connections to the provided host using cleartext instead of SSL. +// +// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to +// more than one invocation of the methods of this category. + (void)useInsecureConnectionsForHost:(NSString *)host; @end From aee5d5c0528178345d99bb3823d06f19a93a3314 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 13:12:22 -0700 Subject: [PATCH 035/117] Print error message on client auth error --- src/core/security/client_auth_filter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index e2d1b6fce91..0e699874bcd 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -77,6 +77,7 @@ typedef struct { static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { call_data *calld = elem->call_data; + gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); grpc_transport_stream_op_add_cancellation(&calld->op, GRPC_STATUS_UNAUTHENTICATED); grpc_call_next_op(elem, &calld->op); From a3adf944774776a4f413d387c8195935f27659dc Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Thu, 6 Aug 2015 12:09:25 -0700 Subject: [PATCH 036/117] Clarify interop spec --- doc/interop-test-descriptions.md | 131 ++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 38 deletions(-) diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index 065e107c249..84ceaa3081a 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -55,7 +55,7 @@ Server features: Procedure: 1. Client calls EmptyCall with the default Empty message -Asserts: +Client asserts: * call was successful * response is non-null @@ -84,7 +84,7 @@ Procedure: } ``` -Asserts: +Client asserts: * call was successful * response payload type is COMPRESSABLE * response payload body is 314159 bytes in size @@ -110,6 +110,7 @@ Procedure: } } ``` + 3. Client then sends: ``` @@ -119,6 +120,7 @@ Procedure: } } ``` + 4. Client then sends: ``` @@ -128,6 +130,7 @@ Procedure: } } ``` + 5. Client then sends: ``` @@ -137,9 +140,10 @@ Procedure: } } ``` - 6. Client halfCloses -Asserts: + 6. Client half-closes + +Client asserts: * call was successful * response aggregated_payload_size is 74922 @@ -172,7 +176,7 @@ Procedure: } ``` -Asserts: +Client asserts: * call was successful * exactly four responses * response payloads are COMPRESSABLE @@ -202,6 +206,7 @@ Procedure: } } ``` + 2. After getting a reply, it sends: ``` @@ -215,6 +220,7 @@ Procedure: } } ``` + 3. After getting a reply, it sends: ``` @@ -228,6 +234,7 @@ Procedure: } } ``` + 4. After getting a reply, it sends: ``` @@ -242,7 +249,9 @@ Procedure: } ``` -Asserts: + 5. After getting a reply, client half-closes + +Client asserts: * call was successful * exactly four responses * response payloads are COMPRESSABLE @@ -261,7 +270,7 @@ Server features: Procedure: 1. Client calls FullDuplexCall and then half-closes -Asserts: +Client asserts: * call was successful * exactly zero responses @@ -300,7 +309,7 @@ Procedure: } ``` -Asserts: +Client asserts: * call was successful * received SimpleResponse.username equals the value of `--default_service_account` flag * received SimpleResponse.oauth_scope is in `--oauth_scope` @@ -328,7 +337,7 @@ Server features: * [Echo OAuth Scope][] Procedure: - 1. Client configures the channel to use ServiceAccountCredentials. + 1. Client configures the channel to use ServiceAccountCredentials 2. Client calls UnaryCall with: ``` @@ -343,7 +352,7 @@ Procedure: } ``` -Asserts: +Client asserts: * call was successful * received SimpleResponse.username is in the json key file read from `--service_account_key_file` @@ -370,7 +379,7 @@ Server features: * [Echo OAuth Scope][] Procedure: - 1. Client configures the channel to use JWTTokenCredentials. + 1. Client configures the channel to use JWTTokenCredentials 2. Client calls UnaryCall with: ``` @@ -384,7 +393,7 @@ Procedure: } ``` -Asserts: +Client asserts: * call was successful * received SimpleResponse.username is in the json key file read from `--service_account_key_file` @@ -422,7 +431,7 @@ Server features: Procedure: 1. Client uses the auth library to obtain an authorization token - 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1. + 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1 3. Client calls UnaryCall with the following message ``` @@ -431,8 +440,8 @@ Procedure: fill_oauth_scope: true } ``` - -Asserts: + +Client asserts: * call was successful * received SimpleResponse.username is in the json key file used by the auth library to obtain the authorization token @@ -464,10 +473,10 @@ Server features: Procedure: 1. Client uses the auth library to obtain an authorization token - 2. Client configures the channel with just SSL credentials. + 2. Client configures the channel with just SSL credentials 3. Client calls UnaryCall, setting per-call credentials to - AccessTokenCredentials with the access token obtained in step 1. The request is - the following message + AccessTokenCredentials with the access token obtained in step 1. The request + is the following message ``` { @@ -475,8 +484,8 @@ Procedure: fill_oauth_scope: true } ``` - -Asserts: + +Client asserts: * call was successful * received SimpleResponse.username is in the json key file used by the auth library to obtain the authorization token @@ -496,8 +505,14 @@ Server features: * [Echo Metadata][] Procedure: - 1. While sending custom metadata (ascii + binary) in the header, client calls - UnaryCall with: + 1. The client attaches custom metadata with the following keys and values: + + ``` + key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value" + key: "x-grpc-test-echo-trailing-bin", value: 0xababab + ``` + + to a UnaryCall with request: ``` { @@ -508,23 +523,41 @@ Procedure: } } ``` -The client attaches custom metadata with the following keys and values: + + 2. The client attaches custom metadata with the following keys and values: + ``` key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value" key: "x-grpc-test-echo-trailing-bin", value: 0xababab ``` - 2. Client repeats step 1. with FullDuplexCall instead of UnaryCall. -Asserts: + to a FullDuplexCall with request: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + + and then half-closes + +Client asserts: * call was successful -* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata. -* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata. +* metadata with key `"x-grpc-test-echo-initial"` and value + `"test_initial_metadata_value"`is received in the initial metadata for calls + in Procedure steps 1 and 2. +* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is + received in the trailing metadata for calls in Procedure steps 1 and 2. ### status_code_and_message -This test verifies unary calls succeed in sending messages, and propagates back +This test verifies unary calls succeed in sending messages, and propagate back status code and message sent along with the messages. Server features: @@ -543,12 +576,26 @@ Procedure: } } ``` -2. Client repeats step 1. with FullDuplexCall instead of UnaryCall. + 2. Client calls FullDuplexCall with: + + ``` + { + response_status:{ + code: 2 + message: "test status message" + } + } + ``` + + and then half-closes -Asserts: -* received status code is the same with sent code -* received status message is the same with sent message + +Client asserts: +* received status code is the same as the sent code for both Procedure steps 1 + and 2 +* received status message is the same as the sent message for both Procedure + steps 1 and 2 ### unimplemented_method @@ -556,15 +603,19 @@ Status: Ready for implementation. Blocking beta. This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code. +Server features: +N/A + Procedure: -* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`): +* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an + empty request (defined as `grpc.testing.Empty`): ``` { } ``` -Asserts: +Client asserts: * received status code is 12 (UNIMPLEMENTED) * received status message is empty or null/unset @@ -580,7 +631,7 @@ Procedure: 1. Client starts StreamingInputCall 2. Client immediately cancels request -Asserts: +Client asserts: * Call completed with status CANCELLED ### cancel_after_first_response @@ -606,9 +657,10 @@ Procedure: } } ``` + 2. After receiving a response, client cancels request -Asserts: +Client asserts: * Call completed with status CANCELLED ### timeout_on_sleeping_server @@ -620,7 +672,8 @@ Server features: * [FullDuplexCall][] Procedure: - 1. Client calls FullDuplexCall with the following request and sets its timeout to 1ms. + 1. Client calls FullDuplexCall with the following request and sets its timeout + to 1ms ``` { @@ -630,7 +683,9 @@ Procedure: } ``` -Asserts: + 2. Client waits + +Client asserts: * Call completed with status DEADLINE_EXCEEDED. ### concurrent_large_unary From 6107bf457a62d8c5035565acc2e1476240806fd1 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Thu, 6 Aug 2015 11:01:11 -0700 Subject: [PATCH 037/117] Set Python user-agent string --- src/python/grpcio/grpc/_adapter/_c/module.c | 6 ++++++ src/python/grpcio/grpc/_adapter/_low.py | 4 ++++ .../grpcio_test/grpc_test/_adapter/_low_test.py | 17 ++++++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/python/grpcio/grpc/_adapter/_c/module.c b/src/python/grpcio/grpc/_adapter/_c/module.c index 1f3aedd9d85..9b93b051f67 100644 --- a/src/python/grpcio/grpc/_adapter/_c/module.c +++ b/src/python/grpcio/grpc/_adapter/_c/module.c @@ -53,6 +53,12 @@ PyMODINIT_FUNC init_c(void) { return; } + if (PyModule_AddStringConstant( + module, "PRIMARY_USER_AGENT_KEY", + GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) { + return; + } + /* GRPC maintains an internal counter of how many times it has been initialized and handles multiple pairs of grpc_init()/grpc_shutdown() invocations accordingly. */ diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py index dcf67dbc117..239aac81b2a 100644 --- a/src/python/grpcio/grpc/_adapter/_low.py +++ b/src/python/grpcio/grpc/_adapter/_low.py @@ -27,9 +27,12 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from grpc import _grpcio_metadata from grpc._adapter import _c from grpc._adapter import _types +_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) + ClientCredentials = _c.ClientCredentials ServerCredentials = _c.ServerCredentials @@ -76,6 +79,7 @@ class Call(_types.Call): class Channel(_types.Channel): def __init__(self, target, args, creds=None): + args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)] if creds is None: self.channel = _c.Channel(target, args) else: diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py index 9a8edfad0cb..b6583662f34 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py +++ b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py @@ -31,11 +31,12 @@ import threading import time import unittest +from grpc import _grpcio_metadata from grpc._adapter import _types from grpc._adapter import _low -def WaitForEvents(completion_queues, deadline): +def wait_for_events(completion_queues, deadline): """ Args: completion_queues: list of completion queues to wait for events on @@ -62,6 +63,7 @@ def WaitForEvents(completion_queues, deadline): thread.join() return results + class InsecureServerInsecureClient(unittest.TestCase): def setUp(self): @@ -123,16 +125,21 @@ class InsecureServerInsecureClient(unittest.TestCase): ], client_call_tag) self.assertEquals(_types.CallError.OK, client_start_batch_result) - client_no_event, request_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 2) + client_no_event, request_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 2) self.assertEquals(client_no_event, None) self.assertEquals(_types.EventType.OP_COMPLETE, request_event.type) self.assertIsInstance(request_event.call, _low.Call) self.assertIs(server_request_tag, request_event.tag) self.assertEquals(1, len(request_event.results)) - got_initial_metadata = dict(request_event.results[0].initial_metadata) + received_initial_metadata = dict(request_event.results[0].initial_metadata) + # Check that our metadata were transmitted self.assertEquals( dict(client_initial_metadata), - dict((x, got_initial_metadata[x]) for x in zip(*client_initial_metadata)[0])) + dict((x, received_initial_metadata[x]) for x in zip(*client_initial_metadata)[0])) + # Check that Python's user agent string is a part of the full user agent + # string + self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__), + received_initial_metadata['user-agent']) self.assertEquals(METHOD, request_event.call_details.method) self.assertEquals(HOST, request_event.call_details.host) self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE) @@ -150,7 +157,7 @@ class InsecureServerInsecureClient(unittest.TestCase): ], server_call_tag) self.assertEquals(_types.CallError.OK, server_start_batch_result) - client_event, server_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 1) + client_event, server_event, = wait_for_events([self.client_completion_queue, self.server_completion_queue], time.time() + 1) self.assertEquals(6, len(client_event.results)) found_client_op_types = set() From da1db029bf7357b4c063d8718ff4fbd2e19c7a76 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 13:43:04 -0700 Subject: [PATCH 038/117] Document op completion --- include/grpc/grpc.h | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index bf340e81ca0..c2142c31f04 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -256,31 +256,44 @@ void grpc_call_details_destroy(grpc_call_details *details); typedef enum { /** Send initial metadata: one and only one instance MUST be sent for each - call, unless the call was cancelled - in which case this can be skipped */ + call, unless the call was cancelled - in which case this can be skipped. + This op completes after all bytes of metadata have been accepted by + outgoing flow control. */ GRPC_OP_SEND_INITIAL_METADATA = 0, - /** Send a message: 0 or more of these operations can occur for each call */ + /** Send a message: 0 or more of these operations can occur for each call. + This op completes after all bytes for the message have been accepted by + outgoing flow control. */ GRPC_OP_SEND_MESSAGE, /** Send a close from the client: one and only one instance MUST be sent from the client, unless the call was cancelled - in which case this can be - skipped */ + skipped. + This op completes after all bytes for the call (including the close) + have passed outgoing flow control. */ GRPC_OP_SEND_CLOSE_FROM_CLIENT, /** Send status from the server: one and only one instance MUST be sent from the server unless the call was cancelled - in which case this can be - skipped */ + skipped. + This op completes after all bytes for the call (including the status) + have passed outgoing flow control. */ GRPC_OP_SEND_STATUS_FROM_SERVER, /** Receive initial metadata: one and only one MUST be made on the client, - must not be made on the server */ + must not be made on the server. + This op completes after all initial metadata has been read from the + peer. */ GRPC_OP_RECV_INITIAL_METADATA, - /** Receive a message: 0 or more of these operations can occur for each call - */ + /** Receive a message: 0 or more of these operations can occur for each call. + This op completes after all bytes of the received message have been + read, or after a half-close has been received on this call. */ GRPC_OP_RECV_MESSAGE, /** Receive status on the client: one and only one must be made on the client. - This operation always succeeds, meaning ops paired with this operation - will also appear to succeed, even though they may not have. In that case - the status will indicate some failure. */ + This operation always succeeds, meaning ops paired with this operation + will also appear to succeed, even though they may not have. In that case + the status will indicate some failure. + This op completes after all activity on the call has completed. */ GRPC_OP_RECV_STATUS_ON_CLIENT, /** Receive close on the server: one and only one must be made on the - server */ + server. + This op completes after the close has been received by the server. */ GRPC_OP_RECV_CLOSE_ON_SERVER } grpc_op_type; From 8e5de39fb959b959dd97e0c05ced818c34c02e32 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 13:50:08 -0700 Subject: [PATCH 039/117] Document finish --- include/grpc++/stream.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/grpc++/stream.h b/include/grpc++/stream.h index 3903f2ec06c..bc0c3c0f3b2 100644 --- a/include/grpc++/stream.h +++ b/include/grpc++/stream.h @@ -54,7 +54,11 @@ class ClientStreamingInterface { // client side declares it has no more message to send, either implicitly or // by calling WritesDone, it needs to make sure there is no more message to // be received from the server, either implicitly or by getting a false from - // a Read(). Otherwise, this implicitly cancels the stream. + // a Read(). + // This function will return either: + // - when all incoming messages have been read and the server has returned + // status + // - OR when the server has returned a non-OK status virtual Status Finish() = 0; }; From 9a0c10efc6b936acdbafde338cf3ed8ccfb2f689 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 15:47:32 -0700 Subject: [PATCH 040/117] Windows fix --- tools/run_tests/port_server.py | 2 +- tools/run_tests/run_tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py index 660928fbe79..0f81470d28f 100755 --- a/tools/run_tests/port_server.py +++ b/tools/run_tests/port_server.py @@ -47,7 +47,7 @@ print 'port server running on port %d' % args.port pool = [] in_use = {} -with open(sys.argv[0]) as f: +with open(__file__) as f: _MY_VERSION = hashlib.sha1(f.read()).hexdigest() diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index c9c6498b367..2ca1f0ea697 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -548,7 +548,7 @@ def _start_port_server(port_server_port): if not running: port_log = open('portlog.txt', 'w') port_server = subprocess.Popen( - ['tools/run_tests/port_server.py', '-p', '%d' % port_server_port], + ['python', 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port], stderr=subprocess.STDOUT, stdout=port_log) # ensure port server is up From 09316e7605bd7768e375a393f7cf9cbce50189f6 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Thu, 6 Aug 2015 15:48:42 -0700 Subject: [PATCH 041/117] Fixing build. --- .../tests/request_response_with_payload_and_call_creds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index 0ea7b30fc55..342dfa03f6b 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -400,8 +400,8 @@ static void test_request_with_server_rejecting_client_creds( f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1); cqv = cq_verifier_create(f.cq); - c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", - deadline); + c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, + "/foo", "foo.test.google.fr", deadline); GPR_ASSERT(c); creds = grpc_iam_credentials_create(iam_token, iam_selector); From 29c990abccc8be833a87da633c4ff6f4cf5b4e66 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Thu, 6 Aug 2015 15:53:33 -0700 Subject: [PATCH 042/117] fixing one more test. --- .../chttp2_simple_ssl_fullstack_with_proxy.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c index 46a64de6c50..4d77039cac1 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c @@ -96,6 +96,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( return f; } +static void process_auth_failure(void *state, grpc_auth_context *ctx, + const grpc_metadata *md, size_t md_count, + grpc_process_auth_metadata_done_cb cb, + void *user_data) { + GPR_ASSERT(state == NULL); + cb(user_data, NULL, 0, 0); +} + static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { @@ -139,12 +147,28 @@ static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_channel_args_destroy(new_client_args); } +static int fail_server_auth_check(grpc_channel_args *server_args) { + size_t i; + if (server_args == NULL) return 0; + for (i = 0; i < server_args->num_args; i++) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == + 0) { + return 1; + } + } + return 0; +} + static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + if (fail_server_auth_check(server_args)) { + grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; + grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); + } chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); } From 015ab35a2875059c9047de2286c22c96a01628cb Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Thu, 6 Aug 2015 16:51:44 -0700 Subject: [PATCH 043/117] Clarify intention of the code that adds a default port --- src/objective-c/GRPCClient/private/GRPCHost.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 14bde92d984..6636c486202 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -58,8 +58,10 @@ // Default initializer. - (instancetype)initWithAddress:(NSString *)address { - // To provide a default port, we try to interpret the address. - // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass through. + // To provide a default port, we try to interpret the address. If it's just a host name without + // scheme and without port, we'll use port 443. If it has a scheme, we pass it untouched to the C + // gRPC library. + // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched. NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; if (hostURL && !hostURL.port) { address = [hostURL.host stringByAppendingString:@":443"]; From b933c2cd55883880b4babc6055f9bbdaa9267476 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 17:49:49 -0700 Subject: [PATCH 044/117] Fix memory leaks --- test/core/util/port_posix.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c index 62d5e7df20a..9bff18d3117 100644 --- a/test/core/util/port_posix.c +++ b/test/core/util/port_posix.c @@ -153,6 +153,11 @@ static void got_port_from_server(void *arg, gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset)); } +static void destroy_pollset_and_shutdown(void *p) { + grpc_pollset_destroy(p); + grpc_shutdown(); +} + static int pick_port_using_server(char *server) { grpc_httpcli_context context; grpc_httpcli_request req; @@ -180,7 +185,8 @@ static int pick_port_using_server(char *server) { } gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset)); - grpc_shutdown(); + grpc_httpcli_context_destroy(&context); + grpc_pollset_shutdown(&pr.pollset, destroy_pollset_and_shutdown, &pr.pollset); return pr.port; } From 63323e3c07521e644a5d44a32849526a0bb20a13 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 7 Aug 2015 02:56:13 +0200 Subject: [PATCH 045/117] Re-enabling tests that got culled off. --- tools/buildgen/plugins/expand_bin_attrs.py | 3 +- tools/run_tests/tests.json | 146 +++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/tools/buildgen/plugins/expand_bin_attrs.py b/tools/buildgen/plugins/expand_bin_attrs.py index 9c6c31e9a39..e35b9fe740a 100755 --- a/tools/buildgen/plugins/expand_bin_attrs.py +++ b/tools/buildgen/plugins/expand_bin_attrs.py @@ -44,8 +44,9 @@ def mako_plugin(dictionary): """ targets = dictionary.get('targets') + default_platforms = ['windows', 'posix', 'linux', 'mac'] for tgt in targets: tgt['flaky'] = tgt.get('flaky', False) - tgt['platforms'] = sorted(tgt.get('platforms', ['windows', 'posix'])) + tgt['platforms'] = sorted(tgt.get('platforms', default_platforms)) diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 01920364208..f2fbc92e934 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -6,6 +6,8 @@ "language": "c", "name": "alarm_heap_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -15,6 +17,8 @@ "language": "c", "name": "alarm_list_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -24,6 +28,8 @@ "language": "c", "name": "alarm_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -33,6 +39,8 @@ "language": "c", "name": "alpn_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -42,6 +50,8 @@ "language": "c", "name": "bin_encoder_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -51,6 +61,8 @@ "language": "c", "name": "chttp2_status_conversion_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -60,6 +72,8 @@ "language": "c", "name": "chttp2_stream_encoder_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -69,6 +83,8 @@ "language": "c", "name": "chttp2_stream_map_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -128,6 +144,8 @@ "language": "c", "name": "gpr_cancellable_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -137,6 +155,8 @@ "language": "c", "name": "gpr_cmdline_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -146,6 +166,8 @@ "language": "c", "name": "gpr_env_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -155,6 +177,8 @@ "language": "c", "name": "gpr_file_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -164,6 +188,8 @@ "language": "c", "name": "gpr_histogram_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -173,6 +199,8 @@ "language": "c", "name": "gpr_host_port_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -182,6 +210,8 @@ "language": "c", "name": "gpr_log_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -191,6 +221,8 @@ "language": "c", "name": "gpr_slice_buffer_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -200,6 +232,8 @@ "language": "c", "name": "gpr_slice_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -209,6 +243,8 @@ "language": "c", "name": "gpr_stack_lockfree_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -218,6 +254,8 @@ "language": "c", "name": "gpr_string_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -227,6 +265,8 @@ "language": "c", "name": "gpr_sync_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -236,6 +276,8 @@ "language": "c", "name": "gpr_thd_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -245,6 +287,8 @@ "language": "c", "name": "gpr_time_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -254,6 +298,8 @@ "language": "c", "name": "gpr_tls_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -263,6 +309,8 @@ "language": "c", "name": "gpr_useful_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -272,6 +320,8 @@ "language": "c", "name": "grpc_auth_context_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -281,6 +331,8 @@ "language": "c", "name": "grpc_base64_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -290,6 +342,8 @@ "language": "c", "name": "grpc_byte_buffer_reader_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -299,6 +353,8 @@ "language": "c", "name": "grpc_channel_stack_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -308,6 +364,8 @@ "language": "c", "name": "grpc_completion_queue_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -317,6 +375,8 @@ "language": "c", "name": "grpc_credentials_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -326,6 +386,8 @@ "language": "c", "name": "grpc_json_token_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -335,6 +397,8 @@ "language": "c", "name": "grpc_jwt_verifier_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -344,6 +408,8 @@ "language": "c", "name": "grpc_security_connector_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -353,6 +419,8 @@ "language": "c", "name": "grpc_stream_op_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -362,6 +430,8 @@ "language": "c", "name": "hpack_parser_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -371,6 +441,8 @@ "language": "c", "name": "hpack_table_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -380,6 +452,8 @@ "language": "c", "name": "httpcli_format_request_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -389,6 +463,8 @@ "language": "c", "name": "httpcli_parser_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -408,6 +484,8 @@ "language": "c", "name": "json_rewrite_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -417,6 +495,8 @@ "language": "c", "name": "json_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -426,6 +506,8 @@ "language": "c", "name": "lame_client_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -435,6 +517,8 @@ "language": "c", "name": "message_compress_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -444,6 +528,8 @@ "language": "c", "name": "multi_init_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -453,6 +539,8 @@ "language": "c", "name": "multiple_server_queues_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -462,6 +550,8 @@ "language": "c", "name": "murmur_hash_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -471,6 +561,8 @@ "language": "c", "name": "no_server_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -480,6 +572,8 @@ "language": "c", "name": "resolve_address_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -489,6 +583,8 @@ "language": "c", "name": "secure_endpoint_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -498,6 +594,8 @@ "language": "c", "name": "sockaddr_utils_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -537,6 +635,8 @@ "language": "c", "name": "time_averaged_stats_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -546,6 +646,8 @@ "language": "c", "name": "timeout_encoding_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -555,6 +657,8 @@ "language": "c", "name": "timers_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -564,6 +668,8 @@ "language": "c", "name": "transport_metadata_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -573,6 +679,8 @@ "language": "c", "name": "transport_security_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -582,6 +690,8 @@ "language": "c", "name": "uri_parser_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -591,6 +701,8 @@ "language": "c++", "name": "async_end2end_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -620,6 +732,8 @@ "language": "c++", "name": "auth_property_iterator_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -629,6 +743,8 @@ "language": "c++", "name": "channel_arguments_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -638,6 +754,8 @@ "language": "c++", "name": "cli_call_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -657,6 +775,8 @@ "language": "c++", "name": "credentials_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -666,6 +786,8 @@ "language": "c++", "name": "cxx_byte_buffer_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -675,6 +797,8 @@ "language": "c++", "name": "cxx_slice_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -684,6 +808,8 @@ "language": "c++", "name": "cxx_time_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -693,6 +819,8 @@ "language": "c++", "name": "dynamic_thread_pool_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -702,6 +830,8 @@ "language": "c++", "name": "end2end_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -711,6 +841,8 @@ "language": "c++", "name": "fixed_size_thread_pool_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -720,6 +852,8 @@ "language": "c++", "name": "generic_end2end_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -739,6 +873,8 @@ "language": "c++", "name": "mock_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -768,6 +904,8 @@ "language": "c++", "name": "secure_auth_context_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -787,6 +925,8 @@ "language": "c++", "name": "status_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -816,6 +956,8 @@ "language": "c++", "name": "thread_stress_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -8089,6 +8231,8 @@ "language": "c", "name": "connection_prefix_bad_client_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] @@ -8098,6 +8242,8 @@ "language": "c", "name": "initial_settings_frame_bad_client_test", "platforms": [ + "linux", + "mac", "posix", "windows" ] From 6659d8b89c0a4c93b8fbba7289cfaea09c326a50 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Aug 2015 18:02:22 -0700 Subject: [PATCH 046/117] Fix memory leaks --- src/core/channel/client_channel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 2ee260b7991..a293c93ec64 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -401,6 +401,7 @@ static void perform_transport_stream_op(grpc_call_element *elem, calld->state = CALL_WAITING_FOR_CONFIG; add_to_lb_policy_wait_queue_locked_state_config(elem); if (!chand->started_resolving && chand->resolver != NULL) { + GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); chand->started_resolving = 1; grpc_resolver_next(chand->resolver, &chand->incoming_configuration, @@ -701,11 +702,11 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack, gpr_mu_lock(&chand->mu_config); GPR_ASSERT(!chand->resolver); chand->resolver = resolver; - GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); GRPC_RESOLVER_REF(resolver, "channel"); if (chand->waiting_for_config_closures != NULL || chand->exit_idle_when_lb_policy_arrives) { chand->started_resolving = 1; + GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); grpc_resolver_next(resolver, &chand->incoming_configuration, &chand->on_config_changed); } @@ -724,6 +725,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state( } else { chand->exit_idle_when_lb_policy_arrives = 1; if (!chand->started_resolving && chand->resolver != NULL) { + GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); chand->started_resolving = 1; grpc_resolver_next(chand->resolver, &chand->incoming_configuration, &chand->on_config_changed); From 971d06ad06caadb369e318112bba0e039188cfc2 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Thu, 6 Aug 2015 20:45:37 -0700 Subject: [PATCH 047/117] Fix build breakage --- src/objective-c/GRPCClient/private/GRPCHost.m | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 6636c486202..45e5f0602da 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -78,6 +78,7 @@ if (cachedHost) { return cachedHost; } + } if ((self = [super init])) { _address = address; From 594ae574ad94476e9913c9cb723d929f09c4b918 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Thu, 6 Aug 2015 22:08:53 -0700 Subject: [PATCH 048/117] Add OAuth2 headers category to GRPCCall --- src/objective-c/GRPCClient/GRPCCall+OAuth2.h | 49 +++++++++++++++ src/objective-c/GRPCClient/GRPCCall+OAuth2.m | 63 ++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/objective-c/GRPCClient/GRPCCall+OAuth2.h create mode 100644 src/objective-c/GRPCClient/GRPCCall+OAuth2.m diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h new file mode 100644 index 00000000000..f14fe254b0f --- /dev/null +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "GRPCCall.h" + +// Helpers for setting and reading headers compatible with OAuth2. +@interface GRPCCall (OAuth2) + +// Setting this property is equivalent to setting "Bearer " as the value of the +// request header with key "authorization" (the authorization header). Setting it to nil removes the +// authorization header from the request. +// The value obtained by getting the property is the OAuth2 bearer token if the authorization header +// of the request has the form "Bearer ", or nil otherwise. +@property(atomic, copy) NSString *oauth2_accessToken; + +// Returns the value (if any) of the "www-authenticate" response header (the challenge header). +@property(atomic, readonly) NSString *oauth2_challengeHeader; + +@end diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m new file mode 100644 index 00000000000..77d00f260eb --- /dev/null +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "GRPCCall+OAuth2.h" + +static NSString * const kAuthorizationHeader = @"authorization"; +static NSString * const kBearerPrefix = @"Bearer "; +static NSString * const kChallengeHeader = @"www-authenticate"; + +@implementation GRPCCall (OAuth2) + +- (NSString *)oauth2_accessToken { + NSString *headerValue = self.requestMetadata[kAuthorizationHeader]; + if ([headerValue hasPrefix:kBearerPrefix]) { + return [headerValue substringFromIndex:kBearerPrefix.length]; + } else { + return nil; + } +} + +- (void)setOauth2_accessToken:(NSString *)token { + if (token) { + self.requestMetadata[kAuthorizationHeader] = [kBearerPrefix stringByAppendingString:token]; + } else { + [self.requestMetadata removeObjectForKey:kAuthorizationHeader]; + } +} + +- (NSString *)oauth2_challengeHeader { + return self.responseMetadata[kChallengeHeader]; +} + +@end From c8abca8f5311832f41751ab11bb2365f9e348ad8 Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Aug 2015 22:50:16 -0700 Subject: [PATCH 049/117] Resolve comments --- include/grpc++/channel_interface.h | 40 ++++++-------- src/cpp/client/channel.cc | 86 ++++-------------------------- src/cpp/client/channel.h | 30 +++-------- test/cpp/end2end/end2end_test.cc | 2 - 4 files changed, 33 insertions(+), 125 deletions(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 335b6ccaaee..4176cded7b6 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -48,7 +48,6 @@ class CallOpBuffer; class ClientContext; class CompletionQueue; class RpcMethod; -class CallInterface; class ChannelInterface : public CallHook, public std::enable_shared_from_this { @@ -65,32 +64,27 @@ class ChannelInterface : public CallHook, // Return the tag on cq when the channel state is changed or deadline expires. // GetState needs to called to get the current state. - virtual void NotifyOnStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline, - CompletionQueue* cq, void* tag) = 0; + template + void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline, + CompletionQueue* cq, void* tag) { + TimePoint deadline_tp(deadline); + NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag); + } // Blocking wait for channel state change or deadline expiration. // GetState needs to called to get the current state. - virtual bool WaitForStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline) = 0; - - // Blocking wait for target state or deadline expriration. - virtual bool WaitForState(grpc_connectivity_state target_state, - gpr_timespec deadline) = 0; - -#ifndef GRPC_CXX0X_NO_CHRONO - virtual void NotifyOnStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline, - CompletionQueue* cq, void* tag) = 0; - virtual bool WaitForStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline) = 0; - virtual bool WaitForState( - grpc_connectivity_state target_state, - const std::chrono::system_clock::time_point& deadline) = 0; -#endif // !GRPC_CXX0X_NO_CHRONO + template + bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) { + TimePoint deadline_tp(deadline); + return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time()); + } + private: + virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline, + CompletionQueue* cq, void* tag) = 0; + virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline) = 0; }; } // namespace grpc diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index ccd30c0f460..8bda1f473f3 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -112,91 +112,25 @@ class TagSaver GRPC_FINAL : public CompletionQueueTag { void* tag_; }; -template -void NotifyOnStateChangeShared(grpc_channel* channel, - grpc_connectivity_state last_observed, - const T& deadline, - CompletionQueue* cq, void* tag) { - TimePoint deadline_tp(deadline); +} // namespace + +void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline, + CompletionQueue* cq, void* tag) { TagSaver* tag_saver = new TagSaver(tag); - grpc_channel_watch_connectivity_state( - channel, last_observed, deadline_tp.raw_time(), cq->cq(), tag_saver); + grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline, + cq->cq(), tag_saver); } -template -bool WaitForStateChangeShared(grpc_channel* channel, - grpc_connectivity_state last_observed, - const T& deadline) { +bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline) { CompletionQueue cq; bool ok = false; void* tag = NULL; - NotifyOnStateChangeShared(channel, last_observed, deadline, &cq, NULL); + NotifyOnStateChangeImpl(last_observed, deadline, &cq, NULL); cq.Next(&tag, &ok); GPR_ASSERT(tag == NULL); return ok; } -template -bool WaitForStateShared(grpc_channel* channel, - grpc_connectivity_state target_state, - const T& deadline) { - grpc_connectivity_state current_state = - grpc_channel_check_connectivity_state(channel, 0); - if (current_state == target_state) { - return true; - } - TimePoint deadline_tp(deadline); - CompletionQueue cq; - bool ok = false; - void* tag = NULL; - while (current_state != target_state) { - NotifyOnStateChangeShared(channel, current_state, deadline_tp.raw_time(), - &cq, NULL); - cq.Next(&tag, &ok); - if (!ok) { - return false; - } - current_state = grpc_channel_check_connectivity_state(channel, 0); - } - return true; -} -} // namespace - -void Channel::NotifyOnStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline, - CompletionQueue* cq, void* tag) { - NotifyOnStateChangeShared(c_channel_, last_observed, deadline, cq, tag); -} - -bool Channel::WaitForStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline) { - return WaitForStateChangeShared(c_channel_, last_observed, deadline); -} - -bool Channel::WaitForState(grpc_connectivity_state target_state, - gpr_timespec deadline) { - return WaitForStateShared(c_channel_, target_state, deadline); -} - -#ifndef GRPC_CXX0X_NO_CHRONO -void Channel::NotifyOnStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline, - CompletionQueue* cq, void* tag) { - NotifyOnStateChangeShared(c_channel_, last_observed, deadline, cq, tag); -} - -bool Channel::WaitForStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline) { - return WaitForStateChangeShared(c_channel_, last_observed, deadline); -} - -bool Channel::WaitForState( - grpc_connectivity_state target_state, - const std::chrono::system_clock::time_point& deadline) { - return WaitForStateShared(c_channel_, target_state, deadline); -} - -#endif // !GRPC_CXX0X_NO_CHRONO } // namespace grpc diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index 4dc67237786..cb8e8d98d22 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -64,32 +64,14 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface { grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE; - void NotifyOnStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline, - CompletionQueue* cq, void* tag) GRPC_OVERRIDE; - - bool WaitForStateChange(grpc_connectivity_state last_observed, - gpr_timespec deadline) GRPC_OVERRIDE; - - bool WaitForState(grpc_connectivity_state target_state, - gpr_timespec deadline) GRPC_OVERRIDE; - -#ifndef GRPC_CXX0X_NO_CHRONO - void NotifyOnStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline, - CompletionQueue* cq, void* tag) GRPC_OVERRIDE; - - bool WaitForStateChange( - grpc_connectivity_state last_observed, - const std::chrono::system_clock::time_point& deadline) GRPC_OVERRIDE; + private: + void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline, CompletionQueue* cq, + void* tag) GRPC_OVERRIDE; - bool WaitForState(grpc_connectivity_state target_state, - const std::chrono::system_clock::time_point& deadline) - GRPC_OVERRIDE; -#endif // !GRPC_CXX0X_NO_CHRONO + bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline) GRPC_OVERRIDE; - private: const grpc::string host_; grpc_channel* const c_channel_; // owned }; diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 12ac25c6dff..9c39554104f 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -890,8 +890,6 @@ TEST_F(End2endTest, ChannelState) { EXPECT_TRUE(channel_->WaitForStateChange( GRPC_CHANNEL_IDLE, gpr_inf_future(GPR_CLOCK_REALTIME))); EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false)); - EXPECT_TRUE(channel_->WaitForState(GRPC_CHANNEL_READY, - gpr_inf_future(GPR_CLOCK_REALTIME))); } } // namespace testing From cec757f22a9932dc0f47640e18428300b75066f7 Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Aug 2015 22:53:58 -0700 Subject: [PATCH 050/117] Fix build --- test/cpp/end2end/end2end_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 87bb5b6362e..5f0749daa5c 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -910,7 +910,7 @@ TEST_P(End2endTest, Peer) { } TEST_F(End2endTest, ChannelState) { - ResetStub(); + ResetStub(false); // Start IDLE EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false)); From 631dc004811bb7b046736faff7666db1d379c1fe Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Thu, 6 Aug 2015 23:08:41 -0700 Subject: [PATCH 051/117] Exercise GRPCCall+OAuth2 in the tests --- src/objective-c/tests/GRPCClientTests.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index e5d7e43ed92..1c8461c8e64 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -35,6 +35,7 @@ #import #import +#import #import #import #import @@ -160,7 +161,7 @@ static ProtoMethod *kUnaryCallMethod; path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter]; - call.requestMetadata[@"Authorization"] = @"Bearer bogusToken"; + call.oauth2_accessToken = @"bogusToken"; id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { XCTFail(@"Received unexpected response: %@", value); @@ -169,7 +170,7 @@ static ProtoMethod *kUnaryCallMethod; XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil); XCTAssertEqualObjects(call.responseMetadata, errorOrNil.userInfo[kGRPCStatusMetadataKey], @"Metadata in the NSError object and call object differ."); - NSString *challengeHeader = call.responseMetadata[@"www-authenticate"]; + NSString *challengeHeader = call.oauth2_challengeHeader; XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", call.responseMetadata); [expectation fulfill]; From c85357e05149374a90559a2c1558ff9dbd35aedc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 07:33:04 -0700 Subject: [PATCH 052/117] Reduce mac CI load --- templates/tools/run_tests/tests.json.template | 2 +- test/core/end2end/gen_build_json.py | 28 +- tools/buildgen/plugins/expand_bin_attrs.py | 2 +- tools/run_tests/run_tests.py | 6 +- tools/run_tests/tests.json | 3991 ++++++++++++++++- 5 files changed, 4010 insertions(+), 19 deletions(-) diff --git a/templates/tools/run_tests/tests.json.template b/templates/tools/run_tests/tests.json.template index d1ba5ed43ca..ffbf843235f 100644 --- a/templates/tools/run_tests/tests.json.template +++ b/templates/tools/run_tests/tests.json.template @@ -5,8 +5,8 @@ import json ${json.dumps([{"name": tgt.name, "language": tgt.language, "platforms": tgt.platforms, + "ci_platforms": tgt.ci_platforms, "flaky": tgt.flaky} for tgt in targets if tgt.get('run', True) and tgt.build == 'test'], sort_keys=True, indent=2)} - diff --git a/test/core/end2end/gen_build_json.py b/test/core/end2end/gen_build_json.py index d1138abd784..6f10b78dad4 100755 --- a/test/core/end2end/gen_build_json.py +++ b/test/core/end2end/gen_build_json.py @@ -36,27 +36,27 @@ import simplejson import collections -FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms') -default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix']) +FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms ci_mac') +default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True) socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False) default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True) uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix']) # maps fixture name to whether it requires the security library END2END_FIXTURES = { - 'chttp2_fake_security': default_secure_fixture_options, + 'chttp2_fake_security': default_secure_fixture_options._replace(ci_mac=False), 'chttp2_fullstack': default_unsecure_fixture_options, 'chttp2_fullstack_compression': default_unsecure_fixture_options, 'chttp2_fullstack_uds_posix': uds_fixture_options, 'chttp2_fullstack_uds_posix_with_poll': uds_fixture_options._replace(platforms=['linux']), 'chttp2_fullstack_with_poll': default_unsecure_fixture_options._replace(platforms=['linux']), - 'chttp2_fullstack_with_proxy': default_unsecure_fixture_options._replace(includes_proxy=True), + 'chttp2_fullstack_with_proxy': default_unsecure_fixture_options._replace(includes_proxy=True, ci_mac=False), 'chttp2_simple_ssl_fullstack': default_secure_fixture_options, 'chttp2_simple_ssl_fullstack_with_poll': default_secure_fixture_options._replace(platforms=['linux']), - 'chttp2_simple_ssl_fullstack_with_proxy': default_secure_fixture_options._replace(includes_proxy=True), - 'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options, - 'chttp2_socket_pair': socketpair_unsecure_fixture_options, - 'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options, + 'chttp2_simple_ssl_fullstack_with_proxy': default_secure_fixture_options._replace(includes_proxy=True, ci_mac=False), + 'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options._replace(ci_mac=False), + 'chttp2_socket_pair': socketpair_unsecure_fixture_options._replace(ci_mac=False), + 'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options._replace(ci_mac=False), 'chttp2_socket_pair_with_grpc_trace': socketpair_unsecure_fixture_options, } @@ -115,6 +115,12 @@ def compatible(f, t): return True +def without(l, e): + l = l[:] + l.remove(e) + return l + + def main(): sec_deps = [ 'end2end_certs', @@ -173,6 +179,9 @@ def main(): 'src': [], 'flaky': END2END_TESTS[t].flaky, 'platforms': END2END_FIXTURES[f].platforms, + 'ci_platforms': (END2END_FIXTURES[f].platforms + if END2END_FIXTURES[f].ci_mac + else without(END2END_FIXTURES[f].platforms, 'mac')), 'deps': [ 'end2end_fixture_%s' % f, 'end2end_test_%s' % t] + sec_deps @@ -188,6 +197,9 @@ def main(): 'src': [], 'flaky': END2END_TESTS[t].flaky, 'platforms': END2END_FIXTURES[f].platforms, + 'ci_platforms': (END2END_FIXTURES[f].platforms + if END2END_FIXTURES[f].ci_mac + else without(END2END_FIXTURES[f].platforms, 'mac')), 'deps': [ 'end2end_fixture_%s' % f, 'end2end_test_%s' % t] + unsec_deps diff --git a/tools/buildgen/plugins/expand_bin_attrs.py b/tools/buildgen/plugins/expand_bin_attrs.py index e35b9fe740a..d221b3a325b 100755 --- a/tools/buildgen/plugins/expand_bin_attrs.py +++ b/tools/buildgen/plugins/expand_bin_attrs.py @@ -49,4 +49,4 @@ def mako_plugin(dictionary): for tgt in targets: tgt['flaky'] = tgt.get('flaky', False) tgt['platforms'] = sorted(tgt.get('platforms', default_platforms)) - + tgt['ci_platforms'] = sorted(tgt.get('ci_platforms', tgt['platforms'])) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 482ffcc435d..0d4caa66aaf 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -127,10 +127,14 @@ class CLanguage(object): for tgt in js if tgt['language'] == test_lang and platform_string() in tgt['platforms']] + self.ci_binaries = [tgt + for tgt in js + if tgt['language'] == test_lang and + platform_string() in tgt['ci_platforms']] def test_specs(self, config, travis): out = [] - for target in self.binaries: + for target in (self.ci_binaries if travis else self.binaries): if travis and target['flaky']: continue if self.platform == 'windows': diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index f2fbc92e934..471dae0efa1 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -2,6 +2,12 @@ [ { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "alarm_heap_test", @@ -13,6 +19,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "alarm_list_test", @@ -24,6 +36,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "alarm_test", @@ -35,6 +53,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "alpn_test", @@ -46,6 +70,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "bin_encoder_test", @@ -57,6 +87,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_status_conversion_test", @@ -68,6 +104,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_stream_encoder_test", @@ -79,6 +121,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_stream_map_test", @@ -90,6 +138,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "dualstack_socket_test", @@ -100,6 +153,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "fd_conservation_posix_test", @@ -110,6 +168,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "fd_posix_test", @@ -120,6 +183,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "fling_stream_test", @@ -130,6 +198,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "fling_test", @@ -140,6 +213,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_cancellable_test", @@ -151,6 +230,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_cmdline_test", @@ -162,6 +247,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_env_test", @@ -173,6 +264,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_file_test", @@ -184,6 +281,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_histogram_test", @@ -195,6 +298,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_host_port_test", @@ -206,6 +315,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_log_test", @@ -217,6 +332,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_slice_buffer_test", @@ -228,6 +349,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_slice_test", @@ -239,6 +366,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_stack_lockfree_test", @@ -250,6 +383,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_string_test", @@ -261,6 +400,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_sync_test", @@ -272,6 +417,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_thd_test", @@ -283,6 +434,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_time_test", @@ -294,6 +451,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_tls_test", @@ -305,6 +468,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "gpr_useful_test", @@ -316,6 +485,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_auth_context_test", @@ -327,6 +502,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_base64_test", @@ -338,6 +519,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_byte_buffer_reader_test", @@ -349,6 +536,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_channel_stack_test", @@ -360,6 +553,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_completion_queue_test", @@ -371,6 +570,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_credentials_test", @@ -382,6 +587,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_json_token_test", @@ -393,6 +604,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_jwt_verifier_test", @@ -404,6 +621,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_security_connector_test", @@ -415,6 +638,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "grpc_stream_op_test", @@ -426,6 +655,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "hpack_parser_test", @@ -437,6 +672,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "hpack_table_test", @@ -448,6 +689,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "httpcli_format_request_test", @@ -459,6 +706,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "httpcli_parser_test", @@ -470,6 +723,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "httpcli_test", @@ -480,6 +738,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "json_rewrite_test", @@ -491,6 +755,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "json_test", @@ -502,6 +772,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "lame_client_test", @@ -513,6 +789,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "message_compress_test", @@ -524,6 +806,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "multi_init_test", @@ -535,6 +823,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "multiple_server_queues_test", @@ -546,6 +840,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "murmur_hash_test", @@ -557,6 +857,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "no_server_test", @@ -568,6 +874,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "resolve_address_test", @@ -579,6 +891,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "secure_endpoint_test", @@ -590,6 +908,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "sockaddr_utils_test", @@ -601,6 +925,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "tcp_client_posix_test", @@ -611,6 +940,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "tcp_posix_test", @@ -621,6 +955,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "tcp_server_posix_test", @@ -631,6 +970,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "time_averaged_stats_test", @@ -642,6 +987,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "timeout_encoding_test", @@ -653,6 +1004,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "timers_test", @@ -664,6 +1021,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "transport_metadata_test", @@ -675,6 +1038,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "transport_security_test", @@ -686,6 +1055,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "uri_parser_test", @@ -697,6 +1072,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "async_end2end_test", @@ -708,6 +1089,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "async_streaming_ping_pong_test", @@ -718,8 +1104,13 @@ ] }, { - "flaky": false, - "language": "c++", + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "flaky": false, + "language": "c++", "name": "async_unary_ping_pong_test", "platforms": [ "linux", @@ -728,6 +1119,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "auth_property_iterator_test", @@ -739,6 +1136,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "channel_arguments_test", @@ -750,6 +1153,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "cli_call_test", @@ -761,6 +1170,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "client_crash_test", @@ -771,6 +1185,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "credentials_test", @@ -782,6 +1202,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "cxx_byte_buffer_test", @@ -793,6 +1219,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "cxx_slice_test", @@ -804,6 +1236,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "cxx_time_test", @@ -815,6 +1253,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "dynamic_thread_pool_test", @@ -826,6 +1270,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "end2end_test", @@ -837,6 +1287,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "fixed_size_thread_pool_test", @@ -848,6 +1304,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "generic_end2end_test", @@ -859,6 +1321,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "interop_test", @@ -869,6 +1336,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "mock_test", @@ -880,6 +1353,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "qps_openloop_test", @@ -890,6 +1368,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "qps_test", @@ -900,6 +1383,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "secure_auth_context_test", @@ -911,6 +1400,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "server_crash_test", @@ -921,6 +1415,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "status_test", @@ -932,6 +1432,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "sync_streaming_ping_pong_test", @@ -942,6 +1447,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c++", "name": "sync_unary_ping_pong_test", @@ -952,6 +1462,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c++", "name": "thread_stress_test", @@ -963,6 +1479,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_bad_hostname_test", @@ -974,6 +1495,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_cancel_after_accept_test", @@ -985,6 +1511,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_test", @@ -996,6 +1527,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_cancel_after_invoke_test", @@ -1007,6 +1543,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_cancel_before_invoke_test", @@ -1018,6 +1559,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_cancel_in_a_vacuum_test", @@ -1029,6 +1575,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_census_simple_request_test", @@ -1040,6 +1591,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_channel_connectivity_test", @@ -1051,6 +1607,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_default_host_test", @@ -1062,6 +1623,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_disappearing_server_test", @@ -1073,6 +1639,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test", @@ -1084,6 +1655,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_test", @@ -1095,6 +1671,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_empty_batch_test", @@ -1106,6 +1687,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_graceful_server_shutdown_test", @@ -1117,6 +1703,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_invoke_large_request_test", @@ -1128,6 +1719,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_max_concurrent_streams_test", @@ -1139,6 +1735,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_max_message_length_test", @@ -1150,6 +1751,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_no_op_test", @@ -1161,6 +1767,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_ping_pong_streaming_test", @@ -1172,6 +1783,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_registered_call_test", @@ -1183,6 +1799,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_test", @@ -1194,6 +1815,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_response_with_metadata_and_payload_test", @@ -1205,6 +1831,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_response_with_payload_test", @@ -1216,6 +1847,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_response_with_payload_and_call_creds_test", @@ -1227,6 +1863,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test", @@ -1238,6 +1879,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_with_compressed_payload_test", @@ -1249,6 +1895,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_with_flags_test", @@ -1260,6 +1911,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_with_large_metadata_test", @@ -1271,6 +1927,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_request_with_payload_test", @@ -1282,6 +1943,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_server_finishes_request_test", @@ -1293,6 +1959,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_simple_delayed_request_test", @@ -1304,6 +1975,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_simple_request_test", @@ -1315,6 +1991,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fake_security_simple_request_with_high_initial_sequence_number_test", @@ -1326,6 +2007,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_bad_hostname_test", @@ -1337,6 +2024,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_accept_test", @@ -1348,6 +2041,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_test", @@ -1359,6 +2058,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_invoke_test", @@ -1370,6 +2075,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_before_invoke_test", @@ -1381,6 +2092,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_in_a_vacuum_test", @@ -1392,6 +2109,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_census_simple_request_test", @@ -1403,6 +2126,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_channel_connectivity_test", @@ -1414,6 +2143,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_default_host_test", @@ -1425,6 +2160,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_disappearing_server_test", @@ -1436,6 +2177,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test", @@ -1447,6 +2194,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_test", @@ -1458,6 +2211,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_empty_batch_test", @@ -1469,6 +2228,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_graceful_server_shutdown_test", @@ -1480,6 +2245,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_invoke_large_request_test", @@ -1491,6 +2262,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_max_concurrent_streams_test", @@ -1502,6 +2279,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_max_message_length_test", @@ -1513,9 +2296,15 @@ ] }, { - "flaky": false, - "language": "c", - "name": "chttp2_fullstack_no_op_test", + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "flaky": false, + "language": "c", + "name": "chttp2_fullstack_no_op_test", "platforms": [ "linux", "mac", @@ -1524,6 +2313,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_ping_pong_streaming_test", @@ -1535,6 +2330,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_registered_call_test", @@ -1546,6 +2347,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_test", @@ -1557,6 +2364,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_metadata_and_payload_test", @@ -1568,6 +2381,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_payload_test", @@ -1579,6 +2398,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_payload_and_call_creds_test", @@ -1590,6 +2415,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test", @@ -1601,6 +2432,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_compressed_payload_test", @@ -1612,6 +2449,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_flags_test", @@ -1623,6 +2466,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_large_metadata_test", @@ -1634,6 +2483,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_payload_test", @@ -1645,6 +2500,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_server_finishes_request_test", @@ -1656,6 +2517,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_delayed_request_test", @@ -1667,6 +2534,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_request_test", @@ -1678,6 +2551,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_request_with_high_initial_sequence_number_test", @@ -1689,6 +2568,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_bad_hostname_test", @@ -1700,6 +2585,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_accept_test", @@ -1711,6 +2602,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test", @@ -1722,6 +2619,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_invoke_test", @@ -1733,6 +2636,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_before_invoke_test", @@ -1744,6 +2653,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_test", @@ -1755,6 +2670,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_census_simple_request_test", @@ -1766,6 +2687,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_channel_connectivity_test", @@ -1777,6 +2704,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_default_host_test", @@ -1788,6 +2721,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_disappearing_server_test", @@ -1799,6 +2738,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test", @@ -1810,6 +2755,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test", @@ -1821,6 +2772,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_empty_batch_test", @@ -1832,6 +2789,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_graceful_server_shutdown_test", @@ -1843,6 +2806,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_invoke_large_request_test", @@ -1854,6 +2823,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_max_concurrent_streams_test", @@ -1865,6 +2840,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_max_message_length_test", @@ -1876,6 +2857,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_no_op_test", @@ -1887,6 +2874,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_ping_pong_streaming_test", @@ -1898,6 +2891,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_registered_call_test", @@ -1909,6 +2908,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test", @@ -1920,6 +2925,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_test", @@ -1931,6 +2942,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_payload_test", @@ -1942,6 +2959,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test", @@ -1953,6 +2976,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test", @@ -1964,6 +2993,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_compressed_payload_test", @@ -1975,6 +3010,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_flags_test", @@ -1986,6 +3027,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_large_metadata_test", @@ -1997,6 +3044,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_payload_test", @@ -2008,6 +3061,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_server_finishes_request_test", @@ -2019,6 +3078,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_delayed_request_test", @@ -2030,6 +3095,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_request_test", @@ -2041,6 +3112,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test", @@ -2052,6 +3129,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_bad_hostname_test", @@ -2062,6 +3144,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_accept_test", @@ -2072,6 +3159,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test", @@ -2082,6 +3174,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_invoke_test", @@ -2092,6 +3189,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_before_invoke_test", @@ -2102,6 +3204,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test", @@ -2112,6 +3219,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_census_simple_request_test", @@ -2122,6 +3234,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_channel_connectivity_test", @@ -2132,6 +3249,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_disappearing_server_test", @@ -2142,6 +3264,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test", @@ -2152,6 +3279,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test", @@ -2162,6 +3294,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_empty_batch_test", @@ -2172,6 +3309,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_graceful_server_shutdown_test", @@ -2182,6 +3324,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_invoke_large_request_test", @@ -2192,6 +3339,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_max_concurrent_streams_test", @@ -2202,6 +3354,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_max_message_length_test", @@ -2212,6 +3369,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_no_op_test", @@ -2222,6 +3384,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_ping_pong_streaming_test", @@ -2232,6 +3399,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_registered_call_test", @@ -2242,6 +3414,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test", @@ -2252,6 +3429,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test", @@ -2262,6 +3444,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_payload_test", @@ -2272,6 +3459,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test", @@ -2282,6 +3474,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test", @@ -2292,6 +3489,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_test", @@ -2302,6 +3504,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_flags_test", @@ -2312,6 +3519,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_large_metadata_test", @@ -2322,6 +3534,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_payload_test", @@ -2332,6 +3549,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_server_finishes_request_test", @@ -2342,6 +3564,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_delayed_request_test", @@ -2352,6 +3579,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_request_test", @@ -2362,6 +3594,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test", @@ -2372,6 +3609,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_bad_hostname_test", @@ -2380,6 +3620,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_test", @@ -2388,6 +3631,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_test", @@ -2396,6 +3642,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_test", @@ -2404,6 +3653,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_test", @@ -2412,6 +3664,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_test", @@ -2420,6 +3675,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_census_simple_request_test", @@ -2428,6 +3686,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_channel_connectivity_test", @@ -2436,6 +3697,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_disappearing_server_test", @@ -2444,6 +3708,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_test", @@ -2452,6 +3719,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_test", @@ -2460,6 +3730,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_empty_batch_test", @@ -2468,6 +3741,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_test", @@ -2476,6 +3752,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_invoke_large_request_test", @@ -2484,6 +3763,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_test", @@ -2492,6 +3774,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_max_message_length_test", @@ -2500,6 +3785,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_no_op_test", @@ -2508,6 +3796,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_test", @@ -2516,6 +3807,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_registered_call_test", @@ -2524,6 +3818,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_test", @@ -2532,6 +3829,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_test", @@ -2540,6 +3840,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_test", @@ -2548,6 +3851,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_and_call_creds_test", @@ -2556,6 +3862,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_test", @@ -2564,6 +3873,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_test", @@ -2572,6 +3884,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_flags_test", @@ -2580,6 +3895,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_test", @@ -2588,6 +3906,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_payload_test", @@ -2596,6 +3917,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_server_finishes_request_test", @@ -2604,6 +3928,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_test", @@ -2612,6 +3939,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_request_test", @@ -2620,6 +3950,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_test", @@ -2628,6 +3961,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_bad_hostname_test", @@ -2636,6 +3972,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_accept_test", @@ -2644,6 +3983,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test", @@ -2652,6 +3994,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_invoke_test", @@ -2660,6 +4005,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_before_invoke_test", @@ -2668,6 +4016,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_in_a_vacuum_test", @@ -2676,6 +4027,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_census_simple_request_test", @@ -2684,6 +4038,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_channel_connectivity_test", @@ -2692,6 +4049,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_default_host_test", @@ -2700,6 +4060,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_disappearing_server_test", @@ -2708,6 +4071,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test", @@ -2716,6 +4082,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test", @@ -2724,6 +4093,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_empty_batch_test", @@ -2732,6 +4104,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_graceful_server_shutdown_test", @@ -2740,6 +4115,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_invoke_large_request_test", @@ -2748,6 +4126,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_max_concurrent_streams_test", @@ -2756,6 +4137,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_max_message_length_test", @@ -2764,6 +4148,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_no_op_test", @@ -2772,6 +4159,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_ping_pong_streaming_test", @@ -2780,6 +4170,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_registered_call_test", @@ -2788,6 +4181,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test", @@ -2796,6 +4192,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test", @@ -2804,6 +4203,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_payload_test", @@ -2812,6 +4214,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test", @@ -2820,6 +4225,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test", @@ -2828,6 +4236,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_test", @@ -2836,6 +4247,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_flags_test", @@ -2844,6 +4258,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_large_metadata_test", @@ -2852,6 +4269,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_payload_test", @@ -2860,6 +4280,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_server_finishes_request_test", @@ -2868,6 +4291,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_delayed_request_test", @@ -2876,6 +4302,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_request_test", @@ -2884,6 +4313,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test", @@ -2892,6 +4324,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_bad_hostname_test", @@ -2903,6 +4340,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_accept_test", @@ -2914,6 +4356,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test", @@ -2925,6 +4372,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_invoke_test", @@ -2936,6 +4388,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_before_invoke_test", @@ -2947,6 +4404,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_in_a_vacuum_test", @@ -2958,6 +4420,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_census_simple_request_test", @@ -2969,6 +4436,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_default_host_test", @@ -2980,6 +4452,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_disappearing_server_test", @@ -2991,6 +4468,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test", @@ -3002,6 +4484,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_test", @@ -3013,6 +4500,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_empty_batch_test", @@ -3024,6 +4516,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_graceful_server_shutdown_test", @@ -3035,6 +4532,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_invoke_large_request_test", @@ -3046,6 +4548,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_max_message_length_test", @@ -3057,6 +4564,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_no_op_test", @@ -3068,6 +4580,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_ping_pong_streaming_test", @@ -3079,6 +4596,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_registered_call_test", @@ -3090,6 +4612,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test", @@ -3101,6 +4628,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_test", @@ -3112,6 +4644,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_payload_test", @@ -3123,6 +4660,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_payload_and_call_creds_test", @@ -3134,6 +4676,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test", @@ -3145,6 +4692,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_with_large_metadata_test", @@ -3156,6 +4708,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_with_payload_test", @@ -3167,6 +4724,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_server_finishes_request_test", @@ -3178,6 +4740,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_delayed_request_test", @@ -3189,6 +4756,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_request_test", @@ -3200,6 +4772,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test", @@ -3211,6 +4788,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_bad_hostname_test", @@ -3222,6 +4805,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_test", @@ -3233,6 +4822,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test", @@ -3244,6 +4839,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_test", @@ -3255,6 +4856,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_test", @@ -3266,6 +4873,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test", @@ -3277,6 +4890,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_census_simple_request_test", @@ -3288,6 +4907,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_channel_connectivity_test", @@ -3299,6 +4924,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_default_host_test", @@ -3310,6 +4941,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_disappearing_server_test", @@ -3321,6 +4958,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test", @@ -3332,6 +4975,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test", @@ -3343,6 +4992,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_empty_batch_test", @@ -3354,6 +5009,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_test", @@ -3365,6 +5026,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_invoke_large_request_test", @@ -3376,6 +5043,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_test", @@ -3387,7 +5060,13 @@ ] }, { - "flaky": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_max_message_length_test", "platforms": [ @@ -3398,6 +5077,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_no_op_test", @@ -3409,6 +5094,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_test", @@ -3420,6 +5111,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_registered_call_test", @@ -3431,6 +5128,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test", @@ -3442,6 +5145,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test", @@ -3453,6 +5162,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_test", @@ -3464,6 +5179,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test", @@ -3475,6 +5196,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test", @@ -3486,6 +5213,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_with_compressed_payload_test", @@ -3497,6 +5230,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_with_flags_test", @@ -3508,6 +5247,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_test", @@ -3519,6 +5264,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_request_with_payload_test", @@ -3530,6 +5281,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_server_finishes_request_test", @@ -3541,6 +5298,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_test", @@ -3552,6 +5315,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_simple_request_test", @@ -3563,6 +5332,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test", @@ -3574,6 +5349,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test", @@ -3582,6 +5360,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test", @@ -3590,6 +5371,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test", @@ -3598,6 +5382,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test", @@ -3606,6 +5393,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test", @@ -3614,6 +5404,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test", @@ -3622,6 +5415,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test", @@ -3630,6 +5426,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_channel_connectivity_test", @@ -3638,6 +5437,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_default_host_test", @@ -3646,6 +5448,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test", @@ -3654,6 +5459,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test", @@ -3662,6 +5470,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test", @@ -3670,6 +5481,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_empty_batch_test", @@ -3678,6 +5492,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test", @@ -3686,6 +5503,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test", @@ -3694,6 +5514,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test", @@ -3702,6 +5525,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_max_message_length_test", @@ -3710,6 +5536,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_no_op_test", @@ -3718,6 +5547,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test", @@ -3726,6 +5558,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_registered_call_test", @@ -3734,6 +5569,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test", @@ -3742,6 +5580,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test", @@ -3750,6 +5591,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test", @@ -3758,6 +5602,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test", @@ -3766,6 +5613,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test", @@ -3774,6 +5624,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test", @@ -3782,6 +5635,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test", @@ -3790,6 +5646,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test", @@ -3798,6 +5657,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test", @@ -3806,6 +5668,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test", @@ -3814,6 +5679,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test", @@ -3822,6 +5690,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_simple_request_test", @@ -3830,6 +5701,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test", @@ -3838,6 +5712,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_bad_hostname_test", @@ -3849,6 +5728,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_test", @@ -3860,6 +5744,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test", @@ -3871,6 +5760,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_cancel_after_invoke_test", @@ -3882,6 +5776,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_cancel_before_invoke_test", @@ -3893,6 +5792,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_cancel_in_a_vacuum_test", @@ -3904,6 +5808,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_census_simple_request_test", @@ -3915,6 +5824,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_default_host_test", @@ -3926,6 +5840,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_disappearing_server_test", @@ -3937,6 +5856,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test", @@ -3948,6 +5872,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_tags_test", @@ -3959,6 +5888,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_empty_batch_test", @@ -3970,6 +5904,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_graceful_server_shutdown_test", @@ -3981,6 +5920,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_invoke_large_request_test", @@ -3992,6 +5936,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_max_message_length_test", @@ -4003,6 +5952,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_no_op_test", @@ -4014,6 +5968,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_ping_pong_streaming_test", @@ -4025,6 +5984,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_registered_call_test", @@ -4036,6 +6000,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test", @@ -4047,6 +6016,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_response_with_metadata_and_payload_test", @@ -4058,6 +6032,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_test", @@ -4069,6 +6048,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_and_call_creds_test", @@ -4080,6 +6064,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test", @@ -4091,6 +6080,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_with_large_metadata_test", @@ -4102,6 +6096,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_request_with_payload_test", @@ -4113,6 +6112,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_server_finishes_request_test", @@ -4124,6 +6128,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_simple_delayed_request_test", @@ -4135,6 +6144,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_simple_request_test", @@ -4146,6 +6160,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test", @@ -4157,6 +6176,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test", @@ -4168,6 +6192,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test", @@ -4179,6 +6208,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test", @@ -4190,6 +6224,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test", @@ -4201,6 +6240,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test", @@ -4212,6 +6256,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test", @@ -4223,6 +6272,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test", @@ -4234,6 +6288,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_channel_connectivity_test", @@ -4245,6 +6304,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_default_host_test", @@ -4256,6 +6320,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test", @@ -4267,6 +6336,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test", @@ -4278,6 +6352,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test", @@ -4289,6 +6368,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test", @@ -4300,6 +6384,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test", @@ -4311,6 +6400,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test", @@ -4322,6 +6416,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test", @@ -4333,6 +6432,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test", @@ -4344,6 +6448,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_test", @@ -4355,6 +6464,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test", @@ -4366,6 +6480,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test", @@ -4377,6 +6496,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test", @@ -4388,6 +6512,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test", @@ -4399,7 +6528,12 @@ ] }, { - "flaky": false, + "ci_platforms": [ + "linux", + "posix", + "windows" + ], + "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test", "platforms": [ @@ -4410,6 +6544,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test", @@ -4421,6 +6560,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test", @@ -4432,6 +6576,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test", @@ -4443,6 +6592,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test", @@ -4454,6 +6608,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test", @@ -4465,6 +6624,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test", @@ -4476,6 +6640,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test", @@ -4487,6 +6656,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test", @@ -4498,6 +6672,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test", @@ -4509,6 +6688,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test", @@ -4520,6 +6704,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_bad_hostname_test", @@ -4531,6 +6720,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_accept_test", @@ -4542,6 +6736,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_test", @@ -4553,6 +6752,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_invoke_test", @@ -4564,6 +6768,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_before_invoke_test", @@ -4575,6 +6784,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_in_a_vacuum_test", @@ -4586,6 +6800,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_census_simple_request_test", @@ -4597,6 +6816,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test", @@ -4608,6 +6832,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_test", @@ -4619,6 +6848,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_empty_batch_test", @@ -4630,6 +6864,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_graceful_server_shutdown_test", @@ -4641,6 +6880,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_invoke_large_request_test", @@ -4652,6 +6896,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_max_concurrent_streams_test", @@ -4663,6 +6912,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_max_message_length_test", @@ -4674,6 +6928,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_no_op_test", @@ -4685,6 +6944,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_ping_pong_streaming_test", @@ -4696,6 +6960,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_registered_call_test", @@ -4707,6 +6976,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test", @@ -4718,6 +6992,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_test", @@ -4729,6 +7008,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_payload_test", @@ -4740,6 +7024,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_payload_and_call_creds_test", @@ -4751,6 +7040,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test", @@ -4762,6 +7056,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_compressed_payload_test", @@ -4773,6 +7072,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_flags_test", @@ -4784,6 +7088,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_large_metadata_test", @@ -4795,6 +7104,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_payload_test", @@ -4806,6 +7120,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_server_finishes_request_test", @@ -4817,6 +7136,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_simple_request_test", @@ -4828,6 +7152,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test", @@ -4839,6 +7168,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test", @@ -4850,6 +7184,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test", @@ -4861,6 +7200,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test", @@ -4872,6 +7216,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test", @@ -4883,6 +7232,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test", @@ -4894,6 +7248,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test", @@ -4905,6 +7264,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test", @@ -4916,6 +7280,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test", @@ -4927,6 +7296,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test", @@ -4938,6 +7312,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_test", @@ -4949,6 +7328,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test", @@ -4960,6 +7344,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test", @@ -4971,6 +7360,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test", @@ -4982,6 +7376,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_max_message_length_test", @@ -4993,6 +7392,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_test", @@ -5004,6 +7408,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test", @@ -5015,6 +7424,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_registered_call_test", @@ -5026,6 +7440,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test", @@ -5037,6 +7456,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test", @@ -5048,6 +7472,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test", @@ -5059,6 +7488,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test", @@ -5070,6 +7504,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test", @@ -5081,6 +7520,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test", @@ -5092,6 +7536,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test", @@ -5103,6 +7552,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test", @@ -5114,6 +7568,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test", @@ -5125,6 +7584,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test", @@ -5136,6 +7600,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_test", @@ -5147,6 +7616,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test", @@ -5158,6 +7632,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_bad_hostname_test", @@ -5169,6 +7649,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test", @@ -5180,6 +7666,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test", @@ -5191,6 +7683,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test", @@ -5202,6 +7700,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test", @@ -5213,6 +7717,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test", @@ -5224,6 +7734,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_census_simple_request_test", @@ -5235,6 +7751,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test", @@ -5246,6 +7768,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test", @@ -5257,6 +7785,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_empty_batch_test", @@ -5268,6 +7802,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test", @@ -5279,6 +7819,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_invoke_large_request_test", @@ -5290,6 +7836,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test", @@ -5301,6 +7853,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_max_message_length_test", @@ -5312,6 +7870,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_no_op_test", @@ -5323,6 +7887,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test", @@ -5334,6 +7904,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_registered_call_test", @@ -5345,6 +7921,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test", @@ -5356,6 +7938,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test", @@ -5367,6 +7955,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test", @@ -5378,6 +7972,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test", @@ -5389,6 +7989,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test", @@ -5400,6 +8006,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test", @@ -5411,6 +8023,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_test", @@ -5422,6 +8040,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test", @@ -5433,6 +8057,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_payload_test", @@ -5444,6 +8074,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_server_finishes_request_test", @@ -5455,6 +8091,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_simple_request_test", @@ -5466,6 +8108,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test", @@ -5477,6 +8125,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_bad_hostname_unsecure_test", @@ -5488,6 +8142,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_accept_unsecure_test", @@ -5499,6 +8159,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test", @@ -5510,6 +8176,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_after_invoke_unsecure_test", @@ -5521,6 +8193,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_before_invoke_unsecure_test", @@ -5532,6 +8210,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_cancel_in_a_vacuum_unsecure_test", @@ -5543,6 +8227,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_census_simple_request_unsecure_test", @@ -5554,6 +8244,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_channel_connectivity_unsecure_test", @@ -5565,6 +8261,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_default_host_unsecure_test", @@ -5576,6 +8278,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_disappearing_server_unsecure_test", @@ -5587,6 +8295,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -5598,6 +8312,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test", @@ -5609,6 +8329,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_empty_batch_unsecure_test", @@ -5620,6 +8346,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_graceful_server_shutdown_unsecure_test", @@ -5631,6 +8363,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_invoke_large_request_unsecure_test", @@ -5642,6 +8380,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_max_concurrent_streams_unsecure_test", @@ -5653,6 +8397,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_max_message_length_unsecure_test", @@ -5664,6 +8414,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_no_op_unsecure_test", @@ -5675,6 +8431,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_ping_pong_streaming_unsecure_test", @@ -5686,6 +8448,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_registered_call_unsecure_test", @@ -5697,6 +8465,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -5708,6 +8482,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test", @@ -5719,6 +8499,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_payload_unsecure_test", @@ -5730,6 +8516,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -5741,6 +8533,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_compressed_payload_unsecure_test", @@ -5752,6 +8550,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_flags_unsecure_test", @@ -5763,6 +8567,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_large_metadata_unsecure_test", @@ -5774,6 +8584,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_request_with_payload_unsecure_test", @@ -5785,6 +8601,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_server_finishes_request_unsecure_test", @@ -5796,6 +8618,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_delayed_request_unsecure_test", @@ -5807,6 +8635,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_request_unsecure_test", @@ -5818,6 +8652,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -5829,6 +8669,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_bad_hostname_unsecure_test", @@ -5840,6 +8686,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_accept_unsecure_test", @@ -5851,6 +8703,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test", @@ -5862,6 +8720,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_after_invoke_unsecure_test", @@ -5873,6 +8737,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_before_invoke_unsecure_test", @@ -5884,6 +8754,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test", @@ -5895,6 +8771,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_census_simple_request_unsecure_test", @@ -5906,6 +8788,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_channel_connectivity_unsecure_test", @@ -5917,6 +8805,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_default_host_unsecure_test", @@ -5928,6 +8822,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_disappearing_server_unsecure_test", @@ -5939,6 +8839,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -5950,6 +8856,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test", @@ -5961,6 +8873,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_empty_batch_unsecure_test", @@ -5972,6 +8890,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test", @@ -5983,6 +8907,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_invoke_large_request_unsecure_test", @@ -5994,6 +8924,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_max_concurrent_streams_unsecure_test", @@ -6005,6 +8941,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_max_message_length_unsecure_test", @@ -6016,6 +8958,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_no_op_unsecure_test", @@ -6027,6 +8975,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_ping_pong_streaming_unsecure_test", @@ -6038,6 +8992,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_registered_call_unsecure_test", @@ -6049,6 +9009,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -6060,6 +9026,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test", @@ -6071,6 +9043,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_payload_unsecure_test", @@ -6082,6 +9060,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -6093,6 +9077,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test", @@ -6104,6 +9094,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_flags_unsecure_test", @@ -6115,6 +9111,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_large_metadata_unsecure_test", @@ -6126,6 +9128,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_request_with_payload_unsecure_test", @@ -6137,6 +9145,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_server_finishes_request_unsecure_test", @@ -6148,6 +9162,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_delayed_request_unsecure_test", @@ -6159,6 +9179,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_request_unsecure_test", @@ -6170,6 +9196,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -6181,6 +9213,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_bad_hostname_unsecure_test", @@ -6191,6 +9228,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test", @@ -6201,6 +9243,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test", @@ -6211,6 +9258,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test", @@ -6221,6 +9273,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test", @@ -6231,6 +9288,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test", @@ -6241,6 +9303,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_census_simple_request_unsecure_test", @@ -6251,6 +9318,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_channel_connectivity_unsecure_test", @@ -6261,6 +9333,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_disappearing_server_unsecure_test", @@ -6271,6 +9348,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -6281,6 +9363,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test", @@ -6291,6 +9378,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_empty_batch_unsecure_test", @@ -6301,6 +9393,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test", @@ -6311,6 +9408,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test", @@ -6321,6 +9423,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test", @@ -6331,6 +9438,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_max_message_length_unsecure_test", @@ -6341,6 +9453,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_no_op_unsecure_test", @@ -6351,6 +9468,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test", @@ -6361,6 +9483,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_registered_call_unsecure_test", @@ -6371,6 +9498,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -6381,6 +9513,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test", @@ -6391,6 +9528,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test", @@ -6401,6 +9543,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -6411,6 +9558,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test", @@ -6421,6 +9573,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_flags_unsecure_test", @@ -6431,6 +9588,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test", @@ -6441,6 +9603,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_request_with_payload_unsecure_test", @@ -6451,6 +9618,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test", @@ -6461,6 +9633,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test", @@ -6471,6 +9648,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_request_unsecure_test", @@ -6481,6 +9663,11 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -6491,6 +9678,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_bad_hostname_unsecure_test", @@ -6499,6 +9689,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_unsecure_test", @@ -6507,6 +9700,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_unsecure_test", @@ -6515,6 +9711,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_unsecure_test", @@ -6523,6 +9722,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_unsecure_test", @@ -6531,6 +9733,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_unsecure_test", @@ -6539,6 +9744,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_census_simple_request_unsecure_test", @@ -6547,6 +9755,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_channel_connectivity_unsecure_test", @@ -6555,6 +9766,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_disappearing_server_unsecure_test", @@ -6563,6 +9777,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -6571,6 +9788,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_unsecure_test", @@ -6579,6 +9799,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_empty_batch_unsecure_test", @@ -6587,6 +9810,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_unsecure_test", @@ -6595,6 +9821,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_invoke_large_request_unsecure_test", @@ -6603,6 +9832,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_unsecure_test", @@ -6611,6 +9843,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_max_message_length_unsecure_test", @@ -6619,6 +9854,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_no_op_unsecure_test", @@ -6627,6 +9865,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_unsecure_test", @@ -6635,6 +9876,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_registered_call_unsecure_test", @@ -6643,6 +9887,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -6651,6 +9898,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_unsecure_test", @@ -6659,6 +9909,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_unsecure_test", @@ -6667,6 +9920,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -6675,6 +9931,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_unsecure_test", @@ -6683,6 +9942,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_flags_unsecure_test", @@ -6691,6 +9953,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_unsecure_test", @@ -6699,6 +9964,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_request_with_payload_unsecure_test", @@ -6707,6 +9975,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_server_finishes_request_unsecure_test", @@ -6715,6 +9986,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_unsecure_test", @@ -6723,6 +9997,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_request_unsecure_test", @@ -6731,6 +10008,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -6739,6 +10019,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_bad_hostname_unsecure_test", @@ -6747,6 +10030,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test", @@ -6755,6 +10041,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test", @@ -6763,6 +10052,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test", @@ -6771,6 +10063,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test", @@ -6779,6 +10074,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test", @@ -6787,6 +10085,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_census_simple_request_unsecure_test", @@ -6795,6 +10096,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_channel_connectivity_unsecure_test", @@ -6803,6 +10107,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_default_host_unsecure_test", @@ -6811,6 +10118,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_disappearing_server_unsecure_test", @@ -6819,6 +10129,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -6827,6 +10140,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test", @@ -6835,6 +10151,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_empty_batch_unsecure_test", @@ -6843,6 +10162,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test", @@ -6851,6 +10173,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_invoke_large_request_unsecure_test", @@ -6859,6 +10184,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test", @@ -6867,6 +10195,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_max_message_length_unsecure_test", @@ -6875,6 +10206,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_no_op_unsecure_test", @@ -6883,6 +10217,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test", @@ -6891,6 +10228,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_registered_call_unsecure_test", @@ -6899,6 +10239,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -6907,6 +10250,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test", @@ -6915,6 +10261,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test", @@ -6923,6 +10272,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -6931,6 +10283,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test", @@ -6939,6 +10294,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_flags_unsecure_test", @@ -6947,6 +10305,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test", @@ -6955,6 +10316,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_request_with_payload_unsecure_test", @@ -6963,6 +10327,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_server_finishes_request_unsecure_test", @@ -6971,6 +10338,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test", @@ -6979,6 +10349,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_request_unsecure_test", @@ -6987,6 +10360,9 @@ ] }, { + "ci_platforms": [ + "linux" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -6995,6 +10371,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_bad_hostname_unsecure_test", @@ -7006,6 +10387,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_accept_unsecure_test", @@ -7017,6 +10403,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_unsecure_test", @@ -7028,6 +10419,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_after_invoke_unsecure_test", @@ -7039,6 +10435,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_before_invoke_unsecure_test", @@ -7050,6 +10451,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_cancel_in_a_vacuum_unsecure_test", @@ -7061,6 +10467,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_census_simple_request_unsecure_test", @@ -7072,6 +10483,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_default_host_unsecure_test", @@ -7083,6 +10499,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_disappearing_server_unsecure_test", @@ -7094,6 +10515,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -7105,6 +10531,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_unsecure_test", @@ -7116,6 +10547,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_empty_batch_unsecure_test", @@ -7127,6 +10563,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_graceful_server_shutdown_unsecure_test", @@ -7138,6 +10579,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_invoke_large_request_unsecure_test", @@ -7149,6 +10595,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_max_message_length_unsecure_test", @@ -7160,6 +10611,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_no_op_unsecure_test", @@ -7171,6 +10627,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_ping_pong_streaming_unsecure_test", @@ -7182,6 +10643,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_registered_call_unsecure_test", @@ -7193,6 +10659,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -7204,6 +10675,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_unsecure_test", @@ -7215,6 +10691,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_payload_unsecure_test", @@ -7226,6 +10707,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -7237,6 +10723,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_with_large_metadata_unsecure_test", @@ -7248,6 +10739,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_request_with_payload_unsecure_test", @@ -7259,6 +10755,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_server_finishes_request_unsecure_test", @@ -7270,6 +10771,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_delayed_request_unsecure_test", @@ -7281,6 +10787,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_request_unsecure_test", @@ -7292,6 +10803,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -7303,6 +10819,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_bad_hostname_unsecure_test", @@ -7314,6 +10835,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_accept_unsecure_test", @@ -7325,6 +10851,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test", @@ -7336,6 +10867,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_after_invoke_unsecure_test", @@ -7347,6 +10883,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_before_invoke_unsecure_test", @@ -7358,6 +10899,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test", @@ -7369,6 +10915,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_census_simple_request_unsecure_test", @@ -7380,6 +10931,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -7391,6 +10947,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test", @@ -7402,6 +10963,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_empty_batch_unsecure_test", @@ -7413,6 +10979,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_graceful_server_shutdown_unsecure_test", @@ -7424,6 +10995,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_invoke_large_request_unsecure_test", @@ -7435,6 +11011,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_max_concurrent_streams_unsecure_test", @@ -7446,6 +11027,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_max_message_length_unsecure_test", @@ -7457,6 +11043,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_no_op_unsecure_test", @@ -7468,6 +11059,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_ping_pong_streaming_unsecure_test", @@ -7479,6 +11075,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_registered_call_unsecure_test", @@ -7490,6 +11091,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -7501,6 +11107,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test", @@ -7512,6 +11123,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_payload_unsecure_test", @@ -7523,6 +11139,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -7534,6 +11155,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_compressed_payload_unsecure_test", @@ -7545,6 +11171,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_flags_unsecure_test", @@ -7556,6 +11187,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_large_metadata_unsecure_test", @@ -7567,6 +11203,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_request_with_payload_unsecure_test", @@ -7578,6 +11219,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_server_finishes_request_unsecure_test", @@ -7589,6 +11235,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_simple_request_unsecure_test", @@ -7600,6 +11251,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -7611,6 +11267,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test", @@ -7622,6 +11283,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test", @@ -7633,6 +11299,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test", @@ -7644,6 +11315,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test", @@ -7655,6 +11331,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test", @@ -7666,6 +11347,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test", @@ -7677,6 +11363,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test", @@ -7688,6 +11379,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -7699,6 +11395,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test", @@ -7710,6 +11411,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test", @@ -7721,6 +11427,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test", @@ -7732,6 +11443,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test", @@ -7743,6 +11459,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test", @@ -7754,6 +11475,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test", @@ -7765,6 +11491,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test", @@ -7776,6 +11507,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test", @@ -7787,6 +11523,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test", @@ -7798,6 +11539,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -7809,6 +11555,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test", @@ -7820,6 +11571,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test", @@ -7831,6 +11587,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -7842,6 +11603,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test", @@ -7853,6 +11619,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test", @@ -7864,6 +11635,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test", @@ -7875,6 +11651,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test", @@ -7886,6 +11667,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test", @@ -7897,6 +11683,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test", @@ -7908,6 +11699,11 @@ ] }, { + "ci_platforms": [ + "linux", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -7919,6 +11715,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test", @@ -7930,6 +11732,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test", @@ -7941,6 +11749,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test", @@ -7952,6 +11766,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test", @@ -7963,6 +11783,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test", @@ -7974,6 +11800,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test", @@ -7985,6 +11817,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test", @@ -7996,6 +11834,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test", @@ -8007,6 +11851,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test", @@ -8018,6 +11868,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test", @@ -8029,6 +11885,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test", @@ -8040,6 +11902,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test", @@ -8051,6 +11919,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test", @@ -8062,6 +11936,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test", @@ -8073,6 +11953,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test", @@ -8084,6 +11970,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test", @@ -8095,6 +11987,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test", @@ -8106,6 +12004,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test", @@ -8117,6 +12021,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test", @@ -8128,6 +12038,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test", @@ -8139,6 +12055,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test", @@ -8150,6 +12072,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test", @@ -8161,6 +12089,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test", @@ -8172,6 +12106,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test", @@ -8183,6 +12123,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test", @@ -8194,6 +12140,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test", @@ -8205,6 +12157,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test", @@ -8216,6 +12174,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test", @@ -8227,6 +12191,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "connection_prefix_bad_client_test", @@ -8238,6 +12208,12 @@ ] }, { + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], "flaky": false, "language": "c", "name": "initial_settings_frame_bad_client_test", @@ -8249,4 +12225,3 @@ ] } ] - From 2d91b5de4031ecd5e82c720ba9d39c677f5888b1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 07:39:27 -0700 Subject: [PATCH 053/117] Only slow down tracing tests if stdout isatty --- .../end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c b/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c index 6d2361b783a..9d798ad1d20 100644 --- a/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c +++ b/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c @@ -148,7 +148,11 @@ int main(int argc, char **argv) { /* force tracing on, with a value to force many code paths in trace.c to be taken */ gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all"); +#ifdef GPR_POSIX_SOCKET + g_fixture_slowdown_factor = isatty(STDOUT_FILENO) ? 10.0 : 1.0; +#else g_fixture_slowdown_factor = 10.0; +#endif grpc_test_init(argc, argv); grpc_init(); From 24a97628b6a30914f4267ed958e8f84d25cf6026 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 07:42:29 -0700 Subject: [PATCH 054/117] Add portlog.txt to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f5ca501db26..45f8fdaa46f 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ cache.mk # Temporary test reports report.xml + +# port server log +portlog.txt From 26e0c9ee4c70ad209a5d1d9609c517235e1d1b21 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Aug 2015 09:48:33 -0700 Subject: [PATCH 055/117] Fixup for 971d06ad06caadb369e318112bba0e039188cfc2 --- src/objective-c/GRPCClient/private/GRPCHost.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 45e5f0602da..d902f95b516 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -78,12 +78,12 @@ if (cachedHost) { return cachedHost; } - } - if ((self = [super init])) { - _address = address; - _secure = YES; - hostCache[address] = self; + if ((self = [super init])) { + _address = address; + _secure = YES; + hostCache[address] = self; + } } return self; } From 721b7a3923996c7ac8aa7258f1fe7d5bc416af2b Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Aug 2015 10:11:16 -0700 Subject: [PATCH 056/117] Rename oauth2_lowerCamel -> oauth2UpperCamel --- src/objective-c/GRPCClient/GRPCCall+OAuth2.h | 4 ++-- src/objective-c/GRPCClient/GRPCCall+OAuth2.m | 6 +++--- src/objective-c/tests/GRPCClientTests.m | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h index f14fe254b0f..2e379a71572 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -41,9 +41,9 @@ // authorization header from the request. // The value obtained by getting the property is the OAuth2 bearer token if the authorization header // of the request has the form "Bearer ", or nil otherwise. -@property(atomic, copy) NSString *oauth2_accessToken; +@property(atomic, copy) NSString *oauth2AccessToken; // Returns the value (if any) of the "www-authenticate" response header (the challenge header). -@property(atomic, readonly) NSString *oauth2_challengeHeader; +@property(atomic, readonly) NSString *oauth2ChallengeHeader; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m index 77d00f260eb..ed39d4b0f7a 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m @@ -39,7 +39,7 @@ static NSString * const kChallengeHeader = @"www-authenticate"; @implementation GRPCCall (OAuth2) -- (NSString *)oauth2_accessToken { +- (NSString *)oauth2AccessToken { NSString *headerValue = self.requestMetadata[kAuthorizationHeader]; if ([headerValue hasPrefix:kBearerPrefix]) { return [headerValue substringFromIndex:kBearerPrefix.length]; @@ -48,7 +48,7 @@ static NSString * const kChallengeHeader = @"www-authenticate"; } } -- (void)setOauth2_accessToken:(NSString *)token { +- (void)setOauth2AccessToken:(NSString *)token { if (token) { self.requestMetadata[kAuthorizationHeader] = [kBearerPrefix stringByAppendingString:token]; } else { @@ -56,7 +56,7 @@ static NSString * const kChallengeHeader = @"www-authenticate"; } } -- (NSString *)oauth2_challengeHeader { +- (NSString *)oauth2ChallengeHeader { return self.responseMetadata[kChallengeHeader]; } diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 1c8461c8e64..e85dd6e65cd 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -161,7 +161,7 @@ static ProtoMethod *kUnaryCallMethod; path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter]; - call.oauth2_accessToken = @"bogusToken"; + call.oauth2AccessToken = @"bogusToken"; id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { XCTFail(@"Received unexpected response: %@", value); @@ -170,7 +170,7 @@ static ProtoMethod *kUnaryCallMethod; XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil); XCTAssertEqualObjects(call.responseMetadata, errorOrNil.userInfo[kGRPCStatusMetadataKey], @"Metadata in the NSError object and call object differ."); - NSString *challengeHeader = call.oauth2_challengeHeader; + NSString *challengeHeader = call.oauth2ChallengeHeader; XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", call.responseMetadata); [expectation fulfill]; From 2e95e4ac1dcbe38555ab2c0307d98654c2677346 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 10:40:33 -0700 Subject: [PATCH 057/117] Move parent removal from final destruction to destruction request We don't need the list for cancel propagation after that point, and doing it early avoids a bug whereby the call is reffed after reaching a zero ref when the parent is destroyed first. --- src/core/surface/call.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index d3e66e9c4cc..6e566e6a8f8 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -456,20 +456,6 @@ void grpc_call_internal_ref(grpc_call *c) { static void destroy_call(void *call, int ignored_success) { size_t i; grpc_call *c = call; - grpc_call *parent = c->parent; - if (parent) { - gpr_mu_lock(&parent->mu); - if (call == parent->first_child) { - parent->first_child = c->sibling_next; - if (c == parent->first_child) { - parent->first_child = NULL; - } - c->sibling_prev->sibling_next = c->sibling_next; - c->sibling_next->sibling_prev = c->sibling_prev; - } - gpr_mu_unlock(&parent->mu); - GRPC_CALL_INTERNAL_UNREF(parent, "child", 1); - } grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c)); GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call"); gpr_mu_destroy(&c->mu); @@ -1257,6 +1243,22 @@ grpc_call_error grpc_call_start_ioreq_and_call_back( void grpc_call_destroy(grpc_call *c) { int cancel; + grpc_call *parent = c->parent; + + if (parent) { + gpr_mu_lock(&parent->mu); + if (c == parent->first_child) { + parent->first_child = c->sibling_next; + if (c == parent->first_child) { + parent->first_child = NULL; + } + c->sibling_prev->sibling_next = c->sibling_next; + c->sibling_next->sibling_prev = c->sibling_prev; + } + gpr_mu_unlock(&parent->mu); + GRPC_CALL_INTERNAL_UNREF(parent, "child", 1); + } + lock(c); GPR_ASSERT(!c->destroy_called); c->destroy_called = 1; From d259bb1dd18683dbce6b2e175c90ebd7a5a65f5c Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 7 Aug 2015 11:21:31 -0700 Subject: [PATCH 058/117] Add a document describing a server reflection protocol. This is largely cribbed from @dklempner's original PR (#2744) . Taking over as he is out on vacation. Removed the discussion around host-reflection and corresponding uses of `host` from the API. --- doc/server-reflection.md | 183 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 doc/server-reflection.md diff --git a/doc/server-reflection.md b/doc/server-reflection.md new file mode 100644 index 00000000000..cceee1647f6 --- /dev/null +++ b/doc/server-reflection.md @@ -0,0 +1,183 @@ +GRPC Server Reflection Protocol +=============================== + +This document describes server reflection as an optional extension for servers +to assist clients in runtime construction of requests without having stub +information precompiled into the client. + +The primary usecase for server reflection is to write (typically) command line +debugging tools for talking to a grpc server. In particular, such a tool will +take in a method and a payload (in human readable text format) send it to the +server (typically in binary proto wire format), and then take the response and +decode it to text to present to the user. + +This broadly involves two problems: determining what formats (which protobuf +messages) a server’s method uses, and determining how to convert messages +between human readable format and the (likely binary) wire format. + +## Method reflection + +We want to be able to answer the following queries: + 1. What methods does a server export? + 2. For a particular method, how do we call it? +Specifically, what are the names of the methods, are those methods unary or +streaming, and what are the types of the argument and result? + +``` +#TODO(dklempner): link to an actual .proto later. +package grpc.reflection.v1alpha; + +message ListApisRequest { +} + +message ListApisResponse { + repeated google.protobuf.Api apis = 1; +} + +message GetMethodRequest { + string method = 1; +} +message GetMethodResponse { + google.protobuf.Method method = 1; +} + +service ServerReflection { + rpc ListApis (ListApisRequest) returns (ListApisResponse); + rpc GetMethod (GetMethodRequest) returns (GetMethodResponse); +} +``` + +Note that a server is under no obligation to return a complete list of all +methods it supports. For example, a reverse proxy may support server reflection +for methods implemented directly on the proxy but not enumerate all methods +supported by its backends. + + +### Open questions on method reflection + * Consider how to extend this protocol to support non-protobuf methods. + +## Argument reflection +The second half of the problem is converting between the human readable +input/output of a debugging tool and the binary format understood by the +method. + +This is obviously dependent on protocol type. At one extreme, if both the +server and the debugging tool accept JSON, there may be no need for such a +conversion in the first place. At the opposite extreme, a server using a custom +binary format has no hope of being supported by a generic system. The +intermediate interesting common case is a server which speaks binary-proto and +a debugging client which speaks either ascii-proto or json-proto. + +One approach would be to require servers directly support human readable input. +In the future method reflection may be extended to document such support, +should it become widespread or standardized. + +## Protobuf descriptors + +A second would be for the server to export its +google::protobuf::DescriptorDatabase over the wire. This is very easy to +implement in C++, and Google implementations of a similar protocol already +exist in C++, Go, and Java. + +This protocol mostly returns FileDescriptorProtos, which are a proto encoding +of a parsed .proto file. It supports four queries: + 1. The FileDescriptorProto for a given file name + 2. The FileDescriptorProto for the file with a given symbol + 3. The FileDescriptorProto for the file with a given extension + 4. The list of known extension tag numbers of a given type + +These directly correspond to the methods of +google::protobuf::DescriptorDatabase. Note that this protocol includes support +for extensions, which have been removed from proto3 but are still in widespread +use in Google’s codebase. + +Because most usecases will require also requesting the transitive dependencies +of requested files, the queries will also return all transitive dependencies of +the returned file. Should interesting usecases for non-transitive queries turn +up later, we can easily extend the protocol to support them. + +### Reverse proxy traversal + +One potential issue with naive reverse proxies is that, while any individual +server will have a consistent and valid picture of the proto DB which is +sufficient to handle incoming requests, incompatibilities will arise if the +backend servers have a mix of builds. For example, if a given message is moved +from foo.proto to bar.proto, and the client requests foo.proto from an old +server and bar.proto from a new server, the resulting database will have a +double definition. + +To solve this problem, the protocol is structured as a bidirectional stream, +ensuring all related requests go to a single server. This has the additional +benefit that overlapping recursive requests don’t require sending a lot of +redundant information, because there is a single stream to maintain context +between queries. + +``` +package grpc.reflection.v1alpha; +message DescriptorDatabaseRequest { + string host = 1; + oneof message_request { + string files_for_file_name = 3; + string files_for_symbol_name = 4; + FileContainingExtensionRequest file_containing_extension = 5; + string list_all_extensions_of_type = 6; + } +} + +message FileContainingExtensionRequest { + string base_message = 1; + int64 extension_id = 2; +} + +message DescriptorDatabaseResponse { + string valid_host = 1; + DescriptorDatabaseRequest original_request = 2; + oneof message_response { + // These are proto2 type google.protobuf.FileDescriptorProto, but + // we avoid taking a dependency on descriptor.proto, which uses + // proto2 only features, by making them opaque + // bytes instead + repeated bytes fd_proto = 4; + ListAllExtensionsResponse extensions_response = 5; + // Notably includes error code 5, NOT FOUND + int32 error_code = 6; + } +} + +message ListAllExtensionsResponse { + string base_type_name; + repeated int64 extension_number; +} + +service ProtoDescriptorDatabase { + rpc DescriptorDatabaseInfo(stream DescriptorDatabaseRequest) returns (stream DescriptorDatabaseResponse); +} +``` + +Any given request must either result in an error code or an answer, usually in +the form of a series of FileDescriptorProtos with the requested file itself +and all previously unsent transitive imports of that file. Servers may track +which FileDescriptorProtos have been sent on a given stream, for a given value +of valid_host, and avoid sending them repeatedly for overlapping requests. + +| message_request message | Result | +| files_for_file_name | transitive closure of file name | +| files_for_symbol_name | transitive closure file containing symbol | +| file_containing_extension | transitive closure of file containing a given extension number of a given symbol | +| list_all_extensions_of_type | ListAllExtensionsResponse containing all known extension numbers of a given type | + +At some point it would make sense to additionally also support any.proto’s +format. Note that known any.proto messages can be queried by symbol using this +protocol even without any such support, by parsing the url and extracting the +symbol name from it. + +## Language specific implementation thoughts +All of the information needed to implement Proto reflection is available to the +code generator, but I’m not certain we actually generate this in every +language. If the proto implementation in the language doesn’t have something +like google::protobuf::DescriptorPool the grpc implementation for that language +will need to index those FileDescriptorProtos by file and symbol and imports. + +One issue is that some grpc implementations are very loosely coupled with +protobufs; in such implementations it probably makes sense to split apart these +reflection APIs so as not to take an additional proto dependency. From c897798fb163cf82f8070512b9b39d366d4b1118 Mon Sep 17 00:00:00 2001 From: Donna Dionne Date: Fri, 7 Aug 2015 11:22:07 -0700 Subject: [PATCH 059/117] adding node, ruby, and php to cloud to prod interop tests. --- tools/run_tests/run_interops.py | 18 ++++++-------- tools/run_tests/run_interops_build.sh | 36 ++++++++++++++++++++++++--- tools/run_tests/run_interops_test.sh | 11 ++++++++ 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/tools/run_tests/run_interops.py b/tools/run_tests/run_interops.py index 1cf268526dc..4e6b5ce2f68 100755 --- a/tools/run_tests/run_interops.py +++ b/tools/run_tests/run_interops.py @@ -4,24 +4,20 @@ import jobset argp = argparse.ArgumentParser(description='Run interop tests.') argp.add_argument('-l', '--language', - choices=['build_only', 'c++'], - nargs='+', - default=['build_only']) + default='c++') args = argp.parse_args() # build job -build_steps = 'tools/run_tests/run_interops_build.sh' -build_job = jobset.JobSpec(cmdline=build_steps, shortname='build') +build_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_build.sh', '%s' % args.language], shortname='build') -# test jobs +# test jobs, each test is a separate job to run in parallel _TESTS = ['large_unary', 'empty_unary', 'ping_pong', 'client_streaming', 'server_streaming'] jobs = [] jobNumber = 0 -for lang in args.language: - for test in _TESTS: - test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % lang, '%s' % test], shortname=test) - jobs.append(test_job) - jobNumber+=1 +for test in _TESTS: + test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % args.language, '%s' % test], shortname=test) + jobs.append(test_job) + jobNumber+=1 root = ET.Element('testsuites') testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') diff --git a/tools/run_tests/run_interops_build.sh b/tools/run_tests/run_interops_build.sh index 23441a5300d..ff1a26cf899 100755 --- a/tools/run_tests/run_interops_build.sh +++ b/tools/run_tests/run_interops_build.sh @@ -29,6 +29,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +language=$1 + set -e #clean up any old docker files and start mirroring repository if not started already @@ -40,8 +42,34 @@ sudo docker run -d -e GCS_BUCKET=docker-interop-images -e STORAGE_PATH=/admin/d #prepare building by pulling down base images and necessary files sudo docker pull 0.0.0.0:5000/grpc/base sudo docker tag -f 0.0.0.0:5000/grpc/base grpc/base -gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_cxx -gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_cxx -#build docker file, add more languages later -sudo docker build --no-cache -t grpc/cxx tools/dockerfile/grpc_cxx +if [ "$language" = "c++" ] +then + gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_cxx + gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_cxx + sudo docker build --no-cache -t grpc/cxx tools/dockerfile/grpc_cxx +elif [ "$language" = "node" ] +then + sudo docker pull 0.0.0.0:5000/grpc/node_base + sudo docker tag -f 0.0.0.0:5000/grpc/node_base grpc/node_base + gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_node + gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_node + sudo docker build --no-cache -t grpc/node tools/dockerfile/grpc_node +elif [ "$language" = "ruby" ] +then + sudo docker pull 0.0.0.0:5000/grpc/ruby_base + sudo docker tag -f 0.0.0.0:5000/grpc/ruby_base grpc/ruby_base + gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_ruby + gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_ruby + sudo docker build --no-cache -t grpc/ruby tools/dockerfile/grpc_ruby +elif [ "$language" = "php" ] +then + sudo docker pull 0.0.0.0:5000/grpc/php_base + sudo docker tag -f 0.0.0.0:5000/grpc/php_base grpc/php_base + gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_php + gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_php + sudo docker build --no-cache -t grpc/php tools/dockerfile/grpc_php +else + echo "interop testss not added for $language" + exit 1 +fi diff --git a/tools/run_tests/run_interops_test.sh b/tools/run_tests/run_interops_test.sh index 1d0eedad85a..9be253af460 100755 --- a/tools/run_tests/run_interops_test.sh +++ b/tools/run_tests/run_interops_test.sh @@ -36,6 +36,17 @@ set -e if [ "$language" = "c++" ] then sudo docker run grpc/cxx /var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots --server_host_override=grpc-test.sandbox.google.com --server_host=grpc-test.sandbox.google.com --server_port=443 --test_case=$test_case +elif [ "$language" = "node" ] +then + sudo docker run grpc/node /usr/bin/nodejs /var/local/git/grpc/src/node/interop/interop_client.js --use_tls=true --use_test_ca=true --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com --test_case=$test_case +elif [ "$language" = "ruby" ] +then + cmd_prefix="SSL_CERT_FILE=/cacerts/roots.pem ruby /var/local/git/grpc/src/ruby/bin/interop/interop_client.rb --use_tls --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com " + cmd="$cmd_prefix --test_case=$test_case" + sudo docker run grpc/ruby bin/bash -l -c '$cmd' +elif [ "$language" = "php" ] +then + sudo docker run -e SSL_CERT_FILE=/cacerts/roots.pem grpc/php /var/local/git/grpc/src/php/bin/interop_client.sh --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com --test_case=$test_case else echo "interop testss not added for $language" exit 1 From 8f1b169b3d3298be2d9dee7c1c5a7ac798fe3d84 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 11:43:38 -0700 Subject: [PATCH 060/117] Reorder filters to ensure that :authority is available when the auth filter needs it --- src/core/surface/secure_channel_create.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index 1f893530257..c3150250b8c 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -88,8 +88,8 @@ static void on_secure_transport_setup_done(void *arg, c->args.channel_args, secure_endpoint, c->args.metadata_context, 1); grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0); c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2); - c->result->filters[0] = &grpc_client_auth_filter; - c->result->filters[1] = &grpc_http_client_filter; + c->result->filters[0] = &grpc_http_client_filter; + c->result->filters[1] = &grpc_client_auth_filter; c->result->num_filters = 2; } notify = c->notify; From de02ae611f3a8fd43e34b8c972b5aace0df5219c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 7 Aug 2015 14:19:38 -0700 Subject: [PATCH 061/117] Shutdown lb_policy when changing it --- src/core/channel/client_channel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index a293c93ec64..6c2e6b38a80 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -527,6 +527,7 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { } if (old_lb_policy != NULL) { + grpc_lb_policy_shutdown(old_lb_policy); GRPC_LB_POLICY_UNREF(old_lb_policy, "channel"); } From 2109217c4a3bf01d08817cab2bf8390b62b878c3 Mon Sep 17 00:00:00 2001 From: yang-g Date: Fri, 7 Aug 2015 15:44:14 -0700 Subject: [PATCH 062/117] Fix gce detection --- src/core/security/google_default_credentials.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index f368819597a..1701a67d026 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -84,6 +84,8 @@ static void on_compute_engine_detection_http_response( gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset)); } +static void destroy_pollset(void *p) { grpc_pollset_destroy(p); } + static int is_stack_running_on_compute_engine(void) { compute_engine_detector detector; grpc_httpcli_request request; @@ -114,12 +116,12 @@ static int is_stack_running_on_compute_engine(void) { while (!detector.is_done) { grpc_pollset_worker worker; grpc_pollset_work(&detector.pollset, &worker, - gpr_inf_future(GPR_CLOCK_REALTIME)); + gpr_inf_future(GPR_CLOCK_MONOTONIC)); } gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset)); grpc_httpcli_context_destroy(&context); - grpc_pollset_destroy(&detector.pollset); + grpc_pollset_shutdown(&detector.pollset, destroy_pollset, &destroy_pollset); return detector.success; } From 6a5494a5bff7f539717aadea975f7021121cbad1 Mon Sep 17 00:00:00 2001 From: yang-g Date: Fri, 7 Aug 2015 15:55:51 -0700 Subject: [PATCH 063/117] :( --- src/core/security/google_default_credentials.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index 1701a67d026..d1f228665f0 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -121,7 +121,7 @@ static int is_stack_running_on_compute_engine(void) { gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset)); grpc_httpcli_context_destroy(&context); - grpc_pollset_shutdown(&detector.pollset, destroy_pollset, &destroy_pollset); + grpc_pollset_shutdown(&detector.pollset, destroy_pollset, &detector.pollset); return detector.success; } From bff90ac384cd19186e4ccde629ad8c6b7a17cd5d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 6 Aug 2015 21:30:26 -0700 Subject: [PATCH 064/117] added WriteOptions support and enabled NoCompress flag to be used for all writes --- src/csharp/Grpc.Core/CallOptions.cs | 16 +++- src/csharp/Grpc.Core/CompressionLevel.cs | 63 ++++++++++++++ src/csharp/Grpc.Core/Grpc.Core.csproj | 2 + src/csharp/Grpc.Core/IAsyncStreamWriter.cs | 12 +++ src/csharp/Grpc.Core/Internal/AsyncCall.cs | 67 +++++++++------ .../Grpc.Core/Internal/AsyncCallBase.cs | 4 +- .../Grpc.Core/Internal/AsyncCallServer.cs | 8 +- .../Grpc.Core/Internal/CallSafeHandle.cs | 57 ++++++++----- .../Grpc.Core/Internal/ClientRequestStream.cs | 24 +++++- .../Grpc.Core/Internal/ServerCallHandler.cs | 12 +-- .../Internal/ServerResponseStream.cs | 25 +++++- src/csharp/Grpc.Core/ServerCallContext.cs | 31 ++++++- src/csharp/Grpc.Core/WriteOptions.cs | 83 +++++++++++++++++++ src/csharp/ext/grpc_csharp_ext.c | 65 +++++++++------ 14 files changed, 376 insertions(+), 93 deletions(-) create mode 100644 src/csharp/Grpc.Core/CompressionLevel.cs create mode 100644 src/csharp/Grpc.Core/WriteOptions.cs diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index 8e9739335f0..e8d0b0647fd 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -47,6 +47,7 @@ namespace Grpc.Core readonly Metadata headers; readonly DateTime deadline; readonly CancellationToken cancellationToken; + readonly WriteOptions writeOptions; /// /// Creates a new instance of CallOptions. @@ -54,10 +55,12 @@ namespace Grpc.Core /// Headers to be sent with the call. /// Deadline for the call to finish. null means no deadline. /// Can be used to request cancellation of the call. - public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + /// Write options that will be used for this call. + public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), WriteOptions writeOptions = null) { // TODO(jtattermusch): consider only creating metadata object once it's really needed. this.headers = headers != null ? headers : new Metadata(); + // TODO(jtattermusch): allow null value of deadline? this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue; this.cancellationToken = cancellationToken; } @@ -85,5 +88,16 @@ namespace Grpc.Core { get { return cancellationToken; } } + + /// + /// Write options that will be used for this call. + /// + public WriteOptions WriteOptions + { + get + { + return this.writeOptions; + } + } } } diff --git a/src/csharp/Grpc.Core/CompressionLevel.cs b/src/csharp/Grpc.Core/CompressionLevel.cs new file mode 100644 index 00000000000..399652b85e5 --- /dev/null +++ b/src/csharp/Grpc.Core/CompressionLevel.cs @@ -0,0 +1,63 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; + +namespace Grpc.Core +{ + /// + /// Compression level based on grpc_compression_level from grpc/compression.h + /// + public enum CompressionLevel + { + /// + /// No compression. + /// + None = 0, + + /// + /// Low compression. + /// + Low, + + /// + /// Medium compression. + /// + Medium, + + /// + /// High compression. + /// + High, + } +} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 52defd1965c..0616ed9f3ec 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -115,6 +115,8 @@ + + diff --git a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs index 2000210252d..b554b6e2660 100644 --- a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs +++ b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs @@ -50,5 +50,17 @@ namespace Grpc.Core /// /// the message to be written. Cannot be null. Task WriteAsync(T message); + + /// + /// Write options that will be used for the next write. + /// If null, default options will be used. + /// Once set, this property maintains its value across subsequent + /// writes. + /// Internally, closing the stream is on client and sending + /// status from server is treated as a write, so write options + /// are also applied to these operations. + /// + /// The write options. + WriteOptions WriteOptions { get; set; } } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 414b5c42820..c26b0773baf 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -50,7 +50,7 @@ namespace Grpc.Core.Internal { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); - readonly CallInvocationDetails callDetails; + readonly CallInvocationDetails details; // Completion of a pending unary response if not null. TaskCompletionSource unaryResponseTcs; @@ -63,7 +63,7 @@ namespace Grpc.Core.Internal public AsyncCall(CallInvocationDetails callDetails) : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer) { - this.callDetails = callDetails; + this.details = callDetails; } // TODO: this method is not Async, so it shouldn't be in AsyncCall class, but @@ -89,11 +89,11 @@ namespace Grpc.Core.Internal readingDone = true; } - using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { using (var ctx = BatchContextSafeHandle.Create()) { - call.StartUnary(payload, ctx, metadataArray); + call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall()); var ev = cq.Pluck(ctx.Handle); bool success = (ev.success != 0); @@ -130,7 +130,7 @@ namespace Grpc.Core.Internal Preconditions.CheckState(!started); started = true; - Initialize(callDetails.Channel.Environment.CompletionQueue); + Initialize(details.Channel.Environment.CompletionQueue); halfcloseRequested = true; readingDone = true; @@ -138,9 +138,9 @@ namespace Grpc.Core.Internal byte[] payload = UnsafeSerialize(msg); unaryResponseTcs = new TaskCompletionSource(); - using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartUnary(payload, HandleUnaryResponse, metadataArray); + call.StartUnary(HandleUnaryResponse, payload, metadataArray, GetWriteFlagsForCall()); } return unaryResponseTcs.Task; } @@ -157,14 +157,14 @@ namespace Grpc.Core.Internal Preconditions.CheckState(!started); started = true; - Initialize(callDetails.Channel.Environment.CompletionQueue); + Initialize(details.Channel.Environment.CompletionQueue); readingDone = true; unaryResponseTcs = new TaskCompletionSource(); - using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartClientStreaming(HandleUnaryResponse, metadataArray); + call.StartClientStreaming(HandleUnaryResponse, metadataArray, GetWriteFlagsForCall()); } return unaryResponseTcs.Task; @@ -181,16 +181,16 @@ namespace Grpc.Core.Internal Preconditions.CheckState(!started); started = true; - Initialize(callDetails.Channel.Environment.CompletionQueue); + Initialize(details.Channel.Environment.CompletionQueue); halfcloseRequested = true; halfclosed = true; // halfclose not confirmed yet, but it will be once finishedHandler is called. byte[] payload = UnsafeSerialize(msg); - using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartServerStreaming(payload, HandleFinished, metadataArray); + call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall()); } } } @@ -206,11 +206,11 @@ namespace Grpc.Core.Internal Preconditions.CheckState(!started); started = true; - Initialize(callDetails.Channel.Environment.CompletionQueue); + Initialize(details.Channel.Environment.CompletionQueue); - using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartDuplexStreaming(HandleFinished, metadataArray); + call.StartDuplexStreaming(HandleFinished, metadataArray, GetWriteFlagsForCall()); } } } @@ -219,9 +219,9 @@ namespace Grpc.Core.Internal /// Sends a streaming request. Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendMessage(TRequest msg, AsyncCompletionDelegate completionDelegate) + public void StartSendMessage(TRequest msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { - StartSendMessageInternal(msg, completionDelegate); + StartSendMessageInternal(msg, writeFlags, completionDelegate); } /// @@ -238,14 +238,14 @@ namespace Grpc.Core.Internal /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendCloseFromClient(AsyncCompletionDelegate completionDelegate) + public void StartSendCloseFromClient(WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); - call.StartSendCloseFromClient(HandleHalfclosed); + call.StartSendCloseFromClient(HandleHalfclosed, writeFlags); halfcloseRequested = true; sendCompletionDelegate = completionDelegate; @@ -278,6 +278,14 @@ namespace Grpc.Core.Internal } } + public CallInvocationDetails Details + { + get + { + return this.details; + } + } + /// /// On client-side, we only fire readCompletionDelegate once all messages have been read /// and status has been received. @@ -310,14 +318,14 @@ namespace Grpc.Core.Internal protected override void OnReleaseResources() { - callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Decrement(); + details.Channel.Environment.DebugStats.ActiveClientCalls.Decrement(); } private void Initialize(CompletionQueueSafeHandle cq) { - var call = callDetails.Channel.Handle.CreateCall(callDetails.Channel.Environment.CompletionRegistry, cq, - callDetails.Method, callDetails.Host, Timespec.FromDateTime(callDetails.Options.Deadline)); - callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); + var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, cq, + details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline)); + details.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); InitializeInternal(call); RegisterCancellationCallback(); } @@ -325,13 +333,22 @@ namespace Grpc.Core.Internal // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called. private void RegisterCancellationCallback() { - var token = callDetails.Options.CancellationToken; + var token = details.Options.CancellationToken; if (token.CanBeCanceled) { token.Register(() => this.Cancel()); } } + /// + /// Gets WriteFlags set in callDetails.Options.WriteOptions + /// + private WriteFlags GetWriteFlagsForCall() + { + var writeOptions = details.Options.WriteOptions; + return writeOptions != null ? writeOptions.Flags : default(WriteFlags); + } + /// /// Handler for unary response completion. /// diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 38f2a5baebd..0c7694e9a59 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -123,7 +123,7 @@ namespace Grpc.Core.Internal /// Initiates sending a message. Only one send operation can be active at a time. /// completionDelegate is invoked upon completion. /// - protected void StartSendMessageInternal(TWrite msg, AsyncCompletionDelegate completionDelegate) + protected void StartSendMessageInternal(TWrite msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { byte[] payload = UnsafeSerialize(msg); @@ -132,7 +132,7 @@ namespace Grpc.Core.Internal Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); - call.StartSendMessage(payload, HandleSendFinished); + call.StartSendMessage(HandleSendFinished, payload, writeFlags); sendCompletionDelegate = completionDelegate; } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 513902ee364..8d7bdf65aac 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -83,9 +83,9 @@ namespace Grpc.Core.Internal /// Sends a streaming response. Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendMessage(TResponse msg, AsyncCompletionDelegate completionDelegate) + public void StartSendMessage(TResponse msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { - StartSendMessageInternal(msg, completionDelegate); + StartSendMessageInternal(msg, writeFlags, completionDelegate); } /// @@ -102,7 +102,7 @@ namespace Grpc.Core.Internal /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate completionDelegate) + public void StartSendStatusFromServer(Status status, Metadata trailers, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { lock (myLock) { @@ -111,7 +111,7 @@ namespace Grpc.Core.Internal using (var metadataArray = MetadataArraySafeHandle.Create(trailers)) { - call.StartSendStatusFromServer(status, HandleHalfclosed, metadataArray); + call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, writeFlags); } halfcloseRequested = true; readingDone = true; diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 714749b171f..be1426feb47 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -53,32 +53,32 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call, - BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray); + BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call, - BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, - MetadataArraySafeHandle metadataArray); + MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, - BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, - BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len); + BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, - BatchContextSafeHandle ctx); + BatchContextSafeHandle ctx, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, - BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray); + BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, @@ -88,6 +88,10 @@ namespace Grpc.Core.Internal static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx); + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); + [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); @@ -103,60 +107,60 @@ namespace Grpc.Core.Internal this.completionRegistry = completionRegistry; } - public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) + public void StartUnary(BatchCompletionDelegate callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray) + grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) .CheckOk(); } - public void StartUnary(byte[] payload, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray) + public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { - grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray) + grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) .CheckOk(); } - public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) + public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk(); + grpcsharp_call_start_client_streaming(this, ctx, metadataArray, writeFlags).CheckOk(); } - public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) + public void StartServerStreaming(BatchCompletionDelegate callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk(); + grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk(); } - public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) + public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk(); + grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, writeFlags).CheckOk(); } - public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback) + public void StartSendMessage(BatchCompletionDelegate callback, byte[] payload, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk(); + grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags).CheckOk(); } - public void StartSendCloseFromClient(BatchCompletionDelegate callback) + public void StartSendCloseFromClient(BatchCompletionDelegate callback, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_close_from_client(this, ctx).CheckOk(); + grpcsharp_call_send_close_from_client(this, ctx, writeFlags).CheckOk(); } - public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) + public void StartSendStatusFromServer(BatchCompletionDelegate callback, Status status, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray).CheckOk(); + grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, writeFlags).CheckOk(); } public void StartReceiveMessage(BatchCompletionDelegate callback) @@ -173,6 +177,13 @@ namespace Grpc.Core.Internal grpcsharp_call_start_serverside(this, ctx).CheckOk(); } + public void SendInitialMetadata(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + { + var ctx = BatchContextSafeHandle.Create(); + completionRegistry.RegisterBatchCompletion(ctx, callback); + grpcsharp_call_send_initial_metadata(this, ctx, metadataArray, writeFlags).CheckOk(); + } + public void Cancel() { grpcsharp_call_cancel(this).CheckOk(); diff --git a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs index 58f493463be..4a146949772 100644 --- a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs +++ b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs @@ -40,24 +40,44 @@ namespace Grpc.Core.Internal internal class ClientRequestStream : IClientStreamWriter { readonly AsyncCall call; + WriteOptions writeOptions; public ClientRequestStream(AsyncCall call) { this.call = call; + this.writeOptions = call.Details.Options.WriteOptions; } public Task WriteAsync(TRequest message) { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendMessage(message, taskSource.CompletionDelegate); + call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } public Task CompleteAsync() { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendCloseFromClient(taskSource.CompletionDelegate); + call.StartSendCloseFromClient(GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } + + public WriteOptions WriteOptions + { + get + { + return this.writeOptions; + } + set + { + writeOptions = value; + } + } + + private WriteFlags GetWriteFlags() + { + var options = writeOptions; + return options != null ? options.Flags : default(WriteFlags); + } } } diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 19f0e3c57f6..34db03cc383 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -75,7 +75,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -131,7 +131,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -187,7 +187,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { var result = await handler(requestStream, context); @@ -247,7 +247,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { await handler(requestStream, responseStream, context); @@ -304,13 +304,13 @@ namespace Grpc.Core.Internal return new Status(StatusCode.Unknown, "Exception was thrown by handler."); } - public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, CancellationToken cancellationToken) + public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, IHasWriteOptions writeOptionsHolder, CancellationToken cancellationToken) { DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); return new ServerCallContext( newRpc.Method, newRpc.Host, peer, realtimeDeadline, - newRpc.RequestMetadata, cancellationToken); + newRpc.RequestMetadata, cancellationToken, writeOptionsHolder); } } } diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs index 756dcee87f6..1d79241f776 100644 --- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs +++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs @@ -38,11 +38,12 @@ namespace Grpc.Core.Internal /// /// Writes responses asynchronously to an underlying AsyncCallServer object. /// - internal class ServerResponseStream : IServerStreamWriter + internal class ServerResponseStream : IServerStreamWriter, IHasWriteOptions where TRequest : class where TResponse : class { readonly AsyncCallServer call; + WriteOptions writeOptions; public ServerResponseStream(AsyncCallServer call) { @@ -52,15 +53,33 @@ namespace Grpc.Core.Internal public Task WriteAsync(TResponse message) { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendMessage(message, taskSource.CompletionDelegate); + call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } public Task WriteStatusAsync(Status status, Metadata trailers) { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendStatusFromServer(status, trailers, taskSource.CompletionDelegate); + call.StartSendStatusFromServer(status, trailers, GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } + + public WriteOptions WriteOptions + { + get + { + return writeOptions; + } + set + { + writeOptions = value; + } + } + + private WriteFlags GetWriteFlags() + { + var options = writeOptions; + return options != null ? options.Flags : default(WriteFlags); + } } } diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 032b1390db3..5657eb8513e 100644 --- a/src/csharp/Grpc.Core/ServerCallContext.cs +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -36,6 +36,8 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Grpc.Core.Internal; + namespace Grpc.Core { /// @@ -54,8 +56,9 @@ namespace Grpc.Core private readonly Metadata responseTrailers = new Metadata(); private Status status = Status.DefaultSuccess; + private IHasWriteOptions writeOptionsHolder; - public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken) + public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, IHasWriteOptions writeOptionsHolder) { this.method = method; this.host = host; @@ -63,6 +66,7 @@ namespace Grpc.Core this.deadline = deadline; this.requestHeaders = requestHeaders; this.cancellationToken = cancellationToken; + this.writeOptionsHolder = writeOptionsHolder; } /// Name of method called in this RPC. @@ -141,5 +145,30 @@ namespace Grpc.Core status = value; } } + + /// + /// Allows setting write options for the following write. + /// For streaming response calls, this property is also exposed as on IServerStreamWriter for convenience. + /// Both properties are backed by the same underlying value. + /// + public WriteOptions WriteOptions + { + get + { + return writeOptionsHolder.WriteOptions; + } + set + { + writeOptionsHolder.WriteOptions = value; + } + } + } + + /// + /// Allows sharing write options between ServerCallContext and other objects. + /// + public interface IHasWriteOptions + { + WriteOptions WriteOptions { get; set; } } } diff --git a/src/csharp/Grpc.Core/WriteOptions.cs b/src/csharp/Grpc.Core/WriteOptions.cs new file mode 100644 index 00000000000..ec4a7dd8cdd --- /dev/null +++ b/src/csharp/Grpc.Core/WriteOptions.cs @@ -0,0 +1,83 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; + +namespace Grpc.Core +{ + /// + /// Flags for write operations. + /// + [Flags] + public enum WriteFlags + { + /// + /// Hint that the write may be buffered and need not go out on the wire immediately. + /// gRPC is free to buffer the message until the next non-buffered + /// write, or until write stream completion, but it need not buffer completely or at all. + /// + BufferHint = 0x1, + + /// + /// Force compression to be disabled for a particular write. + /// + NoCompress = 0x2 + } + + + /// + /// Options for write operations. + /// + public class WriteOptions + { + /// + /// Default write options. + /// + public static readonly WriteOptions Default = new WriteOptions(); + + private WriteFlags flags; + + public WriteOptions(WriteFlags flags = default(WriteFlags)) + { + this.flags = flags; + } + + public WriteFlags Flags + { + get + { + return this.flags; + } + } + } +} diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 048887bc12a..165459371b8 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -497,7 +497,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) { GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, size_t send_buffer_len, - grpc_metadata_array *initial_metadata) { + grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[6]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -506,15 +506,15 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = 0; + ops[0].flags = write_flags; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; - ops[1].flags = 0; + ops[1].flags = write_flags; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[2].flags = 0; + ops[2].flags = write_flags; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -542,7 +542,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(grpc_call *call, grpcsharp_batch_context *ctx, - grpc_metadata_array *initial_metadata) { + grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[4]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -551,7 +551,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = 0; + ops[0].flags = write_flags; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -578,7 +578,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, - size_t send_buffer_len, grpc_metadata_array *initial_metadata) { + size_t send_buffer_len, grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[5]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -587,15 +587,15 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = 0; + ops[0].flags = write_flags; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; - ops[1].flags = 0; + ops[1].flags = write_flags; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[2].flags = 0; + ops[2].flags = write_flags; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -619,7 +619,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(grpc_call *call, grpcsharp_batch_context *ctx, - grpc_metadata_array *initial_metadata) { + grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[3]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -628,7 +628,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = 0; + ops[0].flags = write_flags; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -651,31 +651,31 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx, - const char *send_buffer, size_t send_buffer_len) { + const char *send_buffer, size_t send_buffer_len, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[0].data.send_message = ctx->send_message; - ops[0].flags = 0; + ops[0].flags = write_flags; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(grpc_call *call, - grpcsharp_batch_context *ctx) { + grpcsharp_batch_context *ctx, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[0].flags = 0; + ops[0].flags = write_flags; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code, - const char *status_details, grpc_metadata_array *trailing_metadata) { + const char *status_details, grpc_metadata_array *trailing_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER; @@ -688,7 +688,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( ctx->send_status_from_server.trailing_metadata.count; ops[0].data.send_status_from_server.trailing_metadata = ctx->send_status_from_server.trailing_metadata.metadata; - ops[0].flags = 0; + ops[0].flags = write_flags; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } @@ -706,16 +706,29 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) { GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ - grpc_op ops[2]; - ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; - ops[0].data.send_initial_metadata.count = 0; - ops[0].data.send_initial_metadata.metadata = NULL; + grpc_op ops[1]; + ops[0].op = GRPC_OP_RECV_CLOSE_ON_SERVER; + ops[0].data.recv_close_on_server.cancelled = + (&ctx->recv_close_on_server_cancelled); ops[0].flags = 0; - ops[1].op = GRPC_OP_RECV_CLOSE_ON_SERVER; - ops[1].data.recv_close_on_server.cancelled = - (&ctx->recv_close_on_server_cancelled); - ops[1].flags = 0; + return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); +} + +GPR_EXPORT grpc_call_error GPR_CALLTYPE +grpcsharp_call_send_initial_metadata(grpc_call *call, + grpcsharp_batch_context *ctx, + grpc_metadata_array *initial_metadata, + gpr_uint32 write_flags) { + /* TODO: don't use magic number */ + grpc_op ops[1]; + ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; + grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), + initial_metadata); + ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; + ops[0].data.send_initial_metadata.metadata = + ctx->send_initial_metadata.metadata; + ops[0].flags = write_flags; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } From 8368b2e4b911a0e47cb2a2304513939ab34c74c3 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 01:18:37 -0700 Subject: [PATCH 065/117] implemented sending initial metadata --- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 1 + .../Grpc.Core/Internal/AsyncCallBase.cs | 8 ++++- .../Grpc.Core/Internal/AsyncCallServer.cs | 30 ++++++++++++++++++- .../Grpc.Core/Internal/CallSafeHandle.cs | 14 ++++----- .../Grpc.Core/Internal/ClientRequestStream.cs | 1 + .../Grpc.Core/Internal/ServerCallHandler.cs | 6 ++-- .../Internal/ServerResponseStream.cs | 8 +++++ src/csharp/Grpc.Core/ServerCallContext.cs | 17 +++++++---- src/csharp/ext/grpc_csharp_ext.c | 25 ++++++++++++---- 9 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index c26b0773baf..c8c2449ee6f 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -64,6 +64,7 @@ namespace Grpc.Core.Internal : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer) { this.details = callDetails; + this.initialMetadataSent = true; // we always send metadata at the very beginning of the call. } // TODO: this method is not Async, so it shouldn't be in AsyncCall class, but diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 0c7694e9a59..9fa0baca87a 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -71,6 +71,9 @@ namespace Grpc.Core.Internal protected bool halfclosed; protected bool finished; // True if close has been received from the peer. + protected bool initialMetadataSent; + protected long streamingWritesCounter; + public AsyncCallBase(Func serializer, Func deserializer) { this.serializer = Preconditions.CheckNotNull(serializer); @@ -132,8 +135,11 @@ namespace Grpc.Core.Internal Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); - call.StartSendMessage(HandleSendFinished, payload, writeFlags); + call.StartSendMessage(HandleSendFinished, payload, writeFlags, !initialMetadataSent); + sendCompletionDelegate = completionDelegate; + initialMetadataSent = true; + streamingWritesCounter++; } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 8d7bdf65aac..9eac7f7b614 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -97,6 +97,34 @@ namespace Grpc.Core.Internal StartReadMessageInternal(completionDelegate); } + /// + /// Initiates sending a initial metadata. + /// Even though C-core allows sending metadata in parallel to sending messages, we will treat sending metadata as a send message operation + /// to make things simpler. + /// completionDelegate is invoked upon completion. + /// + public void StartSendInitialMetadata(Metadata headers, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) + { + lock (myLock) + { + Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); + + Preconditions.CheckState(!initialMetadataSent, "Response headers can only be sent once per call."); + Preconditions.CheckState(streamingWritesCounter > 0, "Response headers can only be sent before the first write starts."); + CheckSendingAllowed(); + + Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); + + using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + { + call.StartSendInitialMetadata(HandleSendFinished, metadataArray, writeFlags); + } + + this.initialMetadataSent = true; + sendCompletionDelegate = completionDelegate; + } + } + /// /// Sends call result status, also indicating server is done with streaming responses. /// Only one pending send action is allowed at any given time. @@ -111,7 +139,7 @@ namespace Grpc.Core.Internal using (var metadataArray = MetadataArraySafeHandle.Create(trailers)) { - call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, writeFlags); + call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, writeFlags, !initialMetadataSent); } halfcloseRequested = true; readingDone = true; diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index be1426feb47..02502a6f018 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -70,7 +70,7 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, - BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags); + BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, @@ -78,7 +78,7 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, - BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); + BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags, bool sendEmptyInitialMetadata); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, @@ -142,11 +142,11 @@ namespace Grpc.Core.Internal grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, writeFlags).CheckOk(); } - public void StartSendMessage(BatchCompletionDelegate callback, byte[] payload, WriteFlags writeFlags) + public void StartSendMessage(BatchCompletionDelegate callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags).CheckOk(); + grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata).CheckOk(); } public void StartSendCloseFromClient(BatchCompletionDelegate callback, WriteFlags writeFlags) @@ -156,11 +156,11 @@ namespace Grpc.Core.Internal grpcsharp_call_send_close_from_client(this, ctx, writeFlags).CheckOk(); } - public void StartSendStatusFromServer(BatchCompletionDelegate callback, Status status, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + public void StartSendStatusFromServer(BatchCompletionDelegate callback, Status status, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags, bool sendEmptyInitialMetadata) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, writeFlags).CheckOk(); + grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, writeFlags, sendEmptyInitialMetadata).CheckOk(); } public void StartReceiveMessage(BatchCompletionDelegate callback) @@ -177,7 +177,7 @@ namespace Grpc.Core.Internal grpcsharp_call_start_serverside(this, ctx).CheckOk(); } - public void SendInitialMetadata(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + public void StartSendInitialMetadata(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); diff --git a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs index 4a146949772..dd7f4256c43 100644 --- a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs +++ b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs @@ -68,6 +68,7 @@ namespace Grpc.Core.Internal { return this.writeOptions; } + set { writeOptions = value; diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 34db03cc383..74af19dc019 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -304,13 +304,15 @@ namespace Grpc.Core.Internal return new Status(StatusCode.Unknown, "Exception was thrown by handler."); } - public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, IHasWriteOptions writeOptionsHolder, CancellationToken cancellationToken) + public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, ServerResponseStream serverResponseStream, CancellationToken cancellationToken) + where TRequest : class + where TResponse : class { DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); return new ServerCallContext( newRpc.Method, newRpc.Host, peer, realtimeDeadline, - newRpc.RequestMetadata, cancellationToken, writeOptionsHolder); + newRpc.RequestMetadata, cancellationToken, serverResponseStream.WriteResponseHeadersAsync, serverResponseStream); } } } diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs index 1d79241f776..5dcd5a72209 100644 --- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs +++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs @@ -64,12 +64,20 @@ namespace Grpc.Core.Internal return taskSource.Task; } + public Task WriteResponseHeadersAsync(Metadata responseHeaders) + { + var taskSource = new AsyncCompletionTaskSource(); + call.StartSendInitialMetadata(responseHeaders, GetWriteFlags(), taskSource.CompletionDelegate); + return taskSource.Task; + } + public WriteOptions WriteOptions { get { return writeOptions; } + set { writeOptions = value; diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 5657eb8513e..7849df9bb4b 100644 --- a/src/csharp/Grpc.Core/ServerCallContext.cs +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -43,10 +43,8 @@ namespace Grpc.Core /// /// Context for a server-side call. /// - public sealed class ServerCallContext + public class ServerCallContext { - // TODO(jtattermusch): expose method to send initial metadata back to client - private readonly string method; private readonly string host; private readonly string peer; @@ -56,9 +54,11 @@ namespace Grpc.Core private readonly Metadata responseTrailers = new Metadata(); private Status status = Status.DefaultSuccess; + private Func writeHeadersFunc; private IHasWriteOptions writeOptionsHolder; - public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, IHasWriteOptions writeOptionsHolder) + public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, + Func writeHeadersFunc, IHasWriteOptions writeOptionsHolder) { this.method = method; this.host = host; @@ -66,8 +66,14 @@ namespace Grpc.Core this.deadline = deadline; this.requestHeaders = requestHeaders; this.cancellationToken = cancellationToken; + this.writeHeadersFunc = writeHeadersFunc; this.writeOptionsHolder = writeOptionsHolder; } + + public Task WriteResponseHeadersAsync(Metadata responseHeaders) + { + return writeHeadersFunc(responseHeaders); + } /// Name of method called in this RPC. public string Method @@ -114,7 +120,7 @@ namespace Grpc.Core } } - ///Cancellation token signals when call is cancelled. + /// Cancellation token signals when call is cancelled. public CancellationToken CancellationToken { get @@ -157,6 +163,7 @@ namespace Grpc.Core { return writeOptionsHolder.WriteOptions; } + set { writeOptionsHolder.WriteOptions = value; diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 165459371b8..cb138064e1b 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -651,15 +651,22 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx, - const char *send_buffer, size_t send_buffer_len, gpr_uint32 write_flags) { + const char *send_buffer, size_t send_buffer_len, + gpr_uint32 write_flags, + gpr_int32 send_empty_initial_metadata) { /* TODO: don't use magic number */ - grpc_op ops[1]; + grpc_op ops[2]; + size_t nops = send_empty_initial_metadata ? 2 : 1; ops[0].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[0].data.send_message = ctx->send_message; ops[0].flags = write_flags; + ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; + ops[1].data.send_initial_metadata.count = 0; + ops[1].data.send_initial_metadata.metadata = NULL; + ops[1].flags = 0; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); + return grpc_call_start_batch(call, ops, nops, ctx); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -675,9 +682,11 @@ grpcsharp_call_send_close_from_client(grpc_call *call, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code, - const char *status_details, grpc_metadata_array *trailing_metadata, gpr_uint32 write_flags) { + const char *status_details, grpc_metadata_array *trailing_metadata, + gpr_uint32 write_flags, gpr_int32 send_empty_initial_metadata) { /* TODO: don't use magic number */ - grpc_op ops[1]; + grpc_op ops[2]; + size_t nops = send_empty_initial_metadata ? 2 : 1; ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER; ops[0].data.send_status_from_server.status = status_code; ops[0].data.send_status_from_server.status_details = @@ -689,8 +698,12 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( ops[0].data.send_status_from_server.trailing_metadata = ctx->send_status_from_server.trailing_metadata.metadata; ops[0].flags = write_flags; + ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; + ops[1].data.send_initial_metadata.count = 0; + ops[1].data.send_initial_metadata.metadata = NULL; + ops[1].flags = 0; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); + return grpc_call_start_batch(call, ops, nops, ctx); } GPR_EXPORT grpc_call_error GPR_CALLTYPE From 9b2c25e806d4fae42c49daa042ddd4491366f373 Mon Sep 17 00:00:00 2001 From: vjpai Date: Fri, 7 Aug 2015 17:45:16 -0700 Subject: [PATCH 066/117] Bounds checking for ops in call batch --- include/grpc/grpc.h | 4 +++- src/core/surface/call.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index bf340e81ca0..4f140971515 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -181,7 +181,9 @@ typedef enum grpc_call_error { GRPC_CALL_ERROR_INVALID_MESSAGE, /** completion queue for notification has not been registered with the server */ - GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE + GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE, + /** this batch of operations leads to more operations than allowed */ + GRPC_CALL_ERROR_BATCH_TOO_BIG } grpc_call_error; /* Write Flags: */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 6e566e6a8f8..5839d3ac2e4 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -1539,6 +1539,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_INITIAL_METADATA; req->data.send_metadata.count = op->data.send_initial_metadata.count; req->data.send_metadata.metadata = @@ -1553,6 +1554,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_INVALID_MESSAGE; } req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_MESSAGE; req->data.send_message = op->data.send_message; req->flags = op->flags; @@ -1564,6 +1566,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; req->flags = op->flags; break; @@ -1574,6 +1577,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_CLIENT; } req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_TRAILING_METADATA; req->flags = op->flags; req->data.send_metadata.count = @@ -1581,6 +1585,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, req->data.send_metadata.metadata = op->data.send_status_from_server.trailing_metadata; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_STATUS; req->data.send_status.code = op->data.send_status_from_server.status; req->data.send_status.details = @@ -1590,6 +1595,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, op->data.send_status_from_server.status_details, 0) : NULL; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; break; case GRPC_OP_RECV_INITIAL_METADATA: @@ -1599,6 +1605,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_INITIAL_METADATA; req->data.recv_metadata = op->data.recv_initial_metadata; req->data.recv_metadata->count = 0; @@ -1608,6 +1615,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_MESSAGE; req->data.recv_message = op->data.recv_message; req->flags = op->flags; @@ -1619,22 +1627,26 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_status_value_directly; req->data.recv_status.user_data = op->data.recv_status_on_client.status; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS_DETAILS; req->data.recv_status_details.details = op->data.recv_status_on_client.status_details; req->data.recv_status_details.details_capacity = op->data.recv_status_on_client.status_details_capacity; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_TRAILING_METADATA; req->data.recv_metadata = op->data.recv_status_on_client.trailing_metadata; req->data.recv_metadata->count = 0; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; @@ -1642,12 +1654,14 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_cancelled_value; req->data.recv_status.user_data = op->data.recv_close_on_server.cancelled; req = &reqs[out++]; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; From c678c30cf19d47961f04e5782b7890d3b289b7f0 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Aug 2015 18:28:29 -0700 Subject: [PATCH 067/117] Fix ForwardingWriter init preconditions --- src/objective-c/RxLibrary/GRXForwardingWriter.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/objective-c/RxLibrary/GRXForwardingWriter.m b/src/objective-c/RxLibrary/GRXForwardingWriter.m index 2342f51ab36..cf8be8c557e 100644 --- a/src/objective-c/RxLibrary/GRXForwardingWriter.m +++ b/src/objective-c/RxLibrary/GRXForwardingWriter.m @@ -48,7 +48,10 @@ // Designated initializer - (instancetype)initWithWriter:(GRXWriter *)writer { if (!writer) { - [NSException raise:NSInvalidArgumentException format:@"writer can't be nil."]; + return nil; + } + if (writer.state != GRXWriterStateNotStarted) { + [NSException raise:NSInvalidArgumentException format:@"writer can't be started."]; } if ((self = [super init])) { _writer = writer; From 5b0b392cc3e02d7014b918250d6dd1d946a68d46 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 19:07:14 -0700 Subject: [PATCH 068/117] introduced MockServiceHelper to ease testing --- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + .../Grpc.Core.Tests/MockServiceHelper.cs | 244 ++++++++++++++++++ src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 124 +++------ 3 files changed, 287 insertions(+), 82 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/MockServiceHelper.cs diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index f2bf459dc50..55d0c98d442 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -77,6 +77,7 @@ + diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs new file mode 100644 index 00000000000..25afa30bba7 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -0,0 +1,244 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + /// + /// Allows setting up a mock service in the client-server tests easily. + /// + public class MockServiceHelper + { + public const string ServiceName = "tests.Test"; + + public static readonly Method UnaryMethod = new Method( + MethodType.Unary, + ServiceName, + "Unary", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + public static readonly Method ClientStreamingMethod = new Method( + MethodType.ClientStreaming, + ServiceName, + "ClientStreaming", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + public static readonly Method ServerStreamingMethod = new Method( + MethodType.ServerStreaming, + ServiceName, + "ServerStreaming", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + public static readonly Method DuplexStreamingMethod = new Method( + MethodType.DuplexStreaming, + ServiceName, + "DuplexStreaming", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + readonly string host; + readonly ServerServiceDefinition serviceDefinition; + + UnaryServerMethod unaryHandler; + ClientStreamingServerMethod clientStreamingHandler; + ServerStreamingServerMethod serverStreamingHandler; + DuplexStreamingServerMethod duplexStreamingHandler; + + Server server; + Channel channel; + + public MockServiceHelper(string host = null) + { + this.host = host ?? "localhost"; + + serviceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) + .AddMethod(UnaryMethod, (request, context) => unaryHandler(request, context)) + .AddMethod(ClientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context)) + .AddMethod(ServerStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context)) + .AddMethod(DuplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context)) + .Build(); + + var defaultStatus = new Status(StatusCode.Unknown, "Default mock implementation. Please provide your own."); + + unaryHandler = new UnaryServerMethod(async (request, context) => + { + context.Status = defaultStatus; + return ""; + }); + + clientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + context.Status = defaultStatus; + return ""; + }); + + serverStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => + { + context.Status = defaultStatus; + }); + + duplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => + { + context.Status = defaultStatus; + }); + } + + /// + /// Returns the default server for this service and creates one if not yet created. + /// + public Server GetServer() + { + if (server == null) + { + server = new Server + { + Services = { serviceDefinition }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } + }; + } + return server; + } + + /// + /// Returns the default channel for this service and creates one if not yet created. + /// + public Channel GetChannel() + { + if (channel == null) + { + channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure); + } + return channel; + } + + public CallInvocationDetails CreateUnaryCall(CallOptions options = null) + { + options = options ?? new CallOptions(); + return new CallInvocationDetails(channel, UnaryMethod, options); + } + + public CallInvocationDetails CreateClientStreamingCall(CallOptions options = null) + { + options = options ?? new CallOptions(); + return new CallInvocationDetails(channel, ClientStreamingMethod, options); + } + + public CallInvocationDetails CreateServerStreamingCall(CallOptions options = null) + { + options = options ?? new CallOptions(); + return new CallInvocationDetails(channel, ServerStreamingMethod, options); + } + + public CallInvocationDetails CreateDuplexStreamingCall(CallOptions options = null) + { + options = options ?? new CallOptions(); + return new CallInvocationDetails(channel, DuplexStreamingMethod, options); + } + + public string Host + { + get + { + return this.host; + } + } + + public ServerServiceDefinition ServiceDefinition + { + get + { + return this.serviceDefinition; + } + } + + public UnaryServerMethod UnaryHandler + { + get + { + return this.unaryHandler; + } + set + { + unaryHandler = value; + } + } + + public ClientStreamingServerMethod ClientStreamingHandler + { + get + { + return this.clientStreamingHandler; + } + set + { + clientStreamingHandler = value; + } + } + + public ServerStreamingServerMethod ServerStreamingHandler + { + get + { + return this.serverStreamingHandler; + } + set + { + serverStreamingHandler = value; + } + } + + public DuplexStreamingServerMethod DuplexStreamingHandler + { + get + { + return this.duplexStreamingHandler; + } + set + { + duplexStreamingHandler = value; + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index fc395b0acda..239fc95cb6a 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -48,38 +48,15 @@ namespace Grpc.Core.Tests /// public class TimeoutsTest { - const string Host = "localhost"; - const string ServiceName = "tests.Test"; - - static readonly Method TestMethod = new Method( - MethodType.Unary, - ServiceName, - "Test", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) - .AddMethod(TestMethod, TestMethodHandler) - .Build(); - - // provides a way how to retrieve an out-of-band result value from server handler - static TaskCompletionSource stringFromServerHandlerTcs; - + MockServiceHelper helper = new MockServiceHelper(); Server server; Channel channel; [SetUp] public void Init() { - server = new Server - { - Services = { ServiceDefinition }, - Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } - }; - server.Start(); - channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); - - stringFromServerHandlerTcs = new TaskCompletionSource(); + server = helper.GetServer(); + channel = helper.GetChannel(); } [TearDown] @@ -98,40 +75,44 @@ namespace Grpc.Core.Tests [Test] public void InfiniteDeadline() { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + Assert.AreEqual(DateTime.MaxValue, context.Deadline); + return "PASS"; + }); + // no deadline specified, check server sees infinite deadline - var callDetails = new CallInvocationDetails(channel, TestMethod, new CallOptions()); - Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE")); + Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); // DateTime.MaxValue deadline specified, check server sees infinite deadline - var callDetails2 = new CallInvocationDetails(channel, TestMethod, new CallOptions()); - Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails2, "RETURN_DEADLINE")); + Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MaxValue)), "abc")); } [Test] public void DeadlineTransferredToServer() { - var remainingTimeClient = TimeSpan.FromDays(7); - var deadline = DateTime.UtcNow + remainingTimeClient; - Thread.Sleep(1000); - var callDetails = new CallInvocationDetails(channel, TestMethod, new CallOptions(deadline: deadline)); - - var serverDeadlineTicksString = Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE"); - var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc); - - // A fairly relaxed check that the deadline set by client and deadline seen by server - // are in agreement. C core takes care of the work with transferring deadline over the wire, - // so we don't need an exact check here. - Assert.IsTrue(Math.Abs((deadline - serverDeadline).TotalMilliseconds) < 5000); + var clientDeadline = DateTime.UtcNow + TimeSpan.FromDays(7); + + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + // A fairly relaxed check that the deadline set by client and deadline seen by server + // are in agreement. C core takes care of the work with transferring deadline over the wire, + // so we don't need an exact check here. + Assert.IsTrue(Math.Abs((clientDeadline - context.Deadline).TotalMilliseconds) < 5000); + return "PASS"; + }); + Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: clientDeadline)), "abc"); } [Test] public void DeadlineInThePast() { - var callDetails = new CallInvocationDetails(channel, TestMethod, new CallOptions(deadline: DateTime.MinValue)); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + await Task.Delay(60000); + return "FAIL"; + }); try { - Calls.BlockingUnaryCall(callDetails, "TIMEOUT"); + Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MinValue)), "abc"); Assert.Fail(); } catch (RpcException e) @@ -144,12 +125,14 @@ namespace Grpc.Core.Tests [Test] public void DeadlineExceededStatusOnTimeout() { - var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); - var callDetails = new CallInvocationDetails(channel, TestMethod, new CallOptions(deadline: deadline)); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + await Task.Delay(60000); + return "FAIL"; + }); try { - Calls.BlockingUnaryCall(callDetails, "TIMEOUT"); + Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc"); Assert.Fail(); } catch (RpcException e) @@ -162,12 +145,20 @@ namespace Grpc.Core.Tests [Test] public void ServerReceivesCancellationOnTimeout() { - var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); - var callDetails = new CallInvocationDetails(channel, TestMethod, new CallOptions(deadline: deadline)); + string receivedCancellation = "NO"; + + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + // wait until cancellation token is fired. + var tcs = new TaskCompletionSource(); + context.CancellationToken.Register(() => { tcs.SetResult(null); }); + await tcs.Task; + receivedCancellation = "YES"; + return ""; + }); try { - Calls.BlockingUnaryCall(callDetails, "CHECK_CANCELLATION_RECEIVED"); + Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc"); Assert.Fail(); } catch (RpcException e) @@ -175,38 +166,7 @@ namespace Grpc.Core.Tests // We can't guarantee the status code is always DeadlineExceeded. See issue #2685. Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } - Assert.AreEqual("CANCELLED", stringFromServerHandlerTcs.Task.Result); - } - - private static async Task TestMethodHandler(string request, ServerCallContext context) - { - if (request == "TIMEOUT") - { - await Task.Delay(60000); - return ""; - } - - if (request == "RETURN_DEADLINE") - { - if (context.Deadline == DateTime.MaxValue) - { - return "DATETIME_MAXVALUE"; - } - - return context.Deadline.Ticks.ToString(); - } - - if (request == "CHECK_CANCELLATION_RECEIVED") - { - // wait until cancellation token is fired. - var tcs = new TaskCompletionSource(); - context.CancellationToken.Register(() => { tcs.SetResult(null); }); - await tcs.Task; - stringFromServerHandlerTcs.SetResult("CANCELLED"); - return ""; - } - - return ""; + Assert.AreEqual("YES", receivedCancellation); } } } From a4291e7073a40777bfe8845bd926612a76e154f6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 19:13:31 -0700 Subject: [PATCH 069/117] fixing tests --- src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index 239fc95cb6a..51709813bf8 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -48,14 +48,17 @@ namespace Grpc.Core.Tests /// public class TimeoutsTest { - MockServiceHelper helper = new MockServiceHelper(); + MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { + helper = new MockServiceHelper(); + server = helper.GetServer(); + server.Start(); channel = helper.GetChannel(); } @@ -145,6 +148,7 @@ namespace Grpc.Core.Tests [Test] public void ServerReceivesCancellationOnTimeout() { + object myLock = new object(); string receivedCancellation = "NO"; helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { @@ -152,7 +156,10 @@ namespace Grpc.Core.Tests var tcs = new TaskCompletionSource(); context.CancellationToken.Register(() => { tcs.SetResult(null); }); await tcs.Task; - receivedCancellation = "YES"; + lock (myLock) + { + receivedCancellation = "YES"; + } return ""; }); @@ -166,7 +173,11 @@ namespace Grpc.Core.Tests // We can't guarantee the status code is always DeadlineExceeded. See issue #2685. Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } - Assert.AreEqual("YES", receivedCancellation); + + lock (myLock) + { + Assert.AreEqual("YES", receivedCancellation); + } } } } From 0abb84746ce3f35bb859c0b5a88afa5cff5e2ef0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 20:28:44 -0700 Subject: [PATCH 070/117] big facelift of test code --- .../Grpc.Core.Tests/ClientServerTest.cs | 282 +++++++----------- src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 39 +-- 2 files changed, 117 insertions(+), 204 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 64ea21800fd..eb9cd7cf0cf 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -46,47 +46,18 @@ namespace Grpc.Core.Tests public class ClientServerTest { const string Host = "127.0.0.1"; - const string ServiceName = "tests.Test"; - - static readonly Method EchoMethod = new Method( - MethodType.Unary, - ServiceName, - "Echo", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - static readonly Method ConcatAndEchoMethod = new Method( - MethodType.ClientStreaming, - ServiceName, - "ConcatAndEcho", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - static readonly Method NonexistentMethod = new Method( - MethodType.Unary, - ServiceName, - "NonexistentMethod", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) - .AddMethod(EchoMethod, EchoHandler) - .AddMethod(ConcatAndEchoMethod, ConcatAndEchoHandler) - .Build(); + MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { - server = new Server - { - Services = { ServiceDefinition }, - Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } - }; + helper = new MockServiceHelper(Host); + server = helper.GetServer(); server.Start(); - channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); + channel = helper.GetChannel(); } [TearDown] @@ -103,86 +74,79 @@ namespace Grpc.Core.Tests } [Test] - public void UnaryCall() + public async Task UnaryCall() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - Assert.AreEqual("ABC", Calls.BlockingUnaryCall(callDetails, "ABC")); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return request; + }); + + Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); + + Assert.AreEqual("ABC", await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC")); } [Test] public void UnaryCall_ServerHandlerThrows() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - try + helper.UnaryHandler = new UnaryServerMethod((request, context) => { - Calls.BlockingUnaryCall(callDetails, "THROW"); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); - } + throw new Exception("This was thrown on purpose by a test"); + }); + + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); + + var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unknown, ex2.Status.StatusCode); } [Test] public void UnaryCall_ServerHandlerThrowsRpcException() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - try - { - Calls.BlockingUnaryCall(callDetails, "THROW_UNAUTHENTICATED"); - Assert.Fail(); - } - catch (RpcException e) + helper.UnaryHandler = new UnaryServerMethod((request, context) => { - Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode); - } + throw new RpcException(new Status(StatusCode.Unauthenticated, "")); + }); + + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); + + var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); } [Test] public void UnaryCall_ServerHandlerSetsStatus() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - try - { - Calls.BlockingUnaryCall(callDetails, "SET_UNAUTHENTICATED"); - Assert.Fail(); - } - catch (RpcException e) + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { - Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode); - } - } + context.Status = new Status(StatusCode.Unauthenticated, ""); + return ""; + }); - [Test] - public async Task AsyncUnaryCall() - { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - var result = await Calls.AsyncUnaryCall(callDetails, "ABC"); - Assert.AreEqual("ABC", result); - } + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); - [Test] - public async Task AsyncUnaryCall_ServerHandlerThrows() - { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - try - { - await Calls.AsyncUnaryCall(callDetails, "THROW"); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); - } + var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); + Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); } [Test] public async Task ClientStreamingCall() { - var callDetails = new CallInvocationDetails(channel, ConcatAndEchoMethod, new CallOptions()); - var call = Calls.AsyncClientStreamingCall(callDetails); + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + string result = ""; + await requestStream.ForEach(async (request) => + { + result += request; + }); + await Task.Delay(100); + return result; + }); + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); Assert.AreEqual("ABC", await call.ResponseAsync); } @@ -190,34 +154,46 @@ namespace Grpc.Core.Tests [Test] public async Task ClientStreamingCall_CancelAfterBegin() { + var barrier = new TaskCompletionSource(); + + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + barrier.SetResult(null); + await requestStream.ToList(); + return ""; + }); + var cts = new CancellationTokenSource(); - var callDetails = new CallInvocationDetails(channel, ConcatAndEchoMethod, new CallOptions(cancellationToken: cts.Token)); - var call = Calls.AsyncClientStreamingCall(callDetails); + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token))); - // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. - await Task.Delay(1000); + await barrier.Task; // make sure the handler has started. cts.Cancel(); - try - { - await call.ResponseAsync; - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } + var ex = Assert.Throws(async () => await call.ResponseAsync); + Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } [Test] public void AsyncUnaryCall_EchoMetadata() { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + foreach (Metadata.Entry metadataEntry in context.RequestHeaders) + { + if (metadataEntry.Key != "user-agent") + { + context.ResponseTrailers.Add(metadataEntry); + } + } + return ""; + }); + var headers = new Metadata { new Metadata.Entry("ascii-header", "abcdefg"), new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }), }; - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions(headers: headers)); - var call = Calls.AsyncUnaryCall(callDetails, "ABC"); + var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC"); Assert.AreEqual("ABC", call.ResponseAsync.Result); @@ -236,15 +212,13 @@ namespace Grpc.Core.Tests public void UnaryCall_DisposedChannel() { channel.Dispose(); - - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(callDetails, "ABC")); + Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); } [Test] public void UnaryCallPerformance() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); + var callDetails = helper.CreateUnaryCall(); BenchmarkUtil.RunBenchmark(100, 100, () => { Calls.BlockingUnaryCall(callDetails, "ABC"); }); } @@ -252,44 +226,57 @@ namespace Grpc.Core.Tests [Test] public void UnknownMethodHandler() { - var callDetails = new CallInvocationDetails(channel, NonexistentMethod, new CallOptions()); - try - { - Calls.BlockingUnaryCall(callDetails, "ABC"); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); - } + var nonexistentMethod = new Method( + MethodType.Unary, + MockServiceHelper.ServiceName, + "NonExistentMethod", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + var callDetails = new CallInvocationDetails(channel, nonexistentMethod, new CallOptions()); + + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(callDetails, "abc")); + Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode); } [Test] public void UserAgentStringPresent() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - string userAgent = Calls.BlockingUnaryCall(callDetails, "RETURN-USER-AGENT"); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value; + }); + + string userAgent = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"); Assert.IsTrue(userAgent.StartsWith("grpc-csharp/")); } [Test] public void PeerInfoPresent() { - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - string peer = Calls.BlockingUnaryCall(callDetails, "RETURN-PEER"); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return context.Peer; + }); + + string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"); Assert.IsTrue(peer.Contains(Host)); } [Test] public async Task Channel_WaitForStateChangedAsync() { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return request; + }); + Assert.Throws(typeof(TaskCanceledException), async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10))); var stateChangedTask = channel.WaitForStateChangedAsync(channel.State); - var callDetails = new CallInvocationDetails(channel, EchoMethod, new CallOptions()); - await Calls.AsyncUnaryCall(callDetails, "abc"); + await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"); await stateChangedTask; Assert.AreEqual(ChannelState.Ready, channel.State); @@ -300,62 +287,9 @@ namespace Grpc.Core.Tests { await channel.ConnectAsync(); Assert.AreEqual(ChannelState.Ready, channel.State); + await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(1000)); Assert.AreEqual(ChannelState.Ready, channel.State); } - - private static async Task EchoHandler(string request, ServerCallContext context) - { - foreach (Metadata.Entry metadataEntry in context.RequestHeaders) - { - if (metadataEntry.Key != "user-agent") - { - context.ResponseTrailers.Add(metadataEntry); - } - } - - if (request == "RETURN-USER-AGENT") - { - return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value; - } - - if (request == "RETURN-PEER") - { - return context.Peer; - } - - if (request == "THROW") - { - throw new Exception("This was thrown on purpose by a test"); - } - - if (request == "THROW_UNAUTHENTICATED") - { - throw new RpcException(new Status(StatusCode.Unauthenticated, "")); - } - - if (request == "SET_UNAUTHENTICATED") - { - context.Status = new Status(StatusCode.Unauthenticated, ""); - } - - return request; - } - - private static async Task ConcatAndEchoHandler(IAsyncStreamReader requestStream, ServerCallContext context) - { - string result = ""; - await requestStream.ForEach(async (request) => - { - if (request == "THROW") - { - throw new Exception("This was thrown on purpose by a test"); - } - result += request; - }); - // simulate processing takes some time. - await Task.Delay(250); - return result; - } } } diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index 51709813bf8..a52020cf402 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -113,16 +113,9 @@ namespace Grpc.Core.Tests return "FAIL"; }); - try - { - Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MinValue)), "abc"); - Assert.Fail(); - } - catch (RpcException e) - { - // We can't guarantee the status code always DeadlineExceeded. See issue #2685. - Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); - } + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MinValue)), "abc")); + // We can't guarantee the status code always DeadlineExceeded. See issue #2685. + Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } [Test] @@ -133,16 +126,9 @@ namespace Grpc.Core.Tests return "FAIL"; }); - try - { - Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc"); - Assert.Fail(); - } - catch (RpcException e) - { - // We can't guarantee the status code always DeadlineExceeded. See issue #2685. - Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); - } + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); + // We can't guarantee the status code always DeadlineExceeded. See issue #2685. + Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } [Test] @@ -163,16 +149,9 @@ namespace Grpc.Core.Tests return ""; }); - try - { - Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc"); - Assert.Fail(); - } - catch (RpcException e) - { - // We can't guarantee the status code is always DeadlineExceeded. See issue #2685. - Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); - } + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); + // We can't guarantee the status code always DeadlineExceeded. See issue #2685. + Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); lock (myLock) { From 2615f39b208efec60619ee431e17acbf4d60a458 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 20:41:26 -0700 Subject: [PATCH 071/117] fixing tests --- src/csharp/Grpc.Core.Tests/ClientServerTest.cs | 9 ++++++--- src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 15 ++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index eb9cd7cf0cf..08c80bbe534 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -174,7 +174,7 @@ namespace Grpc.Core.Tests } [Test] - public void AsyncUnaryCall_EchoMetadata() + public async Task AsyncUnaryCall_EchoMetadata() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { @@ -194,8 +194,7 @@ namespace Grpc.Core.Tests new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }), }; var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC"); - - Assert.AreEqual("ABC", call.ResponseAsync.Result); + await call; Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); @@ -218,6 +217,10 @@ namespace Grpc.Core.Tests [Test] public void UnaryCallPerformance() { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + return request; + }); + var callDetails = helper.CreateUnaryCall(); BenchmarkUtil.RunBenchmark(100, 100, () => { Calls.BlockingUnaryCall(callDetails, "ABC"); }); diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index a52020cf402..ead0b1854ba 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -132,20 +132,16 @@ namespace Grpc.Core.Tests } [Test] - public void ServerReceivesCancellationOnTimeout() + public async Task ServerReceivesCancellationOnTimeout() { - object myLock = new object(); - string receivedCancellation = "NO"; + var serverReceivedCancellationTcs = new TaskCompletionSource(); helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { // wait until cancellation token is fired. var tcs = new TaskCompletionSource(); context.CancellationToken.Register(() => { tcs.SetResult(null); }); await tcs.Task; - lock (myLock) - { - receivedCancellation = "YES"; - } + serverReceivedCancellationTcs.SetResult(true); return ""; }); @@ -153,10 +149,7 @@ namespace Grpc.Core.Tests // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); - lock (myLock) - { - Assert.AreEqual("YES", receivedCancellation); - } + Assert.IsTrue(await serverReceivedCancellationTcs.Task); } } } From c8d7b8498c97694fcfc9d82d5aae64598697e7dd Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 20:52:21 -0700 Subject: [PATCH 072/117] polishing tests --- .../MathClientServerTests.cs | 24 +++++-------------- .../Grpc.IntegrationTesting/InteropClient.cs | 22 ++++------------- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 08aece7ef20..73d2a1ca9bb 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -92,15 +92,8 @@ namespace math.Tests [Test] public void DivByZero() { - try - { - DivReply response = client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 0 }.Build()); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); - } + var ex = Assert.Throws(() => client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 0 }.Build())); + Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); } [Test] @@ -158,15 +151,10 @@ namespace math.Tests using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), deadline: DateTime.UtcNow.AddMilliseconds(500))) { - try - { - await call.ResponseStream.ToList(); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); - } + var ex = Assert.Throws(async () => await call.ResponseStream.ToList()); + + // We can't guarantee the status code always DeadlineExceeded. See issue #2685. + Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 7411d91d5a7..6802de489dc 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -404,15 +404,8 @@ namespace Grpc.IntegrationTesting await Task.Delay(1000); cts.Cancel(); - try - { - var response = await call.ResponseAsync; - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } + var ex = Assert.Throws(async () => await call.ResponseAsync); + Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } Console.WriteLine("Passed!"); } @@ -435,15 +428,8 @@ namespace Grpc.IntegrationTesting cts.Cancel(); - try - { - await call.ResponseStream.MoveNext(); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } + var ex = Assert.Throws(async () => await call.ResponseStream.MoveNext()); + Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } Console.WriteLine("Passed!"); } From c75c57c5af620491d0043047533fa0e2f078b09f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 22:07:40 -0700 Subject: [PATCH 073/117] added ResponseHeadersTest, fixed stylecop issues --- .../Grpc.Core.Tests/ClientServerTest.cs | 3 +- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + .../Grpc.Core.Tests/MockServiceHelper.cs | 4 + .../Grpc.Core.Tests/ResponseHeadersTest.cs | 139 ++++++++++++++++++ src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 15 +- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 2 +- .../Grpc.Core/Internal/AsyncCallServer.cs | 3 +- src/csharp/Grpc.Core/WriteOptions.cs | 1 - 8 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 08c80bbe534..f56fb744a61 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -217,7 +217,8 @@ namespace Grpc.Core.Tests [Test] public void UnaryCallPerformance() { - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { return request; }); diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 55d0c98d442..4692d958a05 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -78,6 +78,7 @@ + diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs index 25afa30bba7..b642286b116 100644 --- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -199,6 +199,7 @@ namespace Grpc.Core.Tests { return this.unaryHandler; } + set { unaryHandler = value; @@ -211,6 +212,7 @@ namespace Grpc.Core.Tests { return this.clientStreamingHandler; } + set { clientStreamingHandler = value; @@ -223,6 +225,7 @@ namespace Grpc.Core.Tests { return this.serverStreamingHandler; } + set { serverStreamingHandler = value; @@ -235,6 +238,7 @@ namespace Grpc.Core.Tests { return this.duplexStreamingHandler; } + set { duplexStreamingHandler = value; diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs new file mode 100644 index 00000000000..b0244885494 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs @@ -0,0 +1,139 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + /// + /// Tests for response headers support. + /// + public class ResponseHeadersTest + { + MockServiceHelper helper; + Server server; + Channel channel; + + Metadata headers; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(); + + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + + headers = new Metadata + { + new Metadata.Entry("ascii-header", "abcdefg"), + }; + } + + [TearDown] + public void Cleanup() + { + channel.Dispose(); + server.ShutdownAsync().Wait(); + } + + [TestFixtureTearDown] + public void CleanupClass() + { + GrpcEnvironment.Shutdown(); + } + + [Test] + public void WriteResponseHeaders_NullNotAllowed() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + Assert.Throws(typeof(NullReferenceException), async () => await context.WriteResponseHeadersAsync(null)); + return "PASS"; + }); + + Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); + } + + [Test] + public void WriteResponseHeaders_AllowedOnlyOnce() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + await context.WriteResponseHeadersAsync(headers); + try + { + await context.WriteResponseHeadersAsync(headers); + Assert.Fail(); + } + catch (InvalidOperationException expected) + { + } + return "PASS"; + }); + + Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); + } + + [Test] + public async Task WriteResponseHeaders_NotAllowedAfterWrite() + { + helper.ServerStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => + { + await responseStream.WriteAsync("A"); + try + { + await context.WriteResponseHeadersAsync(headers); + Assert.Fail(); + } + catch (InvalidOperationException expected) + { + } + await responseStream.WriteAsync("B"); + }); + + var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); + var responses = await call.ResponseStream.ToList(); + CollectionAssert.AreEqual(new[] { "A", "B" }, responses); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index ead0b1854ba..d875d601b94 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -78,7 +78,8 @@ namespace Grpc.Core.Tests [Test] public void InfiniteDeadline() { - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { Assert.AreEqual(DateTime.MaxValue, context.Deadline); return "PASS"; }); @@ -95,7 +96,8 @@ namespace Grpc.Core.Tests { var clientDeadline = DateTime.UtcNow + TimeSpan.FromDays(7); - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { // A fairly relaxed check that the deadline set by client and deadline seen by server // are in agreement. C core takes care of the work with transferring deadline over the wire, // so we don't need an exact check here. @@ -108,7 +110,8 @@ namespace Grpc.Core.Tests [Test] public void DeadlineInThePast() { - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { await Task.Delay(60000); return "FAIL"; }); @@ -121,7 +124,8 @@ namespace Grpc.Core.Tests [Test] public void DeadlineExceededStatusOnTimeout() { - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { await Task.Delay(60000); return "FAIL"; }); @@ -136,7 +140,8 @@ namespace Grpc.Core.Tests { var serverReceivedCancellationTcs = new TaskCompletionSource(); - helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { // wait until cancellation token is fired. var tcs = new TaskCompletionSource(); context.CancellationToken.Register(() => { tcs.SetResult(null); }); diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index c8c2449ee6f..df5c07e4c49 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -279,7 +279,7 @@ namespace Grpc.Core.Internal } } - public CallInvocationDetails Details + public CallInvocationDetails Details { get { diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 9eac7f7b614..1704b9afbf4 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -107,10 +107,11 @@ namespace Grpc.Core.Internal { lock (myLock) { + Preconditions.CheckNotNull(headers, "metadata"); Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); Preconditions.CheckState(!initialMetadataSent, "Response headers can only be sent once per call."); - Preconditions.CheckState(streamingWritesCounter > 0, "Response headers can only be sent before the first write starts."); + Preconditions.CheckState(streamingWritesCounter == 0, "Response headers can only be sent before the first write starts."); CheckSendingAllowed(); Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); diff --git a/src/csharp/Grpc.Core/WriteOptions.cs b/src/csharp/Grpc.Core/WriteOptions.cs index ec4a7dd8cdd..7ef3189d762 100644 --- a/src/csharp/Grpc.Core/WriteOptions.cs +++ b/src/csharp/Grpc.Core/WriteOptions.cs @@ -54,7 +54,6 @@ namespace Grpc.Core NoCompress = 0x2 } - /// /// Options for write operations. /// From 67ce098ccf6c7d5b64a85523af1c96e04e46312a Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Aug 2015 23:10:49 -0700 Subject: [PATCH 074/117] Clarify thread-safety expectations of GRXWriters --- src/objective-c/RxLibrary/GRXBufferedPipe.h | 9 +++-- .../RxLibrary/GRXForwardingWriter.h | 10 ++++- .../RxLibrary/GRXImmediateWriter.h | 13 +++++-- src/objective-c/RxLibrary/GRXWriter.h | 39 +++++++++---------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/objective-c/RxLibrary/GRXBufferedPipe.h b/src/objective-c/RxLibrary/GRXBufferedPipe.h index b6296e1ed72..ca94ce275f7 100644 --- a/src/objective-c/RxLibrary/GRXBufferedPipe.h +++ b/src/objective-c/RxLibrary/GRXBufferedPipe.h @@ -36,13 +36,11 @@ #import "GRXWriteable.h" #import "GRXWriter.h" -// A buffered pipe is a Writeable that also acts as a Writer (to whichever other writeable is passed -// to -startWithWriteable:). +// A buffered pipe is a Writer that also acts as a Writeable. // Once it is started, whatever values are written into it (via -writeValue:) will be propagated // immediately, unless flow control prevents it. // If it is throttled and keeps receiving values, as well as if it receives values before being -// started, it will buffer them and propagate them in order as soon as its state becomes -// GRXWriterStateStarted. +// started, it will buffer them and propagate them in order as soon as its state becomes Started. // If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and // propagate the error immediately. // @@ -51,6 +49,9 @@ // pipe will keep buffering all data written to it, your application could run out of memory and // crash. If you want to react to flow control signals to prevent that, instead of using this class // you can implement an object that conforms to GRXWriter. +// +// Thread-safety: +// The methods of an object of this class should not be called concurrently from different threads. @interface GRXBufferedPipe : GRXWriter // Convenience constructor. diff --git a/src/objective-c/RxLibrary/GRXForwardingWriter.h b/src/objective-c/RxLibrary/GRXForwardingWriter.h index d004333d2b4..f310832284a 100644 --- a/src/objective-c/RxLibrary/GRXForwardingWriter.h +++ b/src/objective-c/RxLibrary/GRXForwardingWriter.h @@ -33,11 +33,17 @@ #import "GRXWriter.h" -// A "proxy" class that simply forwards values, completion, and errors from its -// input writer to its writeable. +// A "proxy" class that simply forwards values, completion, and errors from its input writer to its +// writeable. // It is useful as a superclass for pipes that act as a transformation of their // input writer, and for classes that represent objects with input and // output sequences of values, like an RPC. +// +// Thread-safety: +// All messages sent to this object need to be serialized. When it is started, the writer it wraps +// is started in the same thread. Manual state changes are propagated to the wrapped writer in the +// same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be +// serialized with any message sent to this object. @interface GRXForwardingWriter : GRXWriter - (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.h b/src/objective-c/RxLibrary/GRXImmediateWriter.h index b171f0c760a..3fcc2594342 100644 --- a/src/objective-c/RxLibrary/GRXImmediateWriter.h +++ b/src/objective-c/RxLibrary/GRXImmediateWriter.h @@ -36,10 +36,17 @@ #import "GRXWriter.h" // Utility to construct GRXWriter instances from values that are immediately available when -// required. The returned writers all support pausing and early termination. +// required. // -// Unless the writeable callback pauses them or stops them early, these writers will do all their -// interactions with the writeable before the start method returns. +// Thread-safety: +// +// An object of this class shouldn't be messaged concurrently by more than one thread. It will start +// messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the +// only place where the writer can be paused or stopped prematurely. +// +// If a paused writer of this class is resumed, it will start messaging the writeable, in the same +// thread, before |setState:| returns. Because the object can't be legally accessed concurrently, +// that's the only place where it can be paused again (or stopped). @interface GRXImmediateWriter : GRXWriter // Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to diff --git a/src/objective-c/RxLibrary/GRXWriter.h b/src/objective-c/RxLibrary/GRXWriter.h index 5d6e1a472af..65c8806d75f 100644 --- a/src/objective-c/RxLibrary/GRXWriter.h +++ b/src/objective-c/RxLibrary/GRXWriter.h @@ -65,26 +65,27 @@ typedef NS_ENUM(NSInteger, GRXWriterState) { GRXWriterStateFinished }; -// An object that conforms to this protocol can produce, on demand, a sequence -// of values. The sequence may be produced asynchronously, and it may consist of -// any number of elements, including none or an infinite number. +// An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced +// asynchronously, and it may consist of any number of elements, including none or an infinite +// number. // -// GRXWriter is the active dual of NSEnumerator. The difference between them -// is thus whether the object plays an active or passive role during usage: A -// user of NSEnumerator pulls values off it, and passes the values to a writeable. -// A user of GRXWriter, though, just gives it a writeable, and the -// GRXWriter instance pushes values to the writeable. This makes this protocol -// suitable to represent a sequence of future values, as well as collections -// with internal iteration. +// GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the +// object plays an active or passive role during usage: A user of NSEnumerator pulls values off it, +// and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and +// the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to +// represent a sequence of future values, as well as collections with internal iteration. // -// An instance of GRXWriter can start producing values after a writeable is -// passed to it. It can also be commanded to finish the sequence immediately -// (with an optional error). Finally, it can be asked to pause, but the -// conforming instance is not required to oblige. +// An instance of GRXWriter can start producing values after a writeable is passed to it. It can +// also be commanded to finish the sequence immediately (with an optional error). Finally, it can be +// asked to pause, and resumed later. All GRXWriter objects support pausing and early termination. // -// Unless otherwise indicated by a conforming class, no messages should be sent -// concurrently to a GRXWriter. I.e., conforming classes aren't required to -// be thread-safe. +// Thread-safety: +// +// State transitions take immediate effect if the object is used from a single thread. Subclasses +// might offer stronger guarantees. +// +// Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a +// GRXWriter. I.e., conforming classes aren't required to be thread-safe. @interface GRXWriter : NSObject // This property can be used to query the current state of the writer, which @@ -110,9 +111,5 @@ typedef NS_ENUM(NSInteger, GRXWriterState) { // // This method might only be called on writers in the Started or Paused // state. -// -// TODO(jcanizales): Consider adding some guarantee about the immediacy of that -// stopping. I know I've relied on it in part of the code that uses this, but -// can't remember the details in the presence of concurrency. - (void)finishWithError:(NSError *)errorOrNil; @end From 238ad7819ffcd650692baff57d15b577503fd448 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Aug 2015 23:11:29 -0700 Subject: [PATCH 075/117] =?UTF-8?q?Eliminate=20race=20in=20GRPCCall?= =?UTF-8?q?=E2=80=99s=20operation=20of=20the=20requests=20writer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/objective-c/GRPCClient/GRPCCall.m | 35 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 5f7d74bca81..16abd0fadf1 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -74,6 +74,13 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // all. This wrapper over our actual writeable ensures thread-safety and // correct ordering. GRXConcurrentWriteable *_responseWriteable; + + // The network thread wants the requestWriter to resume (when the server is ready for more input), + // or to stop (on errors), concurrently with user threads that want to start it, pause it or stop + // it. Because a writer isn't thread-safe, we'll synchronize those operations on it. + // We don't use a dispatch queue for that purpose, because the writer can call writeValue: or + // writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to + // pause the writer immediately on writeValue:, so we need our locking to be recursive. GRXWriter *_requestWriter; // To create a retain cycle when a call is started, up until it finishes. See @@ -139,8 +146,10 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; _self = nil; // If there were still request messages coming, stop them. - _requestWriter.state = GRXWriterStateFinished; - _requestWriter = nil; + @synchronized(_requestWriter) { + _requestWriter.state = GRXWriterStateFinished; + _requestWriter = nil; + } if (errorOrNil) { [_responseWriteable cancelWithError:errorOrNil]; @@ -240,12 +249,14 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // Resume the request writer. GRPCCall *strongSelf = weakSelf; if (strongSelf) { - strongSelf->_requestWriter.state = GRXWriterStateStarted; + @synchronized(_requestWriter) { + strongSelf->_requestWriter.state = GRXWriterStateStarted; + } } }; - [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMessage alloc] - initWithMessage:message - handler:resumingHandler]] errorHandler:errorHandler]; + [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMessage alloc] initWithMessage:message + handler:resumingHandler]] + errorHandler:errorHandler]; } - (void)writeValue:(id)value { @@ -253,7 +264,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // Pause the input and only resume it when the C layer notifies us that writes // can proceed. - _requestWriter.state = GRXWriterStatePaused; + @synchronized(_requestWriter) { + _requestWriter.state = GRXWriterStatePaused; + } __weak GRPCCall *weakSelf = self; dispatch_async(_callQueue, ^{ @@ -273,7 +286,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; } - (void)writesFinishedWithError:(NSError *)errorOrNil { - _requestWriter = nil; + @synchronized(_requestWriter) { + _requestWriter = nil; + } if (errorOrNil) { [self cancel]; } else { @@ -327,7 +342,9 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; } }]; // Now that the RPC has been initiated, request writes can start. - [_requestWriter startWithWriteable:self]; + @synchronized(_requestWriter) { + [_requestWriter startWithWriteable:self]; + } } #pragma mark GRXWriter implementation From 5321d49b51e00d42af730dddeb8c85f12afeb8ea Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 Aug 2015 23:21:27 -0700 Subject: [PATCH 076/117] fixed writeOptions and added test --- src/csharp/Grpc.Core.Tests/CompressionTest.cs | 128 ++++++++++++++++++ .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + src/csharp/Grpc.Core/CallOptions.cs | 1 + src/csharp/Grpc.Core/IAsyncStreamWriter.cs | 4 - src/csharp/Grpc.Core/Internal/AsyncCall.cs | 8 +- .../Grpc.Core/Internal/AsyncCallServer.cs | 8 +- .../Grpc.Core/Internal/CallSafeHandle.cs | 30 ++-- .../Grpc.Core/Internal/ClientRequestStream.cs | 2 +- .../Internal/ServerResponseStream.cs | 4 +- src/csharp/ext/grpc_csharp_ext.c | 29 ++-- 10 files changed, 170 insertions(+), 45 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/CompressionTest.cs diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs new file mode 100644 index 00000000000..492369968e0 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs @@ -0,0 +1,128 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class CompressionTest + { + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(); + + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.Dispose(); + server.ShutdownAsync().Wait(); + } + + [TestFixtureTearDown] + public void CleanupClass() + { + GrpcEnvironment.Shutdown(); + } + + [Test] + public void WriteOptions_Unary() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); + return request; + }); + + var callOptions = new CallOptions(writeOptions: new WriteOptions(WriteFlags.NoCompress)); + Calls.BlockingUnaryCall(helper.CreateUnaryCall(callOptions), "abc"); + } + + [Test] + public async Task WriteOptions_DuplexStreaming() + { + helper.DuplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => + { + await requestStream.ToList(); + + context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); + + await context.WriteResponseHeadersAsync(new Metadata { new Metadata.Entry("ascii-header", "abcdefg") }); + + await responseStream.WriteAsync("X"); + + responseStream.WriteOptions = null; + await responseStream.WriteAsync("Y"); + + responseStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); + await responseStream.WriteAsync("Z"); + }); + + var callOptions = new CallOptions(writeOptions: new WriteOptions(WriteFlags.NoCompress)); + var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall(callOptions)); + + // check that write options from call options are propagated to request stream. + Assert.IsTrue((call.RequestStream.WriteOptions.Flags & WriteFlags.NoCompress) != 0); + + call.RequestStream.WriteOptions = new WriteOptions(); + await call.RequestStream.WriteAsync("A"); + + call.RequestStream.WriteOptions = null; + await call.RequestStream.WriteAsync("B"); + + call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); + await call.RequestStream.WriteAsync("C"); + + await call.RequestStream.CompleteAsync(); + + await call.ResponseStream.ToList(); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 4692d958a05..58fa7c645f1 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -79,6 +79,7 @@ + diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index e8d0b0647fd..a08986d77e6 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -63,6 +63,7 @@ namespace Grpc.Core // TODO(jtattermusch): allow null value of deadline? this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue; this.cancellationToken = cancellationToken; + this.writeOptions = writeOptions; } /// diff --git a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs index b554b6e2660..4e2acb9c712 100644 --- a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs +++ b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs @@ -56,10 +56,6 @@ namespace Grpc.Core /// If null, default options will be used. /// Once set, this property maintains its value across subsequent /// writes. - /// Internally, closing the stream is on client and sending - /// status from server is treated as a write, so write options - /// are also applied to these operations. - /// /// The write options. WriteOptions WriteOptions { get; set; } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index df5c07e4c49..dee31c670ea 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -165,7 +165,7 @@ namespace Grpc.Core.Internal unaryResponseTcs = new TaskCompletionSource(); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartClientStreaming(HandleUnaryResponse, metadataArray, GetWriteFlagsForCall()); + call.StartClientStreaming(HandleUnaryResponse, metadataArray); } return unaryResponseTcs.Task; @@ -211,7 +211,7 @@ namespace Grpc.Core.Internal using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { - call.StartDuplexStreaming(HandleFinished, metadataArray, GetWriteFlagsForCall()); + call.StartDuplexStreaming(HandleFinished, metadataArray); } } } @@ -239,14 +239,14 @@ namespace Grpc.Core.Internal /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendCloseFromClient(WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) + public void StartSendCloseFromClient(AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); - call.StartSendCloseFromClient(HandleHalfclosed, writeFlags); + call.StartSendCloseFromClient(HandleHalfclosed); halfcloseRequested = true; sendCompletionDelegate = completionDelegate; diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 1704b9afbf4..3710a65d6bb 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -103,7 +103,7 @@ namespace Grpc.Core.Internal /// to make things simpler. /// completionDelegate is invoked upon completion. /// - public void StartSendInitialMetadata(Metadata headers, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) + public void StartSendInitialMetadata(Metadata headers, AsyncCompletionDelegate completionDelegate) { lock (myLock) { @@ -118,7 +118,7 @@ namespace Grpc.Core.Internal using (var metadataArray = MetadataArraySafeHandle.Create(headers)) { - call.StartSendInitialMetadata(HandleSendFinished, metadataArray, writeFlags); + call.StartSendInitialMetadata(HandleSendFinished, metadataArray); } this.initialMetadataSent = true; @@ -131,7 +131,7 @@ namespace Grpc.Core.Internal /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// - public void StartSendStatusFromServer(Status status, Metadata trailers, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) + public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate completionDelegate) { lock (myLock) { @@ -140,7 +140,7 @@ namespace Grpc.Core.Internal using (var metadataArray = MetadataArraySafeHandle.Create(trailers)) { - call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, writeFlags, !initialMetadataSent); + call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, !initialMetadataSent); } halfcloseRequested = true; readingDone = true; diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 02502a6f018..1b9d0abbc4a 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -57,7 +57,7 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call, - BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call, @@ -66,7 +66,7 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, - BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, @@ -74,11 +74,11 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, - BatchContextSafeHandle ctx, WriteFlags writeFlags); + BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, - BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags, bool sendEmptyInitialMetadata); + BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, @@ -90,7 +90,7 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, - BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); + BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); @@ -121,11 +121,11 @@ namespace Grpc.Core.Internal .CheckOk(); } - public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_client_streaming(this, ctx, metadataArray, writeFlags).CheckOk(); + grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk(); } public void StartServerStreaming(BatchCompletionDelegate callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) @@ -135,11 +135,11 @@ namespace Grpc.Core.Internal grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk(); } - public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, writeFlags).CheckOk(); + grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk(); } public void StartSendMessage(BatchCompletionDelegate callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata) @@ -149,18 +149,18 @@ namespace Grpc.Core.Internal grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata).CheckOk(); } - public void StartSendCloseFromClient(BatchCompletionDelegate callback, WriteFlags writeFlags) + public void StartSendCloseFromClient(BatchCompletionDelegate callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_close_from_client(this, ctx, writeFlags).CheckOk(); + grpcsharp_call_send_close_from_client(this, ctx).CheckOk(); } - public void StartSendStatusFromServer(BatchCompletionDelegate callback, Status status, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags, bool sendEmptyInitialMetadata) + public void StartSendStatusFromServer(BatchCompletionDelegate callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, writeFlags, sendEmptyInitialMetadata).CheckOk(); + grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata).CheckOk(); } public void StartReceiveMessage(BatchCompletionDelegate callback) @@ -177,11 +177,11 @@ namespace Grpc.Core.Internal grpcsharp_call_start_serverside(this, ctx).CheckOk(); } - public void StartSendInitialMetadata(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) + public void StartSendInitialMetadata(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); - grpcsharp_call_send_initial_metadata(this, ctx, metadataArray, writeFlags).CheckOk(); + grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk(); } public void Cancel() diff --git a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs index dd7f4256c43..013f00ff6fc 100644 --- a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs +++ b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs @@ -58,7 +58,7 @@ namespace Grpc.Core.Internal public Task CompleteAsync() { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendCloseFromClient(GetWriteFlags(), taskSource.CompletionDelegate); + call.StartSendCloseFromClient(taskSource.CompletionDelegate); return taskSource.Task; } diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs index 5dcd5a72209..03e39efc024 100644 --- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs +++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs @@ -60,14 +60,14 @@ namespace Grpc.Core.Internal public Task WriteStatusAsync(Status status, Metadata trailers) { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendStatusFromServer(status, trailers, GetWriteFlags(), taskSource.CompletionDelegate); + call.StartSendStatusFromServer(status, trailers, taskSource.CompletionDelegate); return taskSource.Task; } public Task WriteResponseHeadersAsync(Metadata responseHeaders) { var taskSource = new AsyncCompletionTaskSource(); - call.StartSendInitialMetadata(responseHeaders, GetWriteFlags(), taskSource.CompletionDelegate); + call.StartSendInitialMetadata(responseHeaders, taskSource.CompletionDelegate); return taskSource.Task; } diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index cb138064e1b..5d17360d6ac 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -506,7 +506,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); @@ -514,7 +514,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, ops[1].flags = write_flags; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[2].flags = write_flags; + ops[2].flags = 0; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -542,7 +542,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(grpc_call *call, grpcsharp_batch_context *ctx, - grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { + grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[4]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -551,7 +551,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -587,7 +587,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); @@ -595,7 +595,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[1].flags = write_flags; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[2].flags = write_flags; + ops[2].flags = 0; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -619,7 +619,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(grpc_call *call, grpcsharp_batch_context *ctx, - grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { + grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[3]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -628,7 +628,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); @@ -671,11 +671,11 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(grpc_call *call, - grpcsharp_batch_context *ctx, gpr_uint32 write_flags) { + grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops[0].flags = write_flags; + ops[0].flags = 0; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } @@ -683,7 +683,7 @@ grpcsharp_call_send_close_from_client(grpc_call *call, GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code, const char *status_details, grpc_metadata_array *trailing_metadata, - gpr_uint32 write_flags, gpr_int32 send_empty_initial_metadata) { + gpr_int32 send_empty_initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[2]; size_t nops = send_empty_initial_metadata ? 2 : 1; @@ -697,7 +697,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( ctx->send_status_from_server.trailing_metadata.count; ops[0].data.send_status_from_server.trailing_metadata = ctx->send_status_from_server.trailing_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; ops[1].data.send_initial_metadata.count = 0; ops[1].data.send_initial_metadata.metadata = NULL; @@ -731,8 +731,7 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(grpc_call *call, grpcsharp_batch_context *ctx, - grpc_metadata_array *initial_metadata, - gpr_uint32 write_flags) { + grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; @@ -741,7 +740,7 @@ grpcsharp_call_send_initial_metadata(grpc_call *call, ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; - ops[0].flags = write_flags; + ops[0].flags = 0; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx); } From 410c473c2b0187ac2ae77ff5a9f4faa06a67f81e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sat, 8 Aug 2015 00:02:07 -0700 Subject: [PATCH 077/117] make intializer for metadata even nicer --- src/csharp/Grpc.Core.Tests/ClientServerTest.cs | 4 ++-- src/csharp/Grpc.Core.Tests/CompressionTest.cs | 2 +- .../Internal/MetadataArraySafeHandleTest.cs | 8 ++++---- src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs | 5 +---- src/csharp/Grpc.Core/Metadata.cs | 10 ++++++++++ 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index f56fb744a61..c5fc85b3fe7 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -190,8 +190,8 @@ namespace Grpc.Core.Tests var headers = new Metadata { - new Metadata.Entry("ascii-header", "abcdefg"), - new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }), + { "ascii-header", "abcdefg" }, + { "binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff } } }; var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC"); await call; diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs index 492369968e0..ac0c3d6b5f1 100644 --- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs +++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs @@ -94,7 +94,7 @@ namespace Grpc.Core.Tests context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); - await context.WriteResponseHeadersAsync(new Metadata { new Metadata.Entry("ascii-header", "abcdefg") }); + await context.WriteResponseHeadersAsync(new Metadata { { "ascii-header", "abcdefg" } }); await responseStream.WriteAsync("X"); diff --git a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs index 46469113c59..33534fdd3c4 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs @@ -53,8 +53,8 @@ namespace Grpc.Core.Internal.Tests { var metadata = new Metadata { - new Metadata.Entry("host", "somehost"), - new Metadata.Entry("header2", "header value"), + { "host", "somehost" }, + { "header2", "header value" }, }; var nativeMetadata = MetadataArraySafeHandle.Create(metadata); nativeMetadata.Dispose(); @@ -65,8 +65,8 @@ namespace Grpc.Core.Internal.Tests { var metadata = new Metadata { - new Metadata.Entry("host", "somehost"), - new Metadata.Entry("header2", "header value"), + { "host", "somehost" }, + { "header2", "header value" } }; var nativeMetadata = MetadataArraySafeHandle.Create(metadata); diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs index b0244885494..8925041ba47 100644 --- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs +++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs @@ -63,10 +63,7 @@ namespace Grpc.Core.Tests server.Start(); channel = helper.GetChannel(); - headers = new Metadata - { - new Metadata.Entry("ascii-header", "abcdefg"), - }; + headers = new Metadata { { "ascii-header", "abcdefg" } }; } [TearDown] diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index 6fd0a7109d6..a58dbdbc93b 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -114,6 +114,16 @@ namespace Grpc.Core entries.Add(item); } + public void Add(string key, string value) + { + Add(new Entry(key, value)); + } + + public void Add(string key, byte[] valueBytes) + { + Add(new Entry(key, valueBytes)); + } + public void Clear() { CheckWriteable(); From fd51dff8b80ac7a202265837218b1718d27f1b12 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sat, 8 Aug 2015 16:12:52 -0700 Subject: [PATCH 078/117] Clarify invalid-argument message for already-started writers --- src/objective-c/RxLibrary/GRXForwardingWriter.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/RxLibrary/GRXForwardingWriter.m b/src/objective-c/RxLibrary/GRXForwardingWriter.m index cf8be8c557e..a72be9ace2f 100644 --- a/src/objective-c/RxLibrary/GRXForwardingWriter.m +++ b/src/objective-c/RxLibrary/GRXForwardingWriter.m @@ -51,7 +51,8 @@ return nil; } if (writer.state != GRXWriterStateNotStarted) { - [NSException raise:NSInvalidArgumentException format:@"writer can't be started."]; + [NSException raise:NSInvalidArgumentException + format:@"The writer argument must not have already started."]; } if ((self = [super init])) { _writer = writer; From eb87b4653a40ee9e6226687ec3f9306c0b9a89df Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sat, 8 Aug 2015 16:16:43 -0700 Subject: [PATCH 079/117] Rename super-confusing ivar _self -> _retainSelf --- src/objective-c/GRPCClient/GRPCCall.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 16abd0fadf1..405f0335e75 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -84,8 +84,10 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; GRXWriter *_requestWriter; // To create a retain cycle when a call is started, up until it finishes. See - // |startWithWriteable:| and |finishWithError:|. - GRPCCall *_self; + // |startWithWriteable:| and |finishWithError:|. This saves users from having to retain a + // reference to the call object if all they're interested in is the handler being executed when + // the response arrives. + GRPCCall *_retainSelf; NSMutableDictionary *_requestMetadata; NSMutableDictionary *_responseMetadata; @@ -143,7 +145,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; - (void)finishWithError:(NSError *)errorOrNil { // If the call isn't retained anywhere else, it can be deallocated now. - _self = nil; + _retainSelf = nil; // If there were still request messages coming, stop them. @synchronized(_requestWriter) { @@ -355,7 +357,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // before being autoreleased). // Care is taken not to retain self strongly in any of the blocks used in this implementation, so // that the life of the instance is determined by this retain cycle. - _self = self; + _retainSelf = self; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable]; [self sendHeaders:_requestMetadata]; From 297ed7bd81ba5a8e607f278713fb0facc9475b91 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sat, 8 Aug 2015 16:29:52 -0700 Subject: [PATCH 080/117] =?UTF-8?q?Don=E2=80=99t=20set=20the=20request=20w?= =?UTF-8?q?riter=20to=20nil,=20as=20@synchr(nil)=20is=20undefined=20behavi?= =?UTF-8?q?or.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also clarify in GRXWriter.h that the writeable is released whenever the writer finishes. --- src/objective-c/GRPCClient/GRPCCall.m | 4 --- src/objective-c/RxLibrary/GRXWriter.h | 52 ++++++++++++--------------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 405f0335e75..6836d34394d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -150,7 +150,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // If there were still request messages coming, stop them. @synchronized(_requestWriter) { _requestWriter.state = GRXWriterStateFinished; - _requestWriter = nil; } if (errorOrNil) { @@ -288,9 +287,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; } - (void)writesFinishedWithError:(NSError *)errorOrNil { - @synchronized(_requestWriter) { - _requestWriter = nil; - } if (errorOrNil) { [self cancel]; } else { diff --git a/src/objective-c/RxLibrary/GRXWriter.h b/src/objective-c/RxLibrary/GRXWriter.h index 65c8806d75f..b1c994aa382 100644 --- a/src/objective-c/RxLibrary/GRXWriter.h +++ b/src/objective-c/RxLibrary/GRXWriter.h @@ -35,33 +35,28 @@ #import "GRXWriteable.h" +// States of a writer. typedef NS_ENUM(NSInteger, GRXWriterState) { - // The writer has not yet been given a writeable to which it can push its - // values. To have an writer transition to the Started state, send it a - // startWithWriteable: message. + // The writer has not yet been given a writeable to which it can push its values. To have a writer + // transition to the Started state, send it a startWithWriteable: message. // - // An writer's state cannot be manually set to this value. + // A writer's state cannot be manually set to this value. GRXWriterStateNotStarted, // The writer might push values to the writeable at any moment. GRXWriterStateStarted, - // The writer is temporarily paused, and won't send any more values to the - // writeable unless its state is set back to Started. The writer might still - // transition to the Finished state at any moment, and is allowed to send - // writesFinishedWithError: to its writeable. - // - // Not all implementations of writer have to support pausing, and thus - // trying to set an writer's state to this value might have no effect. + // The writer is temporarily paused, and won't send any more values to the writeable unless its + // state is set back to Started. The writer might still transition to the Finished state at any + // moment, and is allowed to send writesFinishedWithError: to its writeable. GRXWriterStatePaused, // The writer has released its writeable and won't interact with it anymore. // - // One seldomly wants to set an writer's state to this value, as its - // writeable isn't notified with a writesFinishedWithError: message. Instead, sending - // finishWithError: to the writer will make it notify the writeable and then - // transition to this state. + // One seldomly wants to set a writer's state to this value, as its writeable isn't notified with + // a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make + // it notify the writeable and then transition to this state. GRXWriterStateFinished }; @@ -88,28 +83,25 @@ typedef NS_ENUM(NSInteger, GRXWriterState) { // GRXWriter. I.e., conforming classes aren't required to be thread-safe. @interface GRXWriter : NSObject -// This property can be used to query the current state of the writer, which -// determines how it might currently use its writeable. Some state transitions can -// be triggered by setting this property to the corresponding value, and that's -// useful for advanced use cases like pausing an writer. For more details, -// see the documentation of the enum. +// This property can be used to query the current state of the writer, which determines how it might +// currently use its writeable. Some state transitions can be triggered by setting this property to +// the corresponding value, and that's useful for advanced use cases like pausing an writer. For +// more details, see the documentation of the enum further down. @property(nonatomic) GRXWriterState state; -// Start sending messages to the writeable. Messages may be sent before the method -// returns, or they may be sent later in the future. See GRXWriteable.h for the -// different messages a writeable can receive. +// Transition to the Started state, and start sending messages to the writeable (a reference to it +// is retained). Messages to the writeable may be sent before the method returns, or they may be +// sent later in the future. See GRXWriteable.h for the different messages a writeable can receive. // -// If this writer draws its values from an external source (e.g. from the -// filesystem or from a server), calling this method will commonly trigger side -// effects (like network connections). +// If this writer draws its values from an external source (e.g. from the filesystem or from a +// server), calling this method will commonly trigger side effects (like network connections). // // This method might only be called on writers in the NotStarted state. - (void)startWithWriteable:(id)writeable; -// Send writesFinishedWithError:errorOrNil immediately to the writeable, and don't send -// any more messages to it. +// Send writesFinishedWithError:errorOrNil to the writeable. Then release the reference to it and +// transition to the Finished state. // -// This method might only be called on writers in the Started or Paused -// state. +// This method might only be called on writers in the Started or Paused state. - (void)finishWithError:(NSError *)errorOrNil; @end From 578ab166adc49f3d8c1fccdb1f5a364e7011c8ec Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sat, 8 Aug 2015 17:11:43 -0700 Subject: [PATCH 081/117] =?UTF-8?q?Don=E2=80=99t=20retain=20self=20here!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 6836d34394d..0f4c811ce41 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -250,7 +250,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey"; // Resume the request writer. GRPCCall *strongSelf = weakSelf; if (strongSelf) { - @synchronized(_requestWriter) { + @synchronized(strongSelf->_requestWriter) { strongSelf->_requestWriter.state = GRXWriterStateStarted; } } From 392fae26d2d47f4197b0fd376ff6ea13546d6448 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sat, 8 Aug 2015 22:21:57 -0700 Subject: [PATCH 082/117] context propagation API --- src/csharp/Grpc.Core/CallOptions.cs | 24 ++- .../Grpc.Core/ContextPropagationToken.cs | 139 ++++++++++++++++++ src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + src/csharp/Grpc.Core/Internal/AsyncCall.cs | 6 +- .../Grpc.Core/Internal/CallSafeHandle.cs | 2 + .../Grpc.Core/Internal/ChannelSafeHandle.cs | 6 +- .../Grpc.Core/Internal/ServerCallHandler.cs | 3 +- src/csharp/Grpc.Core/ServerCallContext.cs | 12 +- src/csharp/ext/grpc_csharp_ext.c | 6 +- 9 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 src/csharp/Grpc.Core/ContextPropagationToken.cs diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index a08986d77e6..0d82b5a28ee 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -48,6 +48,7 @@ namespace Grpc.Core readonly DateTime deadline; readonly CancellationToken cancellationToken; readonly WriteOptions writeOptions; + readonly ContextPropagationToken propagationToken; /// /// Creates a new instance of CallOptions. @@ -56,14 +57,16 @@ namespace Grpc.Core /// Deadline for the call to finish. null means no deadline. /// Can be used to request cancellation of the call. /// Write options that will be used for this call. - public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), WriteOptions writeOptions = null) + /// Context propagation token obtained from . + public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken? cancellationToken = null, + WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null) { // TODO(jtattermusch): consider only creating metadata object once it's really needed. - this.headers = headers != null ? headers : new Metadata(); - // TODO(jtattermusch): allow null value of deadline? - this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue; - this.cancellationToken = cancellationToken; + this.headers = headers ?? new Metadata(); + this.deadline = deadline ?? (propagationToken != null ? propagationToken.Deadline : DateTime.MaxValue); + this.cancellationToken = cancellationToken ?? (propagationToken != null ? propagationToken.CancellationToken : CancellationToken.None); this.writeOptions = writeOptions; + this.propagationToken = propagationToken; } /// @@ -100,5 +103,16 @@ namespace Grpc.Core return this.writeOptions; } } + + /// + /// Token for propagating parent call context. + /// + public ContextPropagationToken PropagationToken + { + get + { + return this.propagationToken; + } + } } } diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs new file mode 100644 index 00000000000..e7659477662 --- /dev/null +++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs @@ -0,0 +1,139 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Threading; + +using Grpc.Core.Internal; +using Grpc.Core.Utils; + +namespace Grpc.Core +{ + /// + /// Token for propagating context of server side handlers to child calls. + /// In situations when a backend is making calls to another backend, + /// it makes sense to propagate properties like deadline and cancellation + /// token of the server call to the child call. + /// C core provides some other contexts (like tracing context) that + /// are not accessible to C# layer, but this token still allows propagating them. + /// + public class ContextPropagationToken + { + /// + /// Default propagation mask used by C core. + /// + const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags) 0xffff; + + /// + /// Default propagation mask used by C# - we want to propagate deadline + /// and cancellation token by our own means. + /// + internal const ContextPropagationFlags DefaultMask = DefaultCoreMask + & ~ContextPropagationFlags.Deadline & ~ContextPropagationFlags.Cancellation; + + readonly CallSafeHandle parentCall; + readonly DateTime deadline; + readonly CancellationToken cancellationToken; + readonly ContextPropagationOptions options; + + internal ContextPropagationToken(CallSafeHandle parentCall, DateTime deadline, CancellationToken cancellationToken, ContextPropagationOptions options) + { + this.parentCall = Preconditions.CheckNotNull(parentCall); + this.deadline = deadline; + this.cancellationToken = cancellationToken; + this.options = options ?? ContextPropagationOptions.Default; + } + + internal CallSafeHandle ParentCall + { + get + { + return this.parentCall; + } + } + + internal DateTime Deadline + { + get + { + return this.deadline; + } + } + + internal CancellationToken CancellationToken + { + get + { + return this.cancellationToken; + } + } + + internal ContextPropagationOptions Options + { + get + { + return this.options; + } + } + + internal bool IsPropagateDeadline + { + get { return false; } + } + + internal bool IsPropagateCancellation + { + get { return false; } + } + } + + /// + /// Options for . + /// + public class ContextPropagationOptions + { + public static readonly ContextPropagationOptions Default = new ContextPropagationOptions(); + } + + /// + /// Context propagation flags from grpc/grpc.h. + /// + [Flags] + internal enum ContextPropagationFlags + { + Deadline = 1, + CensusStatsContext = 2, + CensusTracingContext = 4, + Cancellation = 8 + } +} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 0616ed9f3ec..e535c47f550 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -117,6 +117,7 @@ + diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index dee31c670ea..0db9d2a5151 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -324,7 +324,11 @@ namespace Grpc.Core.Internal private void Initialize(CompletionQueueSafeHandle cq) { - var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, cq, + var propagationToken = details.Options.PropagationToken; + var parentCall = propagationToken != null ? propagationToken.ParentCall : CallSafeHandle.NullInstance; + + var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, + parentCall, ContextPropagationToken.DefaultMask, cq, details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline)); details.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); InitializeInternal(call); diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 1b9d0abbc4a..3cb01e29bd8 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -42,6 +42,8 @@ namespace Grpc.Core.Internal /// internal class CallSafeHandle : SafeHandleZeroIsInvalid { + public static readonly CallSafeHandle NullInstance = new CallSafeHandle(); + const uint GRPC_WRITE_BUFFER_HINT = 1; CompletionRegistry completionRegistry; diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index 7324ebdf573..7f03bf4ea56 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -47,7 +47,7 @@ namespace Grpc.Core.Internal static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] - static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); + static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); [DllImport("grpc_csharp_ext.dll")] static extern ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect); @@ -76,9 +76,9 @@ namespace Grpc.Core.Internal return grpcsharp_secure_channel_create(credentials, target, channelArgs); } - public CallSafeHandle CreateCall(CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) + public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) { - var result = grpcsharp_channel_create_call(this, cq, method, host, deadline); + var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline); result.SetCompletionRegistry(registry); return result; } diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 74af19dc019..688f9f6fec5 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -310,8 +310,7 @@ namespace Grpc.Core.Internal { DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); - return new ServerCallContext( - newRpc.Method, newRpc.Host, peer, realtimeDeadline, + return new ServerCallContext(newRpc.Call, newRpc.Method, newRpc.Host, peer, realtimeDeadline, newRpc.RequestMetadata, cancellationToken, serverResponseStream.WriteResponseHeadersAsync, serverResponseStream); } } diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 7849df9bb4b..75d81c64f3a 100644 --- a/src/csharp/Grpc.Core/ServerCallContext.cs +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -45,6 +45,7 @@ namespace Grpc.Core /// public class ServerCallContext { + private readonly CallSafeHandle callHandle; private readonly string method; private readonly string host; private readonly string peer; @@ -57,9 +58,10 @@ namespace Grpc.Core private Func writeHeadersFunc; private IHasWriteOptions writeOptionsHolder; - public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, + internal ServerCallContext(CallSafeHandle callHandle, string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, Func writeHeadersFunc, IHasWriteOptions writeOptionsHolder) { + this.callHandle = callHandle; this.method = method; this.host = host; this.peer = peer; @@ -74,6 +76,14 @@ namespace Grpc.Core { return writeHeadersFunc(responseHeaders); } + + /// + /// Creates a propagation token to be used to propagate call context to a child call. + /// + public ContextPropagationToken CreatePropagationToken(ContextPropagationOptions options = null) + { + return new ContextPropagationToken(callHandle, deadline, cancellationToken, options); + } /// Name of method called in this RPC. public string Method diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 5d17360d6ac..133b2d878ed 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -376,10 +376,12 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) { } GPR_EXPORT grpc_call *GPR_CALLTYPE -grpcsharp_channel_create_call(grpc_channel *channel, grpc_completion_queue *cq, +grpcsharp_channel_create_call(grpc_channel *channel, grpc_call *parent_call, + gpr_uint32 propagation_mask, + grpc_completion_queue *cq, const char *method, const char *host, gpr_timespec deadline) { - return grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq, + return grpc_channel_create_call(channel, parent_call, propagation_mask, cq, method, host, deadline); } From dad17243bbd42c2e0635f87143ed92ad3ecc3ea0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sat, 8 Aug 2015 23:27:04 -0700 Subject: [PATCH 083/117] added tests --- .../Grpc.Core.Tests/ContextPropagationTest.cs | 122 ++++++++++++++++++ .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + .../Grpc.Core/ContextPropagationToken.cs | 2 +- 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs new file mode 100644 index 00000000000..a7f5075874d --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs @@ -0,0 +1,122 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class ContextPropagationTest + { + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(); + + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.Dispose(); + server.ShutdownAsync().Wait(); + } + + [TestFixtureTearDown] + public void CleanupClass() + { + GrpcEnvironment.Shutdown(); + } + + [Test] + public async Task PropagateCancellation() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + // check that we didn't obtain the default cancellation token. + Assert.IsTrue(context.CancellationToken.CanBeCanceled); + return "PASS"; + }); + + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + var propagationToken = context.CreatePropagationToken(); + Assert.IsNotNull(propagationToken.ParentCall); + + var callOptions = new CallOptions(propagationToken: propagationToken); + return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); + }); + + var cts = new CancellationTokenSource(); + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token))); + await call.RequestStream.CompleteAsync(); + Assert.AreEqual("PASS", await call); + } + + [Test] + public async Task PropagateDeadline() + { + var deadline = DateTime.UtcNow.AddDays(7); + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + Assert.IsTrue(context.Deadline < deadline.AddMinutes(1)); + Assert.IsTrue(context.Deadline > deadline.AddMinutes(-1)); + return "PASS"; + }); + + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken()); + return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); + }); + + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: deadline))); + await call.RequestStream.CompleteAsync(); + Assert.AreEqual("PASS", await call); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 58fa7c645f1..97ee0454bb0 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -80,6 +80,7 @@ + diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs index e7659477662..b6ea5115a4f 100644 --- a/src/csharp/Grpc.Core/ContextPropagationToken.cs +++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs @@ -52,7 +52,7 @@ namespace Grpc.Core /// /// Default propagation mask used by C core. /// - const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags) 0xffff; + const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff; /// /// Default propagation mask used by C# - we want to propagate deadline From 4dd2509c826220dd5f89525adb6b078ea381aa1f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 01:01:33 -0700 Subject: [PATCH 084/117] added sandcastle project to generate docs --- src/csharp/Grpc.Core/IAsyncStreamReader.cs | 2 +- src/csharp/Grpc.Core/Version.cs | 2 +- src/csharp/doc/README.md | 2 + src/csharp/doc/grpc_csharp_public.shfbproj | 70 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/csharp/doc/README.md create mode 100644 src/csharp/doc/grpc_csharp_public.shfbproj diff --git a/src/csharp/Grpc.Core/IAsyncStreamReader.cs b/src/csharp/Grpc.Core/IAsyncStreamReader.cs index 371fbf27ce5..c0a0674e500 100644 --- a/src/csharp/Grpc.Core/IAsyncStreamReader.cs +++ b/src/csharp/Grpc.Core/IAsyncStreamReader.cs @@ -43,7 +43,7 @@ namespace Grpc.Core /// A stream of messages to be read. /// /// - public interface IAsyncStreamReader : IAsyncEnumerator + public interface IAsyncStreamReader : IAsyncEnumerator { // TODO(jtattermusch): consider just using IAsyncEnumerator instead of this interface. } diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs index b5cb652945f..d2a029fbb4d 100644 --- a/src/csharp/Grpc.Core/Version.cs +++ b/src/csharp/Grpc.Core/Version.cs @@ -2,4 +2,4 @@ using System.Reflection; using System.Runtime.CompilerServices; // The current version of gRPC C#. -[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".*")] +[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")] diff --git a/src/csharp/doc/README.md b/src/csharp/doc/README.md new file mode 100644 index 00000000000..585500b5cab --- /dev/null +++ b/src/csharp/doc/README.md @@ -0,0 +1,2 @@ + +SandCastle project files to generate HTML reference documentation. \ No newline at end of file diff --git a/src/csharp/doc/grpc_csharp_public.shfbproj b/src/csharp/doc/grpc_csharp_public.shfbproj new file mode 100644 index 00000000000..05c93f4a13f --- /dev/null +++ b/src/csharp/doc/grpc_csharp_public.shfbproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + 2.0 + {77e3da09-fc92-486f-a90a-99ca788e8b59} + 2015.6.5.0 + + Documentation + Documentation + Documentation + + .NET Framework 4.5 + ..\..\..\doc\ref\csharp\html + en-US + + + + OnlyWarningsAndErrors + Website + False + True + False + True + 1.0.0.0 + 2 + False + Standard + Blank + True + VS2013 + False + MemberName + gRPC C# + AboveNamespaces + Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + OnBuildSuccess + + \ No newline at end of file From 2eacf7b780a56919d5ec48afd5f1c6032450943d Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sun, 9 Aug 2015 15:18:23 -0700 Subject: [PATCH 085/117] Allow UTF8 in comments of root certificates files --- .../GRPCClient/private/GRPCSecureChannel.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m index 9b4b6768f84..0a54804bb2f 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m @@ -38,15 +38,18 @@ // Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL, // *errorPtr will be an object describing what went wrong. static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) { - NSString *certsContent = [NSString stringWithContentsOfFile:path - encoding:NSASCIIStringEncoding + // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the + // issuer). Load them as UTF8 and produce an ASCII equivalent. + NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path + encoding:NSUTF8StringEncoding error:errorPtr]; - if (!certsContent) { + NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + if (!contentInASCII.bytes) { // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return. return NULL; } - const char * asCString = [certsContent cStringUsingEncoding:NSASCIIStringEncoding]; - return grpc_ssl_credentials_create(asCString, NULL); + return grpc_ssl_credentials_create(contentInASCII.bytes, NULL); } @implementation GRPCSecureChannel From 42898cf54de2a1ad9216121c7c2c835627d6fb61 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sun, 9 Aug 2015 15:37:21 -0700 Subject: [PATCH 086/117] Add remote interop tests to the suite of tests. This would have caught the encoding problem with the default root certificates. --- src/objective-c/tests/InteropTests.h | 3 +- src/objective-c/tests/InteropTests.m | 7 +-- .../tests/InteropTestsLocalCleartext.m | 59 +++++++++++++++++++ .../tests/Tests.xcodeproj/project.pbxproj | 10 +++- 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 src/objective-c/tests/InteropTestsLocalCleartext.m diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h index 4eb97e9e06e..1045c3d1248 100644 --- a/src/objective-c/tests/InteropTests.h +++ b/src/objective-c/tests/InteropTests.h @@ -37,8 +37,7 @@ // https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md @interface InteropTests : XCTestCase -// Returns @"localhost:5050". +// Returns @"grpc-test.sandbox.google.com". // Override in a subclass to perform the same tests against a different address. -// For interop tests, use @"grpc-test.sandbox.google.com". + (NSString *)host; @end diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index b61d5674649..37e06f25eb2 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -78,20 +78,17 @@ #pragma mark Tests -static NSString * const kLocalCleartextHost = @"localhost:5050"; +static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; @implementation InteropTests { RMTTestService *_service; } + (NSString *)host { - return kLocalCleartextHost; + return kRemoteSSLHost; } - (void)setUp { - // Register test server as non-SSL. - [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost]; - _service = [[RMTTestService alloc] initWithHost:self.class.host]; } diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m new file mode 100644 index 00000000000..10bd1b0694f --- /dev/null +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -0,0 +1,59 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +// Repeat of the tests in InteropTests.m, but using SSL to communicate with the local server instead +// of cleartext. + +#import + +#import "InteropTests.h" + +static NSString * const kLocalCleartextHost = @"localhost:5050"; + +@interface InteropTestsLocalCleartext : InteropTests +@end + +@implementation InteropTestsLocalCleartext + ++ (NSString *)host { + return kLocalCleartextHost; +} + +- (void)setUp { + // Register test server as non-SSL. + [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost]; + + [super setUp]; +} + +@end diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index af98aba9c08..3a1c3d940a9 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; }; 635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; }; 635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; }; + 63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; }; 63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; }; 63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; 7D8A186224D39101F90230F6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; }; @@ -51,6 +52,7 @@ 635697CC1B14FC11007A7283 /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 635697D81B14FC11007A7283 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTests.m; sourceTree = ""; }; + 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalCleartext.m; sourceTree = ""; }; 63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = ""; }; 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = ""; }; 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = ""; }; @@ -117,14 +119,15 @@ 635697C91B14FC11007A7283 /* Tests */ = { isa = PBXGroup; children = ( - 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */, 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */, - 63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */, + 63E240CC1B6C4D3A005F3B0E /* InteropTests.h */, 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */, + 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */, + 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */, 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */, + 63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */, 635697CC1B14FC11007A7283 /* Tests.m */, 635697D71B14FC11007A7283 /* Supporting Files */, - 63E240CC1B6C4D3A005F3B0E /* InteropTests.h */, ); name = Tests; sourceTree = SOURCE_ROOT; @@ -261,6 +264,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */, 63175DFF1B1B9FAF00027841 /* LocalClearTextTests.m in Sources */, 63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */, 63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */, From 7d770488ea84f3964b999bac3ba8c019e2fa17fb Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sun, 9 Aug 2015 16:09:02 -0700 Subject: [PATCH 087/117] Fixup for 42898cf: Correct documentation. --- src/objective-c/tests/InteropTestsLocalCleartext.m | 4 ++-- src/objective-c/tests/InteropTestsLocalSSL.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m index 10bd1b0694f..2d7d3c4b2c0 100644 --- a/src/objective-c/tests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -31,8 +31,8 @@ * */ -// Repeat of the tests in InteropTests.m, but using SSL to communicate with the local server instead -// of cleartext. +// Repeat of the tests in InteropTests.m, but sending the RPCs to a local cleartext server instead +// of the remote SSL one. #import diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index 227ca79659e..f69f806dcf5 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -31,8 +31,8 @@ * */ -// Repeat of the tests in InteropTests.m, but using SSL to communicate with the local server instead -// of cleartext. +// Repeat of the tests in InteropTests.m, but sending the RPCs to a local SSL server instead of the +// remote one. #import From 83c57cbed6e4cfd01628a6ae48df980bd2d1d211 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Sun, 9 Aug 2015 16:36:49 -0700 Subject: [PATCH 088/117] Increase test timeouts to reduce flakiness. --- src/objective-c/tests/GRPCClientTests.m | 4 ++-- src/objective-c/tests/InteropTests.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index e85dd6e65cd..f23102988bd 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -114,7 +114,7 @@ static ProtoMethod *kUnaryCallMethod; [call startWithWriteable:responsesWriteable]; - [self waitForExpectationsWithTimeout:4 handler:nil]; + [self waitForExpectationsWithTimeout:8 handler:nil]; } - (void)testSimpleProtoRPC { @@ -146,7 +146,7 @@ static ProtoMethod *kUnaryCallMethod; [call startWithWriteable:responsesWriteable]; - [self waitForExpectationsWithTimeout:4 handler:nil]; + [self waitForExpectationsWithTimeout:8 handler:nil]; } - (void)testMetadata { diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 37e06f25eb2..1b63fe2059c 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -128,7 +128,7 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; [expectation fulfill]; }]; - [self waitForExpectationsWithTimeout:8 handler:nil]; + [self waitForExpectationsWithTimeout:16 handler:nil]; } - (void)testClientStreamingRPC { From c5a6aca397e9dd8eb0e080eb343577089f2cb6c0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 23:41:17 -0700 Subject: [PATCH 089/117] expose C core version string to C# --- src/csharp/Grpc.Core/GrpcEnvironment.cs | 12 ++++++++++++ src/csharp/ext/grpc_csharp_ext.c | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 034a66be3c5..29a6ea78724 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -53,6 +53,9 @@ namespace Grpc.Core [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_shutdown(); + [DllImport("grpc_csharp_ext.dll")] + static extern IntPtr grpcsharp_version_string(); // returns not-owned const char* + static object staticLock = new object(); static GrpcEnvironment instance; @@ -163,6 +166,15 @@ namespace Grpc.Core } } + /// + /// Gets version of gRPC C core. + /// + internal string GetCoreVersionString() + { + var ptr = grpcsharp_version_string(); // the pointer is not owned + return Marshal.PtrToStringAnsi(ptr); + } + /// /// Shuts down this environment. /// diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 048887bc12a..0d2a74adb6c 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -849,6 +849,11 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) { typedef void(GPR_CALLTYPE *test_callback_funcptr)(gpr_int32 success); +/* Version info */ +GPR_EXPORT char *GPR_CALLTYPE grpcsharp_version_string() { + return grpc_version_string(); +} + /* For testing */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_test_callback(test_callback_funcptr callback) { From 37b9ec1f631ac5f22ad2125961adf9241248bcc0 Mon Sep 17 00:00:00 2001 From: vjpai Date: Mon, 10 Aug 2015 10:02:09 -0700 Subject: [PATCH 090/117] Added invocation of ./config - thanks to @dangunter --- INSTALL | 1 + 1 file changed, 1 insertion(+) diff --git a/INSTALL b/INSTALL index 8a0a98ad2ef..808166dfede 100644 --- a/INSTALL +++ b/INSTALL @@ -132,6 +132,7 @@ We will also need to make openssl and install it appropriately $ cd $ cd third_party/openssl + $ ./config $ sudo make install $ cd ../../ From 481b016e2e4a90875230952d5b95ccdd2538962e Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 10 Aug 2015 10:44:45 -0700 Subject: [PATCH 091/117] resolve offline comments --- doc/health-checking.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/doc/health-checking.md b/doc/health-checking.md index 106c00922bf..fb6566577c3 100644 --- a/doc/health-checking.md +++ b/doc/health-checking.md @@ -3,14 +3,15 @@ GRPC Health Checking Protocol Health checks are used to probe whether the server is able to handle rpcs. The client-to-server health checking can happen from point to point or via some -load balancing mechanism. A server may choose to reply “unhealthy” because it -has not been ready to take requests, it is shutting down or some other reason. +control system. A server may choose to reply “unhealthy” because it +is not ready to take requests, it is shutting down or some other reason. The client can act accordingly if the response is not received within some time window or the response says unhealthy in it. A GRPC service is used as the health checking mechanism for both simple -client-to-server scenario and other systems such as load-balancing. Being a high +client-to-server scenario and other control systems such as load-balancing. +Being a high level service provides some benefits. Firstly, since it is a GRPC service itself, doing a health check is in the same format as a normal rpc. Secondly, it has rich semantics such as per-service health status. Thirdly, as a GRPC @@ -28,8 +29,7 @@ syntax = "proto3"; package grpc.health.v1alpha; message HealthCheckRequest { - string host = 1; - string service = 2; + string service = 1; } message HealthCheckResponse { @@ -47,25 +47,22 @@ service Health { ``` A client can query the server’s health status by calling the `Check` method, and -a deadline should be set on the rpc. The client can optionally set the host -string. The client can optionally set the service name it wants to query for -health status. The suggested format of service name is -`grpc.health.v1alpha.Health`. +a deadline should be set on the rpc. The client can optionally set the service +name it wants to query for health status. The suggested format of service name +is `package_names.ServiceName`, such as `grpc.health.v1alpha.Health`. -The server should register all the services for all the hosts manually and set +The server should register all the services manually and set the individual status, including an empty service name and its status. For each -request received, if the (host, service_name) pair can be found in the registry, +request received, if the service name can be found in the registry, a response must be sent back with an `OK` status and the status field should be set to `SERVING` or `NOT_SERVING` accordingly. If the service name is not registered, the server returns a `NOT_FOUND` GRPC status. -It is recommended that the server use an empty string as the default host string -and create a (“”, “”) pair as the key for server’s health status as a whole. The -server can just do exact matching of the (host, service_name) pair and does not -support any kind of wildcard matching. However, the service owner has the -freedom to implement more complicated matching semantics that both the client -and server agree upon. - +It is recommended that the server use an empty string as the key for server’s +health status as a whole. The server can just do exact matching of the +service name support any kind of wildcard matching. However, the service owner +has the freedom to implement more complicated matching semantics that both the +client and server agree upon. A client can declare the server as unhealthy if the rpc is not finished after some amount of time. The client should be able to handle the case where server From 03ad9510cee313148e0f942e23bc202f956fda6d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 Aug 2015 11:06:58 -0700 Subject: [PATCH 092/117] add const modifier --- src/csharp/ext/grpc_csharp_ext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 0d2a74adb6c..0eb236590ce 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -850,7 +850,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) { typedef void(GPR_CALLTYPE *test_callback_funcptr)(gpr_int32 success); /* Version info */ -GPR_EXPORT char *GPR_CALLTYPE grpcsharp_version_string() { +GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_version_string() { return grpc_version_string(); } From 1338798897378d8d05ab2a4633f25bcd63cfdc87 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 Aug 2015 11:13:28 -0700 Subject: [PATCH 093/117] fix method signature and add test --- src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs | 8 ++++++++ src/csharp/Grpc.Core/GrpcEnvironment.cs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs index 9ae12776f3c..4ed93c7eca2 100644 --- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs +++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs @@ -69,5 +69,13 @@ namespace Grpc.Core.Tests Assert.IsFalse(object.ReferenceEquals(env1, env2)); } + + [Test] + public void GetCoreVersionString() + { + var coreVersion = GrpcEnvironment.GetCoreVersionString(); + var parts = coreVersion.Split('.'); + Assert.AreEqual(4, parts.Length); + } } } diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 29a6ea78724..1bb83c9962d 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -169,7 +169,7 @@ namespace Grpc.Core /// /// Gets version of gRPC C core. /// - internal string GetCoreVersionString() + internal static string GetCoreVersionString() { var ptr = grpcsharp_version_string(); // the pointer is not owned return Marshal.PtrToStringAnsi(ptr); From ffc8a6b4318fdf14516b4b0a816e118131c2f209 Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 10 Aug 2015 12:26:39 -0700 Subject: [PATCH 094/117] move auth property iterator declaration into auth_context.h --- BUILD | 2 - Makefile | 2 - build.json | 1 - include/grpc++/auth_context.h | 32 +++++++- include/grpc++/auth_property_iterator.h | 77 ------------------- src/cpp/common/auth_property_iterator.cc | 2 +- tools/doxygen/Doxyfile.c++ | 1 - tools/doxygen/Doxyfile.c++.internal | 1 - tools/run_tests/sources_and_headers.json | 4 - vsprojects/grpc++/grpc++.vcxproj | 1 - vsprojects/grpc++/grpc++.vcxproj.filters | 3 - .../grpc++_unsecure/grpc++_unsecure.vcxproj | 1 - .../grpc++_unsecure.vcxproj.filters | 3 - 13 files changed, 32 insertions(+), 98 deletions(-) delete mode 100644 include/grpc++/auth_property_iterator.h diff --git a/BUILD b/BUILD index dcabd648e4c..9eaabbbccdb 100644 --- a/BUILD +++ b/BUILD @@ -690,7 +690,6 @@ cc_library( "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", @@ -778,7 +777,6 @@ cc_library( "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", diff --git a/Makefile b/Makefile index 181194f78f0..5cdc46241e1 100644 --- a/Makefile +++ b/Makefile @@ -4484,7 +4484,6 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/async_generic_service.h \ include/grpc++/async_unary_call.h \ include/grpc++/auth_context.h \ - include/grpc++/auth_property_iterator.h \ include/grpc++/byte_buffer.h \ include/grpc++/channel_arguments.h \ include/grpc++/channel_interface.h \ @@ -4728,7 +4727,6 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/async_generic_service.h \ include/grpc++/async_unary_call.h \ include/grpc++/auth_context.h \ - include/grpc++/auth_property_iterator.h \ include/grpc++/byte_buffer.h \ include/grpc++/channel_arguments.h \ include/grpc++/channel_interface.h \ diff --git a/build.json b/build.json index 515cecdc5a7..252694a6630 100644 --- a/build.json +++ b/build.json @@ -33,7 +33,6 @@ "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", diff --git a/include/grpc++/auth_context.h b/include/grpc++/auth_context.h index c42105b927c..f8ea8ad6f4f 100644 --- a/include/grpc++/auth_context.h +++ b/include/grpc++/auth_context.h @@ -34,12 +34,42 @@ #ifndef GRPCXX_AUTH_CONTEXT_H #define GRPCXX_AUTH_CONTEXT_H +#include #include -#include #include +struct grpc_auth_context; +struct grpc_auth_property; +struct grpc_auth_property_iterator; + namespace grpc { +class SecureAuthContext; + +typedef std::pair AuthProperty; + +class AuthPropertyIterator + : public std::iterator { + public: + ~AuthPropertyIterator(); + AuthPropertyIterator& operator++(); + AuthPropertyIterator operator++(int); + bool operator==(const AuthPropertyIterator& rhs) const; + bool operator!=(const AuthPropertyIterator& rhs) const; + const AuthProperty operator*(); + + protected: + AuthPropertyIterator(); + AuthPropertyIterator(const grpc_auth_property* property, + const grpc_auth_property_iterator* iter); + private: + friend class SecureAuthContext; + const grpc_auth_property* property_; + // The following items form a grpc_auth_property_iterator. + const grpc_auth_context* ctx_; + size_t index_; + const char* name_; +}; class AuthContext { public: diff --git a/include/grpc++/auth_property_iterator.h b/include/grpc++/auth_property_iterator.h deleted file mode 100644 index c7870c46be1..00000000000 --- a/include/grpc++/auth_property_iterator.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPCXX_AUTH_PROPERTY_ITERATOR_H -#define GRPCXX_AUTH_PROPERTY_ITERATOR_H - -#include -#include - -#include - -struct grpc_auth_context; -struct grpc_auth_property; -struct grpc_auth_property_iterator; - -namespace grpc { -class SecureAuthContext; - -typedef std::pair AuthProperty; - -class AuthPropertyIterator - : public std::iterator { - public: - ~AuthPropertyIterator(); - AuthPropertyIterator& operator++(); - AuthPropertyIterator operator++(int); - bool operator==(const AuthPropertyIterator& rhs) const; - bool operator!=(const AuthPropertyIterator& rhs) const; - const AuthProperty operator*(); - - protected: - AuthPropertyIterator(); - AuthPropertyIterator(const grpc_auth_property* property, - const grpc_auth_property_iterator* iter); - private: - friend class SecureAuthContext; - const grpc_auth_property* property_; - // The following items form a grpc_auth_property_iterator. - const grpc_auth_context* ctx_; - size_t index_; - const char* name_; -}; - -} // namespace grpc - - #endif // GRPCXX_AUTH_PROPERTY_ITERATOR_H - diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc index e706c6c921d..ba889835158 100644 --- a/src/cpp/common/auth_property_iterator.cc +++ b/src/cpp/common/auth_property_iterator.cc @@ -31,7 +31,7 @@ * */ -#include +#include #include diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index eb14925fff2..374125ad19a 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -763,7 +763,6 @@ WARN_LOGFILE = INPUT = include/grpc++/async_generic_service.h \ include/grpc++/async_unary_call.h \ include/grpc++/auth_context.h \ -include/grpc++/auth_property_iterator.h \ include/grpc++/byte_buffer.h \ include/grpc++/channel_arguments.h \ include/grpc++/channel_interface.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 3d6649bef6d..c7f8e292bd3 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -763,7 +763,6 @@ WARN_LOGFILE = INPUT = include/grpc++/async_generic_service.h \ include/grpc++/async_unary_call.h \ include/grpc++/auth_context.h \ -include/grpc++/auth_property_iterator.h \ include/grpc++/byte_buffer.h \ include/grpc++/channel_arguments.h \ include/grpc++/channel_interface.h \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 5d23bf9e88f..d2c3ec3add9 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -13051,7 +13051,6 @@ "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", @@ -13102,7 +13101,6 @@ "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", @@ -13227,7 +13225,6 @@ "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", @@ -13275,7 +13272,6 @@ "include/grpc++/async_generic_service.h", "include/grpc++/async_unary_call.h", "include/grpc++/auth_context.h", - "include/grpc++/auth_property_iterator.h", "include/grpc++/byte_buffer.h", "include/grpc++/channel_arguments.h", "include/grpc++/channel_interface.h", diff --git a/vsprojects/grpc++/grpc++.vcxproj b/vsprojects/grpc++/grpc++.vcxproj index 58474511fc4..929bc1500ea 100644 --- a/vsprojects/grpc++/grpc++.vcxproj +++ b/vsprojects/grpc++/grpc++.vcxproj @@ -216,7 +216,6 @@ - diff --git a/vsprojects/grpc++/grpc++.vcxproj.filters b/vsprojects/grpc++/grpc++.vcxproj.filters index 2a8ee08b084..0408fb46a5c 100644 --- a/vsprojects/grpc++/grpc++.vcxproj.filters +++ b/vsprojects/grpc++/grpc++.vcxproj.filters @@ -105,9 +105,6 @@ include\grpc++ - - include\grpc++ - include\grpc++ diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj index 0d989c4a933..2ff252e04e7 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj @@ -216,7 +216,6 @@ - diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters index 71d42e5c6dd..b4fae7741ce 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters @@ -90,9 +90,6 @@ include\grpc++ - - include\grpc++ - include\grpc++ From f8b4b98669861115c8a9f662eb09a49de5fc74a4 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Mon, 10 Aug 2015 12:55:58 -0700 Subject: [PATCH 095/117] Improving unprotect doc. --- src/core/tsi/transport_security_interface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h index 936b0c25b0a..e27e6b9fc92 100644 --- a/src/core/tsi/transport_security_interface.h +++ b/src/core/tsi/transport_security_interface.h @@ -158,6 +158,8 @@ tsi_result tsi_frame_protector_protect_flush( value is expected to be at most max_protected_frame_size minus overhead which means that max_protected_frame_size is a safe bet. The output value is the number of bytes actually written. + If *unprotected_bytes_size is unchanged, there may be more data remaining + to unprotect, and the caller should call this function again. - This method returns TSI_OK in case of success. Success includes cases where there is not enough data to output a frame in which case From e71a6b094ba62a40e2c6fb8f5781c8accf07548a Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 10 Aug 2015 15:48:34 -0700 Subject: [PATCH 096/117] call grpc_init for defaultcredentials --- src/cpp/client/secure_credentials.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 2d6114e06b8..68c72c62178 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -34,6 +34,7 @@ #include #include +#include #include "src/cpp/client/channel.h" #include "src/cpp/client/secure_credentials.h" @@ -61,6 +62,7 @@ std::shared_ptr WrapCredentials(grpc_credentials* creds) { } // namespace std::shared_ptr GoogleDefaultCredentials() { + GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_google_default_credentials_create()); } From 9adf796d0687303f8e39b04f1235d6ef46849f73 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Thu, 6 Aug 2015 11:30:07 -0700 Subject: [PATCH 097/117] Implement timeout interop test for Python --- .../grpc_interop/_interop_test_case.py | 3 +++ .../grpcio_test/grpc_interop/methods.py | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/python/grpcio_test/grpc_interop/_interop_test_case.py b/src/python/grpcio_test/grpc_interop/_interop_test_case.py index ed8f7ef0099..b6d06b300dc 100644 --- a/src/python/grpcio_test/grpc_interop/_interop_test_case.py +++ b/src/python/grpcio_test/grpc_interop/_interop_test_case.py @@ -59,3 +59,6 @@ class InteropTestCase(object): def testCancelAfterFirstResponse(self): methods.TestCase.CANCEL_AFTER_FIRST_RESPONSE.test_interoperability(self.stub, None) + + def testTimeoutOnSleepingServer(self): + methods.TestCase.TIMEOUT_ON_SLEEPING_SERVER.test_interoperability(self.stub, None) diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio_test/grpc_interop/methods.py index f4c94685eea..7a831f3cbd2 100644 --- a/src/python/grpcio_test/grpc_interop/methods.py +++ b/src/python/grpcio_test/grpc_interop/methods.py @@ -33,10 +33,12 @@ import enum import json import os import threading +import time from oauth2client import client as oauth2client_client from grpc.framework.alpha import utilities +from grpc.framework.alpha import exceptions from grpc_interop import empty_pb2 from grpc_interop import messages_pb2 @@ -318,6 +320,24 @@ def _cancel_after_first_response(stub): raise ValueError('expected call to be cancelled') +def _timeout_on_sleeping_server(stub): + request_payload_size = 27182 + with stub, _Pipe() as pipe: + response_iterator = stub.FullDuplexCall(pipe, 0.001) + + request = messages_pb2.StreamingOutputCallRequest( + response_type=messages_pb2.COMPRESSABLE, + payload=messages_pb2.Payload(body=b'\x00' * request_payload_size)) + pipe.add(request) + time.sleep(0.1) + try: + next(response_iterator) + except exceptions.ExpirationError: + pass + else: + raise ValueError('expected call to exceed deadline') + + def _compute_engine_creds(stub, args): response = _large_unary_common_behavior(stub, True, True) if args.default_service_account != response.username: @@ -351,6 +371,7 @@ class TestCase(enum.Enum): CANCEL_AFTER_FIRST_RESPONSE = 'cancel_after_first_response' COMPUTE_ENGINE_CREDS = 'compute_engine_creds' SERVICE_ACCOUNT_CREDS = 'service_account_creds' + TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server' def test_interoperability(self, stub, args): if self is TestCase.EMPTY_UNARY: @@ -367,6 +388,8 @@ class TestCase(enum.Enum): _cancel_after_begin(stub) elif self is TestCase.CANCEL_AFTER_FIRST_RESPONSE: _cancel_after_first_response(stub) + elif self is TestCase.TIMEOUT_ON_SLEEPING_SERVER: + _timeout_on_sleeping_server(stub) elif self is TestCase.COMPUTE_ENGINE_CREDS: _compute_engine_creds(stub, args) elif self is TestCase.SERVICE_ACCOUNT_CREDS: From 9fc755f46520a4c351119728b67f9dd59ab3f20c Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 10 Aug 2015 16:39:08 -0700 Subject: [PATCH 098/117] Add to all secure credentials --- src/cpp/client/secure_credentials.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 68c72c62178..6cd6b77fcf5 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -69,6 +69,7 @@ std::shared_ptr GoogleDefaultCredentials() { // Builds SSL Credentials given SSL specific options std::shared_ptr SslCredentials( const SslCredentialsOptions& options) { + GrpcLibrary init; // To call grpc_init(). grpc_ssl_pem_key_cert_pair pem_key_cert_pair = { options.pem_private_key.c_str(), options.pem_cert_chain.c_str()}; @@ -80,6 +81,7 @@ std::shared_ptr SslCredentials( // Builds credentials for use when running in GCE std::shared_ptr ComputeEngineCredentials() { + GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_compute_engine_credentials_create()); } @@ -87,6 +89,7 @@ std::shared_ptr ComputeEngineCredentials() { std::shared_ptr ServiceAccountCredentials( const grpc::string& json_key, const grpc::string& scope, long token_lifetime_seconds) { + GrpcLibrary init; // To call grpc_init(). if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create ServiceAccountCredentials " @@ -102,6 +105,7 @@ std::shared_ptr ServiceAccountCredentials( // Builds JWT credentials. std::shared_ptr ServiceAccountJWTAccessCredentials( const grpc::string& json_key, long token_lifetime_seconds) { + GrpcLibrary init; // To call grpc_init(). if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create JWTCredentials with non-positive lifetime"); @@ -116,6 +120,7 @@ std::shared_ptr ServiceAccountJWTAccessCredentials( // Builds refresh token credentials. std::shared_ptr RefreshTokenCredentials( const grpc::string& json_refresh_token) { + GrpcLibrary init; // To call grpc_init(). return WrapCredentials( grpc_refresh_token_credentials_create(json_refresh_token.c_str())); } @@ -123,6 +128,7 @@ std::shared_ptr RefreshTokenCredentials( // Builds access token credentials. std::shared_ptr AccessTokenCredentials( const grpc::string& access_token) { + GrpcLibrary init; // To call grpc_init(). return WrapCredentials( grpc_access_token_credentials_create(access_token.c_str())); } @@ -131,6 +137,7 @@ std::shared_ptr AccessTokenCredentials( std::shared_ptr IAMCredentials( const grpc::string& authorization_token, const grpc::string& authority_selector) { + GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_iam_credentials_create( authorization_token.c_str(), authority_selector.c_str())); } From 39a9ec8954ccd13367918c615f9efd9a5aaf3b9f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 15:37:23 -0700 Subject: [PATCH 099/117] fix preconditions class --- .../Grpc.Core.Tests/ChannelOptionsTest.cs | 6 ++--- src/csharp/Grpc.Core.Tests/ChannelTest.cs | 2 +- src/csharp/Grpc.Core/CallInvocationDetails.cs | 10 ++++---- src/csharp/Grpc.Core/Channel.cs | 2 +- src/csharp/Grpc.Core/ChannelOptions.cs | 6 ++--- src/csharp/Grpc.Core/GrpcEnvironment.cs | 2 +- src/csharp/Grpc.Core/Internal/Timespec.cs | 2 +- src/csharp/Grpc.Core/KeyCertificatePair.cs | 4 +-- src/csharp/Grpc.Core/Marshaller.cs | 4 +-- src/csharp/Grpc.Core/Metadata.cs | 8 +++--- src/csharp/Grpc.Core/Method.cs | 10 ++++---- src/csharp/Grpc.Core/Server.cs | 2 +- src/csharp/Grpc.Core/ServerCredentials.cs | 2 +- src/csharp/Grpc.Core/ServerPort.cs | 4 +-- src/csharp/Grpc.Core/Utils/Preconditions.cs | 25 +++++++++---------- .../HealthServiceImplTest.cs | 8 +++--- 16 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs index df09857efe3..52be77c8466 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs @@ -67,9 +67,9 @@ namespace Grpc.Core.Internal.Tests [Test] public void ConstructorPreconditions() { - Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, "abc"); }); - Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, 1); }); - Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption("abc", null); }); + Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, "abc"); }); + Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, 1); }); + Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption("abc", null); }); } [Test] diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs index 60b45176e56..90f6e570c4c 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs @@ -50,7 +50,7 @@ namespace Grpc.Core.Tests [Test] public void Constructor_RejectsInvalidParams() { - Assert.Throws(typeof(NullReferenceException), () => new Channel(null, Credentials.Insecure)); + Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure)); } [Test] diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs index eb23a3a209b..cca78aca0ff 100644 --- a/src/csharp/Grpc.Core/CallInvocationDetails.cs +++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs @@ -56,12 +56,12 @@ namespace Grpc.Core public CallInvocationDetails(Channel channel, string method, string host, Marshaller requestMarshaller, Marshaller responseMarshaller, CallOptions options) { - this.channel = Preconditions.CheckNotNull(channel); - this.method = Preconditions.CheckNotNull(method); + this.channel = Preconditions.CheckNotNull(channel, "channel"); + this.method = Preconditions.CheckNotNull(method, "method"); this.host = host; - this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); - this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); - this.options = Preconditions.CheckNotNull(options); + this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); + this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); + this.options = Preconditions.CheckNotNull(options, "options"); } public Channel Channel diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 9273ea4582c..f8cbe08466c 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -63,7 +63,7 @@ namespace Grpc.Core /// Channel options. public Channel(string host, Credentials credentials, IEnumerable options = null) { - Preconditions.CheckNotNull(host); + Preconditions.CheckNotNull(host, "host"); this.environment = GrpcEnvironment.GetInstance(); this.options = options != null ? new List(options) : new List(); diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs index 1e0f90287a0..0cb2953f2c2 100644 --- a/src/csharp/Grpc.Core/ChannelOptions.cs +++ b/src/csharp/Grpc.Core/ChannelOptions.cs @@ -63,8 +63,8 @@ namespace Grpc.Core public ChannelOption(string name, string stringValue) { this.type = OptionType.String; - this.name = Preconditions.CheckNotNull(name); - this.stringValue = Preconditions.CheckNotNull(stringValue); + this.name = Preconditions.CheckNotNull(name, "name"); + this.stringValue = Preconditions.CheckNotNull(stringValue, "stringValue"); } /// @@ -75,7 +75,7 @@ namespace Grpc.Core public ChannelOption(string name, int intValue) { this.type = OptionType.Integer; - this.name = Preconditions.CheckNotNull(name); + this.name = Preconditions.CheckNotNull(name, "name"); this.intValue = intValue; } diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 1bb83c9962d..a93819564e6 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -115,7 +115,7 @@ namespace Grpc.Core /// public static void SetLogger(ILogger customLogger) { - Preconditions.CheckNotNull(customLogger); + Preconditions.CheckNotNull(customLogger, "customLogger"); logger = customLogger; } diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index e83d21f4a4a..daf85d5f61d 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -211,7 +211,7 @@ namespace Grpc.Core.Internal return Timespec.InfPast; } - Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime"); + Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime needs of kind DateTimeKind.Utc or be equal to DateTime.MaxValue or DateTime.MinValue."); try { diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs index 5def15a656b..6f691975e99 100644 --- a/src/csharp/Grpc.Core/KeyCertificatePair.cs +++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs @@ -54,8 +54,8 @@ namespace Grpc.Core /// PEM encoded private key. public KeyCertificatePair(string certificateChain, string privateKey) { - this.certificateChain = Preconditions.CheckNotNull(certificateChain); - this.privateKey = Preconditions.CheckNotNull(privateKey); + this.certificateChain = Preconditions.CheckNotNull(certificateChain, "certificateChain"); + this.privateKey = Preconditions.CheckNotNull(privateKey, "privateKey"); } /// diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs index 8b1a9290741..8e78b9a2029 100644 --- a/src/csharp/Grpc.Core/Marshaller.cs +++ b/src/csharp/Grpc.Core/Marshaller.cs @@ -46,8 +46,8 @@ namespace Grpc.Core public Marshaller(Func serializer, Func deserializer) { - this.serializer = Preconditions.CheckNotNull(serializer); - this.deserializer = Preconditions.CheckNotNull(deserializer); + this.serializer = Preconditions.CheckNotNull(serializer, "serializer"); + this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer"); } public Func Serializer diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index a58dbdbc93b..9db2abf46ef 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -186,15 +186,15 @@ namespace Grpc.Core public Entry(string key, byte[] valueBytes) { - this.key = Preconditions.CheckNotNull(key); + this.key = Preconditions.CheckNotNull(key, "key"); this.value = null; - this.valueBytes = Preconditions.CheckNotNull(valueBytes); + this.valueBytes = Preconditions.CheckNotNull(valueBytes, "valueBytes"); } public Entry(string key, string value) { - this.key = Preconditions.CheckNotNull(key); - this.value = Preconditions.CheckNotNull(value); + this.key = Preconditions.CheckNotNull(key, "key"); + this.value = Preconditions.CheckNotNull(value, "value"); this.valueBytes = null; } diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs index cc047ac9f8f..23004446bcf 100644 --- a/src/csharp/Grpc.Core/Method.cs +++ b/src/csharp/Grpc.Core/Method.cs @@ -62,10 +62,10 @@ namespace Grpc.Core public Method(MethodType type, string serviceName, string name, Marshaller requestMarshaller, Marshaller responseMarshaller) { this.type = type; - this.serviceName = Preconditions.CheckNotNull(serviceName); - this.name = Preconditions.CheckNotNull(name); - this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); - this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); + this.serviceName = Preconditions.CheckNotNull(serviceName, "serviceName"); + this.name = Preconditions.CheckNotNull(name, "name"); + this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); + this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); this.fullName = GetFullName(serviceName); } @@ -122,7 +122,7 @@ namespace Grpc.Core /// internal string GetFullName(string serviceName) { - return "/" + Preconditions.CheckNotNull(serviceName) + "/" + this.Name; + return "/" + Preconditions.CheckNotNull(serviceName, "serviceName") + "/" + this.Name; } } } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index eb5b043d1c5..c76f126026f 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -192,7 +192,7 @@ namespace Grpc.Core { lock (myLock) { - Preconditions.CheckNotNull(serverPort.Credentials); + Preconditions.CheckNotNull(serverPort.Credentials, "serverPort"); Preconditions.CheckState(!startRequested); var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port); int boundPort; diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index c11a1ede085..3c6703d30e5 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -91,7 +91,7 @@ namespace Grpc.Core { this.keyCertificatePairs = new List(keyCertificatePairs).AsReadOnly(); Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, - "At least one KeyCertificatePair needs to be provided"); + "At least one KeyCertificatePair needs to be provided."); if (forceClientAuth) { Preconditions.CheckNotNull(rootCertificates, diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs index 55e4bd00621..598404d0459 100644 --- a/src/csharp/Grpc.Core/ServerPort.cs +++ b/src/csharp/Grpc.Core/ServerPort.cs @@ -62,9 +62,9 @@ namespace Grpc.Core /// credentials to use to secure this port. public ServerPort(string host, int port, ServerCredentials credentials) { - this.host = Preconditions.CheckNotNull(host); + this.host = Preconditions.CheckNotNull(host, "host"); this.port = port; - this.credentials = Preconditions.CheckNotNull(credentials); + this.credentials = Preconditions.CheckNotNull(credentials, "credentials"); } /// diff --git a/src/csharp/Grpc.Core/Utils/Preconditions.cs b/src/csharp/Grpc.Core/Utils/Preconditions.cs index aeb5d210a79..374262f87ad 100644 --- a/src/csharp/Grpc.Core/Utils/Preconditions.cs +++ b/src/csharp/Grpc.Core/Utils/Preconditions.cs @@ -32,17 +32,16 @@ #endregion using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading.Tasks; namespace Grpc.Core.Utils { + /// + /// Utility methods to simplify checking preconditions in the code. + /// public static class Preconditions { /// - /// Throws ArgumentException if condition is false. + /// Throws if condition is false. /// public static void CheckArgument(bool condition) { @@ -53,7 +52,7 @@ namespace Grpc.Core.Utils } /// - /// Throws ArgumentException with given message if condition is false. + /// Throws with given message if condition is false. /// public static void CheckArgument(bool condition, string errorMessage) { @@ -64,31 +63,31 @@ namespace Grpc.Core.Utils } /// - /// Throws NullReferenceException if reference is null. + /// Throws if reference is null. /// public static T CheckNotNull(T reference) { if (reference == null) { - throw new NullReferenceException(); + throw new ArgumentNullException(); } return reference; } /// - /// Throws NullReferenceException with given message if reference is null. + /// Throws if reference is null. /// - public static T CheckNotNull(T reference, string errorMessage) + public static T CheckNotNull(T reference, string paramName) { if (reference == null) { - throw new NullReferenceException(errorMessage); + throw new ArgumentNullException(paramName); } return reference; } /// - /// Throws InvalidOperationException if condition is false. + /// Throws if condition is false. /// public static void CheckState(bool condition) { @@ -99,7 +98,7 @@ namespace Grpc.Core.Utils } /// - /// Throws InvalidOperationException with given message if condition is false. + /// Throws with given message if condition is false. /// public static void CheckState(bool condition, string errorMessage) { diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs index 71844156556..c4caa3b57aa 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs @@ -92,11 +92,11 @@ namespace Grpc.HealthCheck.Tests public void NullsRejected() { var impl = new HealthServiceImpl(); - Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING)); - Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING)); + Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING)); + Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING)); - Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, "")); - Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null)); + Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, "")); + Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null)); } private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service) From f22abfbf1a179c8fa803c2fc9d3498380fda2f8c Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 16:15:34 -0700 Subject: [PATCH 100/117] rename async extension methods for clarity --- src/csharp/Grpc.Core.Tests/ClientServerTest.cs | 6 +++--- src/csharp/Grpc.Core.Tests/CompressionTest.cs | 4 ++-- src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs | 2 +- src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs | 9 ++++----- .../Grpc.Examples.Tests/MathClientServerTests.cs | 10 +++++----- src/csharp/Grpc.Examples/MathExamples.cs | 10 +++++----- src/csharp/Grpc.Examples/MathServiceImpl.cs | 7 ++----- src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 6 +++--- src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs | 4 ++-- 9 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index c5fc85b3fe7..e49fdb5268c 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -138,7 +138,7 @@ namespace Grpc.Core.Tests helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { string result = ""; - await requestStream.ForEach(async (request) => + await requestStream.ForEachAsync(async (request) => { result += request; }); @@ -147,7 +147,7 @@ namespace Grpc.Core.Tests }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); - await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); + await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" }); Assert.AreEqual("ABC", await call.ResponseAsync); } @@ -159,7 +159,7 @@ namespace Grpc.Core.Tests helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { barrier.SetResult(null); - await requestStream.ToList(); + await requestStream.ToListAsync(); return ""; }); diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs index ac0c3d6b5f1..9547683f60f 100644 --- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs +++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs @@ -90,7 +90,7 @@ namespace Grpc.Core.Tests { helper.DuplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => { - await requestStream.ToList(); + await requestStream.ToListAsync(); context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); @@ -122,7 +122,7 @@ namespace Grpc.Core.Tests await call.RequestStream.CompleteAsync(); - await call.ResponseStream.ToList(); + await call.ResponseStream.ToListAsync(); } } } diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs index 8925041ba47..e32f98862f8 100644 --- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs +++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs @@ -129,7 +129,7 @@ namespace Grpc.Core.Tests }); var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); - var responses = await call.ResponseStream.ToList(); + var responses = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new[] { "A", "B" }, responses); } } diff --git a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs index 8a748b45a81..cdf1e510261 100644 --- a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs +++ b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs @@ -33,7 +33,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace Grpc.Core.Utils @@ -46,7 +45,7 @@ namespace Grpc.Core.Utils /// /// Reads the entire stream and executes an async action for each element. /// - public static async Task ForEach(this IAsyncStreamReader streamReader, Func asyncAction) + public static async Task ForEachAsync(this IAsyncStreamReader streamReader, Func asyncAction) where T : class { while (await streamReader.MoveNext()) @@ -58,7 +57,7 @@ namespace Grpc.Core.Utils /// /// Reads the entire stream and creates a list containing all the elements read. /// - public static async Task> ToList(this IAsyncStreamReader streamReader) + public static async Task> ToListAsync(this IAsyncStreamReader streamReader) where T : class { var result = new List(); @@ -73,7 +72,7 @@ namespace Grpc.Core.Utils /// Writes all elements from given enumerable to the stream. /// Completes the stream afterwards unless close = false. /// - public static async Task WriteAll(this IClientStreamWriter streamWriter, IEnumerable elements, bool complete = true) + public static async Task WriteAllAsync(this IClientStreamWriter streamWriter, IEnumerable elements, bool complete = true) where T : class { foreach (var element in elements) @@ -89,7 +88,7 @@ namespace Grpc.Core.Utils /// /// Writes all elements from given enumerable to the stream. /// - public static async Task WriteAll(this IServerStreamWriter streamWriter, IEnumerable elements) + public static async Task WriteAllAsync(this IServerStreamWriter streamWriter, IEnumerable elements) where T : class { foreach (var element in elements) diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 73d2a1ca9bb..fdef950f09d 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -109,7 +109,7 @@ namespace math.Tests { using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) { - var responses = await call.ResponseStream.ToList(); + var responses = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new List { 1, 1, 2, 3, 5, 8 }, responses.ConvertAll((n) => n.Num_)); } @@ -151,7 +151,7 @@ namespace math.Tests using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), deadline: DateTime.UtcNow.AddMilliseconds(500))) { - var ex = Assert.Throws(async () => await call.ResponseStream.ToList()); + var ex = Assert.Throws(async () => await call.ResponseStream.ToListAsync()); // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); @@ -167,7 +167,7 @@ namespace math.Tests var numbers = new List { 10, 20, 30 }.ConvertAll( n => Num.CreateBuilder().SetNum_(n).Build()); - await call.RequestStream.WriteAll(numbers); + await call.RequestStream.WriteAllAsync(numbers); var result = await call.ResponseAsync; Assert.AreEqual(60, result.Num_); } @@ -185,8 +185,8 @@ namespace math.Tests using (var call = client.DivMany()) { - await call.RequestStream.WriteAll(divArgsList); - var result = await call.ResponseStream.ToList(); + await call.RequestStream.WriteAllAsync(divArgsList); + var result = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs index 06d81a4d83d..dc1bf439950 100644 --- a/src/csharp/Grpc.Examples/MathExamples.cs +++ b/src/csharp/Grpc.Examples/MathExamples.cs @@ -54,7 +54,7 @@ namespace math { using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build())) { - List result = await call.ResponseStream.ToList(); + List result = await call.ResponseStream.ToListAsync(); Console.WriteLine("Fib Result: " + string.Join("|", result)); } } @@ -70,7 +70,7 @@ namespace math using (var call = client.Sum()) { - await call.RequestStream.WriteAll(numbers); + await call.RequestStream.WriteAllAsync(numbers); Console.WriteLine("Sum Result: " + await call.ResponseAsync); } } @@ -85,8 +85,8 @@ namespace math }; using (var call = client.DivMany()) { - await call.RequestStream.WriteAll(divArgsList); - Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList())); + await call.RequestStream.WriteAllAsync(divArgsList); + Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToListAsync())); } } @@ -102,7 +102,7 @@ namespace math Num sum; using (var sumCall = client.Sum()) { - await sumCall.RequestStream.WriteAll(numbers); + await sumCall.RequestStream.WriteAllAsync(numbers); sum = await sumCall.ResponseAsync; } diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index dd26b1d3501..7b2684615c6 100644 --- a/src/csharp/Grpc.Examples/MathServiceImpl.cs +++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs @@ -75,7 +75,7 @@ namespace math public async Task Sum(IAsyncStreamReader requestStream, ServerCallContext context) { long sum = 0; - await requestStream.ForEach(async num => + await requestStream.ForEachAsync(async num => { sum += num.Num_; }); @@ -84,10 +84,7 @@ namespace math public async Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { - await requestStream.ForEach(async divArgs => - { - await responseStream.WriteAsync(DivInternal(divArgs)); - }); + await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs))); } static DivReply DivInternal(DivArgs args) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 6802de489dc..c918f60127a 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -215,7 +215,7 @@ namespace Grpc.IntegrationTesting using (var call = client.StreamingInputCall()) { - await call.RequestStream.WriteAll(bodySizes); + await call.RequestStream.WriteAllAsync(bodySizes); var response = await call.ResponseAsync; Assert.AreEqual(74922, response.AggregatedPayloadSize); @@ -237,7 +237,7 @@ namespace Grpc.IntegrationTesting using (var call = client.StreamingOutputCall(request)) { - var responseList = await call.ResponseStream.ToList(); + var responseList = await call.ResponseStream.ToListAsync(); foreach (var res in responseList) { Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); @@ -303,7 +303,7 @@ namespace Grpc.IntegrationTesting { await call.RequestStream.CompleteAsync(); - var responseList = await call.ResponseStream.ToList(); + var responseList = await call.ResponseStream.ToListAsync(); Assert.AreEqual(0, responseList.Count); } Console.WriteLine("Passed!"); diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs index ccf9fe6ced6..ceebd5dd8c1 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs @@ -71,7 +71,7 @@ namespace grpc.testing public async Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context) { int sum = 0; - await requestStream.ForEach(async request => + await requestStream.ForEachAsync(async request => { sum += request.Payload.Body.Length; }); @@ -80,7 +80,7 @@ namespace grpc.testing public async Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { - await requestStream.ForEach(async request => + await requestStream.ForEachAsync(async request => { foreach (var responseParam in request.ResponseParametersList) { From 3e941977f51a8b585551a49228ad1193e443d6d8 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 16:21:24 -0700 Subject: [PATCH 101/117] get rid of unnecessary ExceptionHelper --- src/csharp/Grpc.Core/Grpc.Core.csproj | 1 - src/csharp/Grpc.Core/Internal/AsyncCall.cs | 12 +--- src/csharp/Grpc.Core/Utils/ExceptionHelper.cs | 57 ------------------- 3 files changed, 3 insertions(+), 67 deletions(-) delete mode 100644 src/csharp/Grpc.Core/Utils/ExceptionHelper.cs diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index e535c47f550..9a8195e9d09 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -77,7 +77,6 @@ - diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 0db9d2a5151..6aeca29d964 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -109,15 +109,9 @@ namespace Grpc.Core.Internal } } - try - { - // Once the blocking call returns, the result should be available synchronously. - return unaryResponseTcs.Task.Result; - } - catch (AggregateException ae) - { - throw ExceptionHelper.UnwrapRpcException(ae); - } + // Once the blocking call returns, the result should be available synchronously. + // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException. + return unaryResponseTcs.Task.GetAwaiter().GetResult(); } } diff --git a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs deleted file mode 100644 index c4d6bee0580..00000000000 --- a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs +++ /dev/null @@ -1,57 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; - -namespace Grpc.Core.Utils -{ - public static class ExceptionHelper - { - /// - /// If inner exceptions contain RpcException, rethrows it. - /// Otherwise, rethrows the original aggregate exception. - /// Always throws, the exception return type is here only to make the. - /// - public static Exception UnwrapRpcException(AggregateException ae) - { - foreach (var e in ae.InnerExceptions) - { - if (e is RpcException) - { - throw e; - } - } - throw ae; - } - } -} From 66eb18dcc7495cc17621447389a9164362b0fcfe Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 9 Aug 2015 20:03:24 -0700 Subject: [PATCH 102/117] fixing doc comments --- src/csharp/Grpc.Core/Calls.cs | 2 - src/csharp/Grpc.Core/GrpcEnvironment.cs | 18 -- src/csharp/Grpc.Core/Logging/ConsoleLogger.cs | 13 +- src/csharp/Grpc.Core/Logging/ILogger.cs | 6 + src/csharp/Grpc.Core/Marshaller.cs | 19 ++- src/csharp/Grpc.Core/Method.cs | 52 +++++- src/csharp/Grpc.Core/RpcException.cs | 14 +- src/csharp/Grpc.Core/ServerMethods.cs | 4 - .../Grpc.Core/ServerServiceDefinition.cs | 8 +- src/csharp/Grpc.Core/Status.cs | 13 +- src/csharp/Grpc.Core/StatusCode.cs | 156 +++++++++--------- src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs | 3 + src/csharp/Grpc.Core/Version.cs | 34 +++- src/csharp/Grpc.Core/VersionInfo.cs | 37 ++++- 14 files changed, 254 insertions(+), 125 deletions(-) diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index 00a8cabf82a..b9128c914d5 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -31,8 +31,6 @@ #endregion -using System; -using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index a93819564e6..30d8c802355 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -192,23 +192,5 @@ namespace Grpc.Core Logger.Info("gRPC shutdown."); } - - /// - /// Shuts down this environment asynchronously. - /// - private Task CloseAsync() - { - return Task.Run(() => - { - try - { - Close(); - } - catch (Exception e) - { - Logger.Error(e, "Error occured while shutting down GrpcEnvironment."); - } - }); - } } } diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs index c67765c78d5..382481d8716 100644 --- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs +++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs @@ -42,16 +42,21 @@ namespace Grpc.Core.Logging readonly Type forType; readonly string forTypeString; + /// Creates a console logger not associated to any specific type. public ConsoleLogger() : this(null) { } + /// Creates a console logger that logs messsage specific for given type. private ConsoleLogger(Type forType) { this.forType = forType; this.forTypeString = forType != null ? forType.FullName + " " : ""; } - + + /// + /// Returns a logger associated with the specified type. + /// public ILogger ForType() { if (typeof(T) == forType) @@ -61,31 +66,37 @@ namespace Grpc.Core.Logging return new ConsoleLogger(typeof(T)); } + /// Logs a message with severity Debug. public void Debug(string message, params object[] formatArgs) { Log("D", message, formatArgs); } + /// Logs a message with severity Info. public void Info(string message, params object[] formatArgs) { Log("I", message, formatArgs); } + /// Logs a message with severity Warning. public void Warning(string message, params object[] formatArgs) { Log("W", message, formatArgs); } + /// Logs a message and an associated exception with severity Warning. public void Warning(Exception exception, string message, params object[] formatArgs) { Log("W", message + " " + exception, formatArgs); } + /// Logs a message with severity Error. public void Error(string message, params object[] formatArgs) { Log("E", message, formatArgs); } + /// Logs a message and an associated exception with severity Error. public void Error(Exception exception, string message, params object[] formatArgs) { Log("E", message + " " + exception, formatArgs); diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs index 0d58f133e3a..61e0c91388b 100644 --- a/src/csharp/Grpc.Core/Logging/ILogger.cs +++ b/src/csharp/Grpc.Core/Logging/ILogger.cs @@ -42,16 +42,22 @@ namespace Grpc.Core.Logging /// Returns a logger associated with the specified type. ILogger ForType(); + /// Logs a message with severity Debug. void Debug(string message, params object[] formatArgs); + /// Logs a message with severity Info. void Info(string message, params object[] formatArgs); + /// Logs a message with severity Warning. void Warning(string message, params object[] formatArgs); + /// Logs a message and an associated exception with severity Warning. void Warning(Exception exception, string message, params object[] formatArgs); + /// Logs a message with severity Error. void Error(string message, params object[] formatArgs); + /// Logs a message and an associated exception with severity Error. void Error(Exception exception, string message, params object[] formatArgs); } } diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs index 8e78b9a2029..f38cb0863ff 100644 --- a/src/csharp/Grpc.Core/Marshaller.cs +++ b/src/csharp/Grpc.Core/Marshaller.cs @@ -37,19 +37,27 @@ using Grpc.Core.Utils; namespace Grpc.Core { /// - /// For serializing and deserializing messages. + /// Encapsulates the logic for serializing and deserializing messages. /// public struct Marshaller { readonly Func serializer; readonly Func deserializer; + /// + /// Initializes a new marshaller. + /// + /// Function that will be used to serialize messages. + /// Function that will be used to deserialize messages. public Marshaller(Func serializer, Func deserializer) { this.serializer = Preconditions.CheckNotNull(serializer, "serializer"); this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer"); } + /// + /// Gets the serializer function. + /// public Func Serializer { get @@ -58,6 +66,9 @@ namespace Grpc.Core } } + /// + /// Gets the deserializer function. + /// public Func Deserializer { get @@ -72,11 +83,17 @@ namespace Grpc.Core /// public static class Marshallers { + /// + /// Creates a marshaller from specified serializer and deserializer. + /// public static Marshaller Create(Func serializer, Func deserializer) { return new Marshaller(serializer, deserializer); } + /// + /// Returns a marshaller for string type. This is useful for testing. + /// public static Marshaller StringMarshaller { get diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs index 23004446bcf..4c208b4a263 100644 --- a/src/csharp/Grpc.Core/Method.cs +++ b/src/csharp/Grpc.Core/Method.cs @@ -41,14 +41,21 @@ namespace Grpc.Core /// public enum MethodType { - Unary, // Unary request, unary response. - ClientStreaming, // Streaming request, unary response. - ServerStreaming, // Unary request, streaming response. - DuplexStreaming // Streaming request, streaming response. + /// Single request sent from client, single response received from server. + Unary, + + /// Stream of request sent from client, single response received from server. + ClientStreaming, + + /// Single request sent from client, stream of responses received from server. + ServerStreaming, + + /// Both server and client can stream arbitrary number of requests and responses simultaneously. + DuplexStreaming } /// - /// A description of a service method. + /// A description of a remote method. /// public class Method { @@ -59,6 +66,14 @@ namespace Grpc.Core readonly Marshaller responseMarshaller; readonly string fullName; + /// + /// Initializes a new instance of the Method class. + /// + /// Type of method. + /// Name of service this method belongs to. + /// Unqualified name of the method. + /// Marshaller used for request messages. + /// Marshaller used for response messages. public Method(MethodType type, string serviceName, string name, Marshaller requestMarshaller, Marshaller responseMarshaller) { this.type = type; @@ -66,9 +81,12 @@ namespace Grpc.Core this.name = Preconditions.CheckNotNull(name, "name"); this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); - this.fullName = GetFullName(serviceName); + this.fullName = GetFullName(serviceName, name); } + /// + /// Gets the type of the method. + /// public MethodType Type { get @@ -77,6 +95,9 @@ namespace Grpc.Core } } + /// + /// Gets the name of the service to which this method belongs. + /// public string ServiceName { get @@ -85,6 +106,9 @@ namespace Grpc.Core } } + /// + /// Gets the unqualified name of the method. + /// public string Name { get @@ -93,6 +117,9 @@ namespace Grpc.Core } } + /// + /// Gets the marshaller used for request messages. + /// public Marshaller RequestMarshaller { get @@ -101,6 +128,9 @@ namespace Grpc.Core } } + /// + /// Gets the marshaller used for response messages. + /// public Marshaller ResponseMarshaller { get @@ -108,7 +138,11 @@ namespace Grpc.Core return this.responseMarshaller; } } - + + /// + /// Gets the fully qualified name of the method. On the server side, methods are dispatched + /// based on this name. + /// public string FullName { get @@ -120,9 +154,9 @@ namespace Grpc.Core /// /// Gets full name of the method including the service name. /// - internal string GetFullName(string serviceName) + internal static string GetFullName(string serviceName, string methodName) { - return "/" + Preconditions.CheckNotNull(serviceName, "serviceName") + "/" + this.Name; + return "/" + serviceName + "/" + methodName; } } } diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs index c58578286b3..cac417e6261 100644 --- a/src/csharp/Grpc.Core/RpcException.cs +++ b/src/csharp/Grpc.Core/RpcException.cs @@ -36,22 +36,34 @@ using System; namespace Grpc.Core { /// - /// Thrown when remote procedure call fails. + /// Thrown when remote procedure call fails. Every RpcException is associated with a resulting of the call. /// public class RpcException : Exception { private readonly Status status; + /// + /// Creates a new RpcException associated with given status. + /// + /// Resulting status of a call. public RpcException(Status status) : base(status.ToString()) { this.status = status; } + /// + /// Creates a new RpcException associated with given status and message. + /// + /// Resulting status of a call. + /// The exception message. public RpcException(Status status, string message) : base(message) { this.status = status; } + /// + /// Resulting status of the call. + /// public Status Status { get diff --git a/src/csharp/Grpc.Core/ServerMethods.cs b/src/csharp/Grpc.Core/ServerMethods.cs index d4577702037..1f119a80ffe 100644 --- a/src/csharp/Grpc.Core/ServerMethods.cs +++ b/src/csharp/Grpc.Core/ServerMethods.cs @@ -31,12 +31,8 @@ #endregion -using System; -using System.Threading; using System.Threading.Tasks; -using Grpc.Core.Internal; - namespace Grpc.Core { /// diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs index a00d156e527..94b0a320c30 100644 --- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs +++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs @@ -79,7 +79,7 @@ namespace Grpc.Core where TRequest : class where TResponse : class { - callHandlers.Add(method.GetFullName(serviceName), ServerCalls.UnaryCall(method, handler)); + callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler)); return this; } @@ -89,7 +89,7 @@ namespace Grpc.Core where TRequest : class where TResponse : class { - callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ClientStreamingCall(method, handler)); + callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler)); return this; } @@ -99,7 +99,7 @@ namespace Grpc.Core where TRequest : class where TResponse : class { - callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ServerStreamingCall(method, handler)); + callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler)); return this; } @@ -109,7 +109,7 @@ namespace Grpc.Core where TRequest : class where TResponse : class { - callHandlers.Add(method.GetFullName(serviceName), ServerCalls.DuplexStreamingCall(method, handler)); + callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler)); return this; } diff --git a/src/csharp/Grpc.Core/Status.cs b/src/csharp/Grpc.Core/Status.cs index 754f6cb3cab..6bd8dc820be 100644 --- a/src/csharp/Grpc.Core/Status.cs +++ b/src/csharp/Grpc.Core/Status.cs @@ -29,13 +29,12 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; -using System.Runtime.InteropServices; +using Grpc.Core.Utils; namespace Grpc.Core { /// - /// Represents RPC result. + /// Represents RPC result, which consists of and an optional detail string. /// public struct Status { @@ -52,6 +51,11 @@ namespace Grpc.Core readonly StatusCode statusCode; readonly string detail; + /// + /// Creates a new instance of Status. + /// + /// Status code. + /// Detail. public Status(StatusCode statusCode, string detail) { this.statusCode = statusCode; @@ -80,6 +84,9 @@ namespace Grpc.Core } } + /// + /// Returns a that represents the current . + /// public override string ToString() { return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail); diff --git a/src/csharp/Grpc.Core/StatusCode.cs b/src/csharp/Grpc.Core/StatusCode.cs index a9696fa4690..90606955afb 100644 --- a/src/csharp/Grpc.Core/StatusCode.cs +++ b/src/csharp/Grpc.Core/StatusCode.cs @@ -31,8 +31,6 @@ #endregion -using System; - namespace Grpc.Core { /// @@ -41,101 +39,101 @@ namespace Grpc.Core /// public enum StatusCode { - /* Not an error; returned on success */ + /// Not an error; returned on success. OK = 0, - /* The operation was cancelled (typically by the caller). */ + + /// The operation was cancelled (typically by the caller). Cancelled = 1, - /* Unknown error. An example of where this error may be returned is - if a Status value received from another address space belongs to - an error-space that is not known in this address space. Also - errors raised by APIs that do not return enough error information - may be converted to this error. */ + + /// + /// Unknown error. An example of where this error may be returned is + /// if a Status value received from another address space belongs to + /// an error-space that is not known in this address space. Also + /// errors raised by APIs that do not return enough error information + /// may be converted to this error. + /// Unknown = 2, - /* Client specified an invalid argument. Note that this differs - from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments - that are problematic regardless of the state of the system - (e.g., a malformed file name). */ + + /// + /// Client specified an invalid argument. Note that this differs + /// from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments + /// that are problematic regardless of the state of the system + /// (e.g., a malformed file name). + /// InvalidArgument = 3, - /* Deadline expired before operation could complete. For operations - that change the state of the system, this error may be returned - even if the operation has completed successfully. For example, a - successful response from a server could have been delayed long - enough for the deadline to expire. */ + + /// + /// Deadline expired before operation could complete. For operations + /// that change the state of the system, this error may be returned + /// even if the operation has completed successfully. For example, a + /// successful response from a server could have been delayed long + /// enough for the deadline to expire. + /// DeadlineExceeded = 4, - /* Some requested entity (e.g., file or directory) was not found. */ + + /// Some requested entity (e.g., file or directory) was not found. NotFound = 5, - /* Some entity that we attempted to create (e.g., file or directory) - already exists. */ + + /// Some entity that we attempted to create (e.g., file or directory) already exists. AlreadyExists = 6, - /* The caller does not have permission to execute the specified - operation. PERMISSION_DENIED must not be used for rejections - caused by exhausting some resource (use RESOURCE_EXHAUSTED - instead for those errors). PERMISSION_DENIED must not be - used if the caller can not be identified (use UNAUTHENTICATED - instead for those errors). */ + + /// + /// The caller does not have permission to execute the specified + /// operation. PERMISSION_DENIED must not be used for rejections + /// caused by exhausting some resource (use RESOURCE_EXHAUSTED + /// instead for those errors). PERMISSION_DENIED must not be + /// used if the caller can not be identified (use UNAUTHENTICATED + /// instead for those errors). + /// PermissionDenied = 7, - /* The request does not have valid authentication credentials for the - operation. */ + + /// The request does not have valid authentication credentials for the operation. Unauthenticated = 16, - /* Some resource has been exhausted, perhaps a per-user quota, or - perhaps the entire file system is out of space. */ + + /// + /// Some resource has been exhausted, perhaps a per-user quota, or + /// perhaps the entire file system is out of space. + /// ResourceExhausted = 8, - /* Operation was rejected because the system is not in a state - required for the operation's execution. For example, directory - to be deleted may be non-empty, an rmdir operation is applied to - a non-directory, etc. - - A litmus test that may help a service implementor in deciding - between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: - (a) Use UNAVAILABLE if the client can retry just the failing call. - (b) Use ABORTED if the client should retry at a higher-level - (e.g., restarting a read-modify-write sequence). - (c) Use FAILED_PRECONDITION if the client should not retry until - the system state has been explicitly fixed. E.g., if an "rmdir" - fails because the directory is non-empty, FAILED_PRECONDITION - should be returned since the client should not retry unless - they have first fixed up the directory by deleting files from it. - (d) Use FAILED_PRECONDITION if the client performs conditional - REST Get/Update/Delete on a resource and the resource on the - server does not match the condition. E.g., conflicting - read-modify-write on the same resource. */ + + /// + /// Operation was rejected because the system is not in a state + /// required for the operation's execution. For example, directory + /// to be deleted may be non-empty, an rmdir operation is applied to + /// a non-directory, etc. + /// FailedPrecondition = 9, - /* The operation was aborted, typically due to a concurrency issue - like sequencer check failures, transaction aborts, etc. - See litmus test above for deciding between FAILED_PRECONDITION, - ABORTED, and UNAVAILABLE. */ + /// + /// The operation was aborted, typically due to a concurrency issue + /// like sequencer check failures, transaction aborts, etc. + /// Aborted = 10, - /* Operation was attempted past the valid range. E.g., seeking or - reading past end of file. - - Unlike INVALID_ARGUMENT, this error indicates a problem that may - be fixed if the system state changes. For example, a 32-bit file - system will generate INVALID_ARGUMENT if asked to read at an - offset that is not in the range [0,2^32-1], but it will generate - OUT_OF_RANGE if asked to read from an offset past the current - file size. - - There is a fair bit of overlap between FAILED_PRECONDITION and - OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific - error) when it applies so that callers who are iterating through - a space can easily look for an OUT_OF_RANGE error to detect when - they are done. */ + + /// + /// Operation was attempted past the valid range. E.g., seeking or + /// reading past end of file. + /// OutOfRange = 11, - /* Operation is not implemented or not supported/enabled in this service. */ + + /// Operation is not implemented or not supported/enabled in this service. Unimplemented = 12, - /* Internal errors. Means some invariants expected by underlying - system has been broken. If you see one of these errors, - something is very broken. */ + + /// + /// Internal errors. Means some invariants expected by underlying + /// system has been broken. If you see one of these errors, + /// something is very broken. + /// Internal = 13, - /* The service is currently unavailable. This is a most likely a - transient condition and may be corrected by retrying with - a backoff. - See litmus test above for deciding between FAILED_PRECONDITION, - ABORTED, and UNAVAILABLE. */ + /// + /// The service is currently unavailable. This is a most likely a + /// transient condition and may be corrected by retrying with + /// a backoff. + /// Unavailable = 14, - /* Unrecoverable data loss or corruption. */ + + /// Unrecoverable data loss or corruption. DataLoss = 15 } } diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs index 82653c3a1f5..eb3a5b16e3c 100644 --- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs +++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs @@ -39,6 +39,9 @@ using System.Threading.Tasks; namespace Grpc.Core.Utils { + /// + /// Utility methods to run microbenchmarks. + /// public static class BenchmarkUtil { /// diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs index d2a029fbb4d..d02b301cac7 100644 --- a/src/csharp/Grpc.Core/Version.cs +++ b/src/csharp/Grpc.Core/Version.cs @@ -1,5 +1,37 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + using System.Reflection; -using System.Runtime.CompilerServices; // The current version of gRPC C#. [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")] diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 939372e2370..b6dbd3b49c0 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -1,8 +1,41 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion namespace Grpc.Core { + /// + /// Provides info about current version of gRPC. + /// public static class VersionInfo { /// From 2527967e365a1315bbbe3218d9f5723f6b8d4251 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 Aug 2015 10:57:31 -0700 Subject: [PATCH 103/117] fix test --- src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs index e32f98862f8..981b8ea3c8e 100644 --- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs +++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs @@ -84,7 +84,7 @@ namespace Grpc.Core.Tests { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { - Assert.Throws(typeof(NullReferenceException), async () => await context.WriteResponseHeadersAsync(null)); + Assert.Throws(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null)); return "PASS"; }); From 9698b5b29f84707ca590c2f618c8f5d00a921da7 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 Aug 2015 16:40:19 -0700 Subject: [PATCH 104/117] polishing CallOptions --- .../Grpc.Core.Tests/ContextPropagationTest.cs | 31 +++++++ .../Grpc.Core.Tests/MockServiceHelper.cs | 12 +-- src/csharp/Grpc.Core/CallInvocationDetails.cs | 24 +++++- src/csharp/Grpc.Core/CallOptions.cs | 86 ++++++++++++++++--- src/csharp/Grpc.Core/ClientBase.cs | 18 +++- .../Grpc.Core/ContextPropagationToken.cs | 58 ++++++++++--- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 7 +- 7 files changed, 193 insertions(+), 43 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs index a7f5075874d..db5f953b0e1 100644 --- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs +++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs @@ -110,6 +110,14 @@ namespace Grpc.Core.Tests helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { + Assert.Throws(typeof(ArgumentException), () => + { + // Trying to override deadline while propagating deadline from parent call will throw. + Calls.BlockingUnaryCall(helper.CreateUnaryCall( + new CallOptions(deadline: DateTime.UtcNow.AddDays(8), + propagationToken: context.CreatePropagationToken())), ""); + }); + var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken()); return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); }); @@ -118,5 +126,28 @@ namespace Grpc.Core.Tests await call.RequestStream.CompleteAsync(); Assert.AreEqual("PASS", await call); } + + [Test] + public async Task SuppressDeadlinePropagation() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + Assert.AreEqual(DateTime.MaxValue, context.Deadline); + return "PASS"; + }); + + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + Assert.IsTrue(context.CancellationToken.CanBeCanceled); + + var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken(new ContextPropagationOptions(propagateDeadline: false))); + return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); + }); + + var cts = new CancellationTokenSource(); + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddDays(7)))); + await call.RequestStream.CompleteAsync(); + Assert.AreEqual("PASS", await call); + } } } diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs index b642286b116..bb69648d8bf 100644 --- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -153,27 +153,23 @@ namespace Grpc.Core.Tests return channel; } - public CallInvocationDetails CreateUnaryCall(CallOptions options = null) + public CallInvocationDetails CreateUnaryCall(CallOptions options = default(CallOptions)) { - options = options ?? new CallOptions(); return new CallInvocationDetails(channel, UnaryMethod, options); } - public CallInvocationDetails CreateClientStreamingCall(CallOptions options = null) + public CallInvocationDetails CreateClientStreamingCall(CallOptions options = default(CallOptions)) { - options = options ?? new CallOptions(); return new CallInvocationDetails(channel, ClientStreamingMethod, options); } - public CallInvocationDetails CreateServerStreamingCall(CallOptions options = null) + public CallInvocationDetails CreateServerStreamingCall(CallOptions options = default(CallOptions)) { - options = options ?? new CallOptions(); return new CallInvocationDetails(channel, ServerStreamingMethod, options); } - public CallInvocationDetails CreateDuplexStreamingCall(CallOptions options = null) + public CallInvocationDetails CreateDuplexStreamingCall(CallOptions options = default(CallOptions)) { - options = options ?? new CallOptions(); return new CallInvocationDetails(channel, DuplexStreamingMethod, options); } diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs index cca78aca0ff..8959baf306b 100644 --- a/src/csharp/Grpc.Core/CallInvocationDetails.cs +++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs @@ -40,17 +40,22 @@ namespace Grpc.Core /// /// Details about a client-side call to be invoked. /// - public class CallInvocationDetails + public struct CallInvocationDetails { readonly Channel channel; readonly string method; readonly string host; readonly Marshaller requestMarshaller; readonly Marshaller responseMarshaller; - readonly CallOptions options; + CallOptions options; public CallInvocationDetails(Channel channel, Method method, CallOptions options) : - this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options) + this(channel, method, null, options) + { + } + + public CallInvocationDetails(Channel channel, Method method, string host, CallOptions options) : + this(channel, method.FullName, host, method.RequestMarshaller, method.ResponseMarshaller, options) { } @@ -61,7 +66,7 @@ namespace Grpc.Core this.host = host; this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); - this.options = Preconditions.CheckNotNull(options, "options"); + this.options = options; } public Channel Channel @@ -111,5 +116,16 @@ namespace Grpc.Core return options; } } + + /// + /// Returns new instance of with + /// Options set to the value provided. Values of all other fields are preserved. + /// + public CallInvocationDetails WithOptions(CallOptions options) + { + var newDetails = this; + newDetails.options = options; + return newDetails; + } } } diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index 0d82b5a28ee..3dfe80b48ce 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -42,29 +42,28 @@ namespace Grpc.Core /// /// Options for calls made by client. /// - public class CallOptions + public struct CallOptions { - readonly Metadata headers; - readonly DateTime deadline; - readonly CancellationToken cancellationToken; - readonly WriteOptions writeOptions; - readonly ContextPropagationToken propagationToken; + Metadata headers; + DateTime? deadline; + CancellationToken cancellationToken; + WriteOptions writeOptions; + ContextPropagationToken propagationToken; /// - /// Creates a new instance of CallOptions. + /// Creates a new instance of CallOptions struct. /// /// Headers to be sent with the call. /// Deadline for the call to finish. null means no deadline. /// Can be used to request cancellation of the call. /// Write options that will be used for this call. /// Context propagation token obtained from . - public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken? cancellationToken = null, + public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null) { - // TODO(jtattermusch): consider only creating metadata object once it's really needed. - this.headers = headers ?? new Metadata(); - this.deadline = deadline ?? (propagationToken != null ? propagationToken.Deadline : DateTime.MaxValue); - this.cancellationToken = cancellationToken ?? (propagationToken != null ? propagationToken.CancellationToken : CancellationToken.None); + this.headers = headers; + this.deadline = deadline; + this.cancellationToken = cancellationToken; this.writeOptions = writeOptions; this.propagationToken = propagationToken; } @@ -80,7 +79,7 @@ namespace Grpc.Core /// /// Call deadline. /// - public DateTime Deadline + public DateTime? Deadline { get { return deadline; } } @@ -114,5 +113,66 @@ namespace Grpc.Core return this.propagationToken; } } + + /// + /// Returns new instance of with + /// Headers set to the value provided. Values of all other fields are preserved. + /// + public CallOptions WithHeaders(Metadata headers) + { + var newOptions = this; + newOptions.headers = headers; + return newOptions; + } + + /// + /// Returns new instance of with + /// Deadline set to the value provided. Values of all other fields are preserved. + /// + public CallOptions WithDeadline(DateTime deadline) + { + var newOptions = this; + newOptions.deadline = deadline; + return newOptions; + } + + /// + /// Returns new instance of with + /// CancellationToken set to the value provided. Values of all other fields are preserved. + /// + public CallOptions WithCancellationToken(CancellationToken cancellationToken) + { + var newOptions = this; + newOptions.cancellationToken = cancellationToken; + return newOptions; + } + + /// + /// Returns a new instance of with + /// all previously unset values set to their defaults and deadline and cancellation + /// token propagated when appropriate. + /// + internal CallOptions Normalize() + { + var newOptions = this; + if (propagationToken != null) + { + if (propagationToken.Options.IsPropagateDeadline) + { + Preconditions.CheckArgument(!newOptions.deadline.HasValue, + "Cannot propagate deadline from parent call. The deadline has already been set explicitly."); + newOptions.deadline = propagationToken.ParentDeadline; + } + if (propagationToken.Options.IsPropagateCancellation) + { + Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled, + "Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value."); + } + } + + newOptions.headers = newOptions.headers ?? Metadata.Empty; + newOptions.deadline = newOptions.deadline ?? DateTime.MaxValue; + return newOptions; + } } } diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index 88494bb4ac8..48fc7ed34a5 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -62,6 +62,18 @@ namespace Grpc.Core set; } + /// + /// gRPC supports multiple "hosts" being served by a single server. + /// This property can be used to set the target host explicitly. + /// By default, this will be set to null with the meaning + /// "use default host". + /// + public string Host + { + get; + set; + } + /// /// Channel associated with this client. /// @@ -83,10 +95,14 @@ namespace Grpc.Core var interceptor = HeaderInterceptor; if (interceptor != null) { + if (options.Headers == null) + { + options = options.WithHeaders(new Metadata()); + } interceptor(options.Headers); options.Headers.Freeze(); } - return new CallInvocationDetails(channel, method, options); + return new CallInvocationDetails(channel, method, Host, options); } } } diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs index b6ea5115a4f..2e4bfc9e477 100644 --- a/src/csharp/Grpc.Core/ContextPropagationToken.cs +++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs @@ -52,7 +52,7 @@ namespace Grpc.Core /// /// Default propagation mask used by C core. /// - const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff; + private const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff; /// /// Default propagation mask used by C# - we want to propagate deadline @@ -74,6 +74,9 @@ namespace Grpc.Core this.options = options ?? ContextPropagationOptions.Default; } + /// + /// Gets the native handle of the parent call. + /// internal CallSafeHandle ParentCall { get @@ -82,7 +85,10 @@ namespace Grpc.Core } } - internal DateTime Deadline + /// + /// Gets the parent call's deadline. + /// + internal DateTime ParentDeadline { get { @@ -90,7 +96,10 @@ namespace Grpc.Core } } - internal CancellationToken CancellationToken + /// + /// Gets the parent call's cancellation token. + /// + internal CancellationToken ParentCancellationToken { get { @@ -98,6 +107,9 @@ namespace Grpc.Core } } + /// + /// Get the context propagation options. + /// internal ContextPropagationOptions Options { get @@ -105,16 +117,6 @@ namespace Grpc.Core return this.options; } } - - internal bool IsPropagateDeadline - { - get { return false; } - } - - internal bool IsPropagateCancellation - { - get { return false; } - } } /// @@ -122,7 +124,37 @@ namespace Grpc.Core /// public class ContextPropagationOptions { + /// + /// The context propagation options that will be used by default. + /// public static readonly ContextPropagationOptions Default = new ContextPropagationOptions(); + + bool propagateDeadline; + bool propagateCancellation; + + + /// + /// Creates new context propagation options. + /// + /// If set to true parent call's deadline will be propagated to the child call. + /// If set to true parent call's cancellation token will be propagated to the child call. + public ContextPropagationOptions(bool propagateDeadline = true, bool propagateCancellation = true) + { + this.propagateDeadline = propagateDeadline; + this.propagateCancellation = propagateCancellation; + } + + /// true if parent call's deadline should be propagated to the child call. + public bool IsPropagateDeadline + { + get { return this.propagateDeadline; } + } + + /// true if parent call's cancellation token should be propagated to the child call. + public bool IsPropagateCancellation + { + get { return this.propagateCancellation; } + } } /// diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 6aeca29d964..2c3e3d75eae 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -63,7 +63,7 @@ namespace Grpc.Core.Internal public AsyncCall(CallInvocationDetails callDetails) : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer) { - this.details = callDetails; + this.details = callDetails.WithOptions(callDetails.Options.Normalize()); this.initialMetadataSent = true; // we always send metadata at the very beginning of the call. } @@ -318,12 +318,11 @@ namespace Grpc.Core.Internal private void Initialize(CompletionQueueSafeHandle cq) { - var propagationToken = details.Options.PropagationToken; - var parentCall = propagationToken != null ? propagationToken.ParentCall : CallSafeHandle.NullInstance; + var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance; var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, parentCall, ContextPropagationToken.DefaultMask, cq, - details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline)); + details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value)); details.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); InitializeInternal(call); RegisterCancellationCallback(); From 1b926ee4ddde9b13c4f1b8a2e1c4d6684ea4c1fe Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 Aug 2015 22:51:29 -0700 Subject: [PATCH 105/117] add comments --- src/csharp/Grpc.Core/CallInvocationDetails.cs | 40 +++++++++++++++++ src/csharp/Grpc.Core/Calls.cs | 44 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs index 8959baf306b..6565073fc5e 100644 --- a/src/csharp/Grpc.Core/CallInvocationDetails.cs +++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs @@ -49,16 +49,38 @@ namespace Grpc.Core readonly Marshaller responseMarshaller; CallOptions options; + /// + /// Initializes a new instance of the struct. + /// + /// Channel to use for this call. + /// Method to call. + /// Call options. public CallInvocationDetails(Channel channel, Method method, CallOptions options) : this(channel, method, null, options) { } + /// + /// Initializes a new instance of the struct. + /// + /// Channel to use for this call. + /// Method to call. + /// Host that contains the method. if null, default host will be used. + /// Call options. public CallInvocationDetails(Channel channel, Method method, string host, CallOptions options) : this(channel, method.FullName, host, method.RequestMarshaller, method.ResponseMarshaller, options) { } + /// + /// Initializes a new instance of the struct. + /// + /// Channel to use for this call. + /// Qualified method name. + /// Host that contains the method. + /// Request marshaller. + /// Response marshaller. + /// Call options. public CallInvocationDetails(Channel channel, string method, string host, Marshaller requestMarshaller, Marshaller responseMarshaller, CallOptions options) { this.channel = Preconditions.CheckNotNull(channel, "channel"); @@ -69,6 +91,9 @@ namespace Grpc.Core this.options = options; } + /// + /// Get channel associated with this call. + /// public Channel Channel { get @@ -77,6 +102,9 @@ namespace Grpc.Core } } + /// + /// Gets name of method to be called. + /// public string Method { get @@ -85,6 +113,9 @@ namespace Grpc.Core } } + /// + /// Get name of host. + /// public string Host { get @@ -93,6 +124,9 @@ namespace Grpc.Core } } + /// + /// Gets marshaller used to serialize requests. + /// public Marshaller RequestMarshaller { get @@ -101,6 +135,9 @@ namespace Grpc.Core } } + /// + /// Gets marshaller used to deserialized responses. + /// public Marshaller ResponseMarshaller { get @@ -109,6 +146,9 @@ namespace Grpc.Core } } + /// + /// Gets the call options. + /// public CallOptions Options { get diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index b9128c914d5..7067456638a 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -38,9 +38,20 @@ namespace Grpc.Core { /// /// Helper methods for generated clients to make RPC calls. + /// Most users will use this class only indirectly and will be + /// making calls using client object generated from protocol + /// buffer definition files. /// public static class Calls { + /// + /// Invokes a simple remote call in a blocking fashion. + /// + /// The response. + /// The call defintion. + /// Request message. + /// Type of request message. + /// The of response message. public static TResponse BlockingUnaryCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class @@ -49,6 +60,14 @@ namespace Grpc.Core return asyncCall.UnaryCall(req); } + /// + /// Invokes a simple remote call asynchronously. + /// + /// An awaitable call object providing access to the response. + /// The call defintion. + /// Request message. + /// Type of request message. + /// The of response message. public static AsyncUnaryCall AsyncUnaryCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class @@ -58,6 +77,15 @@ namespace Grpc.Core return new AsyncUnaryCall(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } + /// + /// Invokes a server streaming call asynchronously. + /// In server streaming scenario, client sends on request and server responds with a stream of responses. + /// + /// A call object providing access to the asynchronous response stream. + /// The call defintion. + /// Request message. + /// Type of request message. + /// The of response messages. public static AsyncServerStreamingCall AsyncServerStreamingCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class @@ -68,6 +96,13 @@ namespace Grpc.Core return new AsyncServerStreamingCall(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } + /// + /// Invokes a client streaming call asynchronously. + /// In client streaming scenario, client sends a stream of requests and server responds with a single response. + /// + /// An awaitable call object providing access to the response. + /// Type of request messages. + /// The of response message. public static AsyncClientStreamingCall AsyncClientStreamingCall(CallInvocationDetails call) where TRequest : class where TResponse : class @@ -78,6 +113,15 @@ namespace Grpc.Core return new AsyncClientStreamingCall(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } + /// + /// Invokes a duplex streaming call asynchronously. + /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses. + /// The response stream is completely independent and both side can be sending messages at the same time. + /// + /// A call object providing access to the asynchronous request and response streams. + /// The call definition. + /// Type of request messages. + /// Type of reponse messages. public static AsyncDuplexStreamingCall AsyncDuplexStreamingCall(CallInvocationDetails call) where TRequest : class where TResponse : class From bc435e7ee99c37d8ffcad15c957dc75c947c9e7b Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 10 Aug 2015 23:47:07 -0700 Subject: [PATCH 106/117] recommend to require empty service name --- doc/health-checking.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/health-checking.md b/doc/health-checking.md index fb6566577c3..0b3f9c6a034 100644 --- a/doc/health-checking.md +++ b/doc/health-checking.md @@ -58,11 +58,12 @@ a response must be sent back with an `OK` status and the status field should be set to `SERVING` or `NOT_SERVING` accordingly. If the service name is not registered, the server returns a `NOT_FOUND` GRPC status. -It is recommended that the server use an empty string as the key for server’s -health status as a whole. The server can just do exact matching of the -service name support any kind of wildcard matching. However, the service owner -has the freedom to implement more complicated matching semantics that both the -client and server agree upon. +The server should use an empty string as the key for server’s +overall health status, so that a client not interested in a specific service can +query the server's status with an empty request. The server can just do exact +matching of the service name without support of any kind of wildcard matching. +However, the service owner has the freedom to implement more complicated +matching semantics that both the client and server agree upon. A client can declare the server as unhealthy if the rpc is not finished after some amount of time. The client should be able to handle the case where server From 623a74d0a86d37f3ce43a2298301a204ec7abd96 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 11 Aug 2015 09:24:20 -0700 Subject: [PATCH 107/117] Exposes call#peer, channel#target --- src/ruby/ext/grpc/rb_call.c | 14 ++++++++++++++ src/ruby/ext/grpc/rb_channel.c | 17 +++++++++++++++++ src/ruby/spec/client_server_spec.rb | 17 +++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index a7607a83a36..88659da5354 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -179,6 +179,19 @@ static VALUE grpc_rb_call_cancel(VALUE self) { return Qnil; } +/* Called to obtain the peer that this call is connected to. */ +static VALUE grpc_rb_call_get_peer(VALUE self) { + VALUE res = Qnil; + grpc_call *call = NULL; + char *peer = NULL; + TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); + peer = grpc_call_get_peer(call); + res = rb_str_new2(peer); + gpr_free(peer); + + return res; +} + /* call-seq: status = call.status @@ -720,6 +733,7 @@ void Init_grpc_call() { /* Add ruby analogues of the Call methods. */ rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4); rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0); + rb_define_method(grpc_rb_cCall, "peer", grpc_rb_call_get_peer, 0); rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0); rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1); rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0); diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index a0663607c24..43d9937d748 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -37,6 +37,7 @@ #include #include +#include #include "rb_grpc.h" #include "rb_call.h" #include "rb_channel_args.h" @@ -249,6 +250,21 @@ static VALUE grpc_rb_channel_destroy(VALUE self) { return Qnil; } + +/* Called to obtain the target that this channel accesses. */ +static VALUE grpc_rb_channel_get_target(VALUE self) { + grpc_rb_channel *wrapper = NULL; + VALUE res = Qnil; + char* target = NULL; + + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); + target = grpc_channel_get_target(wrapper->wrapped); + res = rb_str_new2(target); + gpr_free(target); + + return res; +} + void Init_grpc_channel() { grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject); grpc_rb_cChannel = @@ -265,6 +281,7 @@ void Init_grpc_channel() { /* Add ruby analogues of the Channel methods. */ rb_define_method(grpc_rb_cChannel, "create_call", grpc_rb_channel_create_call, 4); + rb_define_method(grpc_rb_cChannel, "target", grpc_rb_channel_get_target, 0); rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0); rb_define_alias(grpc_rb_cChannel, "close", "destroy"); diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index 0e854412099..ed8032517b8 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -69,6 +69,23 @@ shared_examples 'basic GRPC message delivery is OK' do include GRPC::Core include_context 'setup: tags' + context 'the test channel' do + it 'should have a target' do + expect(@ch.target).to be_a(String) + end + end + + context 'a client call' do + it 'should have a peer' do + expect(new_client_call.peer).to be_a(String) + end + end + + it 'calls have peer info' do + call = new_client_call + expect(call.peer).to be_a(String) + end + it 'servers receive requests from clients and can respond' do call = new_client_call server_call = nil From 10ddfde8e63abcca866e4d3cfeed1d5182ecd61b Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 11 Aug 2015 09:54:59 -0700 Subject: [PATCH 108/117] Adds grpc.primary_user_agent key during stub creation --- src/ruby/lib/grpc/generic/client_stub.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index 7b2c04aa226..3640a8c050a 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -28,6 +28,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc/generic/active_call' +require 'grpc/version' # GRPC contains the General RPC module. module GRPC @@ -46,6 +47,7 @@ module GRPC fail(TypeError, '!Channel') unless alt_chan.is_a?(Core::Channel) return alt_chan end + kw['grpc.primary_user_agent'] = "grpc-ruby/#{VERSION}" return Core::Channel.new(host, kw) if creds.nil? fail(TypeError, '!Credentials') unless creds.is_a?(Core::Credentials) Core::Channel.new(host, kw, creds) From 23e0f8843b1d150f20b575461a43792a44e9e08d Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 11 Aug 2015 10:13:18 -0700 Subject: [PATCH 109/117] Aligns with the cognoscenti on timeouts --- src/ruby/lib/grpc/generic/client_stub.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index 3640a8c050a..745eab437ea 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -37,8 +37,8 @@ module GRPC include Core::StatusCodes include Core::TimeConsts - # Default timeout is 5 seconds. - DEFAULT_TIMEOUT = 5 + # Default timeout is infinity. + DEFAULT_TIMEOUT = INFINITE_FUTURE # setup_channel is used by #initialize to constuct a channel from its # arguments. From d42c1b7b5ac6baea3536943780f694caea2a94ac Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 11 Aug 2015 10:50:21 -0700 Subject: [PATCH 110/117] Use null for default host --- src/ruby/ext/grpc/rb_channel.c | 5 ++++- src/ruby/lib/grpc/generic/client_stub.rb | 2 +- src/ruby/spec/call_spec.rb | 2 +- src/ruby/spec/channel_spec.rb | 4 ++-- src/ruby/spec/client_server_spec.rb | 2 +- src/ruby/spec/generic/active_call_spec.rb | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 43d9937d748..ac591f15637 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -203,7 +203,10 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method, grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; char *method_chars = StringValueCStr(method); - char *host_chars = StringValueCStr(host); + char *host_chars = NULL; + if (host != Qnil) { + host_chars = StringValueCStr(host); + } cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index 3640a8c050a..d9823da712f 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -410,7 +410,7 @@ module GRPC # @param timeout [TimeConst] def new_active_call(method, marshal, unmarshal, timeout = nil) deadline = from_relative_time(timeout.nil? ? @timeout : timeout) - call = @ch.create_call(@queue, method, @host, deadline) + call = @ch.create_call(@queue, method, nil, deadline) ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false) end end diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb index 4977c10a7e1..36a442faed1 100644 --- a/src/ruby/spec/call_spec.rb +++ b/src/ruby/spec/call_spec.rb @@ -137,7 +137,7 @@ describe GRPC::Core::Call do end def make_test_call - @ch.create_call(client_queue, 'dummy_method', 'dummy_host', deadline) + @ch.create_call(client_queue, 'dummy_method', nil, deadline) end def deadline diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index d471ff5db6f..9081f0e20c2 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -117,7 +117,7 @@ describe GRPC::Core::Channel do deadline = Time.now + 5 blk = proc do - ch.create_call(cq, 'dummy_method', 'dummy_host', deadline) + ch.create_call(cq, 'dummy_method', nil, deadline) end expect(&blk).to_not raise_error end @@ -128,7 +128,7 @@ describe GRPC::Core::Channel do deadline = Time.now + 5 blk = proc do - ch.create_call(cq, 'dummy_method', 'dummy_host', deadline) + ch.create_call(cq, 'dummy_method', nil, deadline) end expect(&blk).to raise_error(RuntimeError) end diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index ed8032517b8..57c9a8de9b1 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -61,7 +61,7 @@ shared_context 'setup: tags' do end def new_client_call - @ch.create_call(@client_queue, '/method', 'foo.test.google.fr', deadline) + @ch.create_call(@client_queue, '/method', nil, deadline) end end diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index bc3bee3d440..424b2dbdeb8 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -338,7 +338,7 @@ describe GRPC::ActiveCall do end def make_test_call - @ch.create_call(@client_queue, '/method', 'a.dummy.host', deadline) + @ch.create_call(@client_queue, '/method', nil, deadline) end def deadline From 17b16590146b6a90825c59f1f355708f98e23dc5 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 11 Aug 2015 11:32:46 -0700 Subject: [PATCH 111/117] Corrects the way the gemspec references files --- src/ruby/grpc.gemspec | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index dd4e27df514..45f31329e94 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -16,12 +16,15 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 2.0.0' s.requirements << 'libgrpc ~> 0.10.0 needs to be installed' - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- spec/*`.split("\n") - s.executables = `git ls-files -- bin/*.rb`.split("\n").map do |f| - File.basename(f) + s.files = %w( Rakefile ) + s.files += Dir.glob('lib/**/*') + s.files += Dir.glob('ext/**/*') + s.files += Dir.glob('bin/**/*') + s.test_files = Dir.glob('spec/**/*') + %w(math noproto).each do |b| + s.executables += [ "#{b}_client.rb", "#{b}_server.rb" ] end - s.require_paths = ['lib'] + s.require_paths = %w( bin lib ) s.platform = Gem::Platform::RUBY s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1' From 9bfb16aaf266327a47b8d4a7e4e9cf41026d9b83 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 11 Aug 2015 17:30:05 -0700 Subject: [PATCH 112/117] Fixed lint errors --- src/node/interop/interop_client.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 55d243ca1a8..27f6c19c13f 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -67,7 +67,7 @@ function zeroBuffer(size) { * primarily for use with mocha */ function emptyUnary(client, done) { - var call = client.emptyCall({}, function(err, resp) { + client.emptyCall({}, function(err, resp) { assert.ifError(err); if (done) { done(); @@ -89,7 +89,7 @@ function largeUnary(client, done) { body: zeroBuffer(271828) } }; - var call = client.unaryCall(arg, function(err, resp) { + client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); assert.strictEqual(resp.payload.body.length, 314159); @@ -293,7 +293,7 @@ function authTest(expected_user, scope, client, done) { fill_username: true, fill_oauth_scope: true }; - var call = client.unaryCall(arg, function(err, resp) { + client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); assert.strictEqual(resp.payload.body.length, 314159); @@ -328,7 +328,7 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) { }; var makeTestCall = function(error, client_metadata) { assert.ifError(error); - var call = client.unaryCall(arg, function(err, resp) { + client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.username, expected_user); assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); From c7176a80ab9a01a4bbfdedeed0fbf1710a120850 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Tue, 11 Aug 2015 17:39:00 -0700 Subject: [PATCH 113/117] Fixing clock type. --- test/core/security/verify_jwt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c index 9b334b3c3e8..69bbc3cc0cb 100644 --- a/test/core/security/verify_jwt.c +++ b/test/core/security/verify_jwt.c @@ -112,7 +112,7 @@ int main(int argc, char **argv) { while (!sync.is_done) { grpc_pollset_worker worker; grpc_pollset_work(&sync.pollset, &worker, - gpr_inf_future(GPR_CLOCK_REALTIME)); + gpr_inf_future(GPR_CLOCK_MONOTONIC)); } gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset)); From 086a98274424d3c779c12f442310c6e4621e83a2 Mon Sep 17 00:00:00 2001 From: "David G. Quintas" Date: Tue, 11 Aug 2015 18:56:10 -0700 Subject: [PATCH 114/117] Removed "<:" bigram confusing gcc 4.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resulted in error: ```test/cpp/end2end/end2end_test.cc:120: error: ‘<::’ cannot begin a template-argument list test/cpp/end2end/end2end_test.cc:120: note: ‘<:’ is an alternate spelling for ‘[’. Insert whitespace between ‘<’ and ‘::’ test/cpp/end2end/end2end_test.cc:120: note: (if you use ‘-fpermissive’ G++ will accept your code) make: *** [objs/opt/test/cpp/end2end/end2end_test.o] Error 1``` --- test/cpp/end2end/end2end_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 5f0749daa5c..37669815c63 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -117,7 +117,7 @@ class Proxy : public ::grpc::cpp::test::util::TestService::Service { } private: - std::unique_ptr<::grpc::cpp::test::util::TestService::Stub> stub_; + std::unique_ptr< ::grpc::cpp::test::util::TestService::Stub> stub_; }; class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { From ebf4046d7fc8df57642612807e0254266753e248 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 11 Aug 2015 10:14:41 -0700 Subject: [PATCH 115/117] getting rid of unnecessary exception type --- .../Grpc.Core/Internal/AsyncCallBase.cs | 4 +- .../Grpc.Core/OperationFailedException.cs | 47 ------------------- 2 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 src/csharp/Grpc.Core/OperationFailedException.cs diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 9fa0baca87a..6ca4bbdafc5 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -293,7 +293,7 @@ namespace Grpc.Core.Internal if (!success) { - FireCompletion(origCompletionDelegate, null, new OperationFailedException("Send failed")); + FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Send failed")); } else { @@ -318,7 +318,7 @@ namespace Grpc.Core.Internal if (!success) { - FireCompletion(origCompletionDelegate, null, new OperationFailedException("Halfclose failed")); + FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Halfclose failed")); } else { diff --git a/src/csharp/Grpc.Core/OperationFailedException.cs b/src/csharp/Grpc.Core/OperationFailedException.cs deleted file mode 100644 index 9b1c24d0c16..00000000000 --- a/src/csharp/Grpc.Core/OperationFailedException.cs +++ /dev/null @@ -1,47 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; - -namespace Grpc.Core -{ - /// - /// Thrown when gRPC operation fails. - /// - public class OperationFailedException : Exception - { - public OperationFailedException(string message) : base(message) - { - } - } -} From 0c140a863ed5ccc5c3c5aa2577332ccc4dbb2ef4 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Sun, 2 Aug 2015 00:54:02 -0700 Subject: [PATCH 116/117] migrate to usable auth library --- src/csharp/Grpc.Auth/GoogleCredential.cs | 125 ------------------ src/csharp/Grpc.Auth/Grpc.Auth.csproj | 27 ++-- src/csharp/Grpc.Auth/OAuth2Interceptors.cs | 26 ++-- src/csharp/Grpc.Auth/app.config | 4 + src/csharp/Grpc.Auth/packages.config | 4 +- src/csharp/Grpc.Core.Tests/ChannelTest.cs | 4 +- src/csharp/Grpc.Core/Channel.cs | 24 +++- src/csharp/Grpc.Core/ClientBase.cs | 11 +- .../Grpc.IntegrationTesting.Client/app.config | 4 + .../Grpc.IntegrationTesting.Server/app.config | 4 + .../Grpc.IntegrationTesting.csproj | 38 +++--- .../Grpc.IntegrationTesting/InteropClient.cs | 80 +++++++---- src/csharp/Grpc.IntegrationTesting/app.config | 4 + .../Grpc.IntegrationTesting/packages.config | 4 +- 14 files changed, 144 insertions(+), 215 deletions(-) delete mode 100644 src/csharp/Grpc.Auth/GoogleCredential.cs diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs deleted file mode 100644 index 9936cf583ca..00000000000 --- a/src/csharp/Grpc.Auth/GoogleCredential.cs +++ /dev/null @@ -1,125 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; - -using Google.Apis.Auth.OAuth2; -using Google.Apis.Auth.OAuth2.Responses; -using Newtonsoft.Json.Linq; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; - -namespace Grpc.Auth -{ - // TODO(jtattermusch): Remove this class once possible. - /// - /// A temporary placeholder for Google credential from - /// Google Auth library for .NET. It emulates the usage pattern - /// for Usable auth. - /// - public class GoogleCredential - { - private const string GoogleApplicationCredentialsEnvName = "GOOGLE_APPLICATION_CREDENTIALS"; - private const string ClientEmailFieldName = "client_email"; - private const string PrivateKeyFieldName = "private_key"; - - private ServiceCredential credential; - - private GoogleCredential(ServiceCredential credential) - { - this.credential = credential; - } - - public static GoogleCredential GetApplicationDefault() - { - return new GoogleCredential(null); - } - - public bool IsCreateScopedRequired - { - get - { - return true; - } - } - - public GoogleCredential CreateScoped(IEnumerable scopes) - { - var credsPath = Environment.GetEnvironmentVariable(GoogleApplicationCredentialsEnvName); - if (credsPath == null) - { - // Default to ComputeCredentials if path to JSON key is not set. - // ComputeCredential is not scoped actually, but for our use case it's - // fine to treat is as such. - return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer())); - } - - JObject jsonCredentialParameters = JObject.Parse(File.ReadAllText(credsPath)); - string clientEmail = jsonCredentialParameters.GetValue(ClientEmailFieldName).Value(); - string privateKeyString = jsonCredentialParameters.GetValue(PrivateKeyFieldName).Value(); - - var serviceCredential = new ServiceAccountCredential( - new ServiceAccountCredential.Initializer(clientEmail) - { - Scopes = scopes, - }.FromPrivateKey(privateKeyString)); - return new GoogleCredential(serviceCredential); - } - - public Task RequestAccessTokenAsync(CancellationToken taskCancellationToken) - { - return credential.RequestAccessTokenAsync(taskCancellationToken); - } - - public TokenResponse Token - { - get - { - return credential.Token; - } - } - - internal ServiceCredential InternalCredential - { - get - { - return credential; - } - } - } -} diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 8e5036832d5..930a34b0c33 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -11,7 +11,7 @@ Grpc.Auth v4.5 bin\$(Configuration)\Grpc.Auth.Xml - 9b408026 + 4f8487a9 true @@ -41,28 +41,32 @@ C:\keys\Grpc.snk - + + False ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll - + False - ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll - + False - ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll - + False - ..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll - + + False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - + + False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - + + False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll @@ -87,7 +91,6 @@ Version.cs - diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs index cc9d2c175ff..d628a83246d 100644 --- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs +++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs @@ -54,7 +54,7 @@ namespace Grpc.Auth /// public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential) { - var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default); + var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default); return new MetadataInterceptorDelegate(interceptor.InterceptHeaders); } @@ -66,7 +66,7 @@ namespace Grpc.Auth public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token) { Preconditions.CheckNotNull(oauth2Token); - return new MetadataInterceptorDelegate((metadata) => + return new MetadataInterceptorDelegate((authUri, metadata) => { metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token)); }); @@ -80,10 +80,10 @@ namespace Grpc.Auth private const string AuthorizationHeader = "Authorization"; private const string Schema = "Bearer"; - private ServiceCredential credential; + private ITokenAccess credential; private IClock clock; - public OAuth2Interceptor(ServiceCredential credential, IClock clock) + public OAuth2Interceptor(ITokenAccess credential, IClock clock) { this.credential = credential; this.clock = clock; @@ -94,23 +94,15 @@ namespace Grpc.Auth /// /// /// - public string GetAccessToken(CancellationToken cancellationToken) + public string GetAccessToken(string authUri, CancellationToken cancellationToken) { - if (credential.Token == null || credential.Token.IsExpired(clock)) - { - // TODO(jtattermusch): Parallel requests will spawn multiple requests to refresh the token once the token expires. - // TODO(jtattermusch): Rethink synchronous wait to obtain the result. - if (!credential.RequestAccessTokenAsync(cancellationToken).Result) - { - throw new InvalidOperationException("The access token has expired but we can't refresh it"); - } - } - return credential.Token.AccessToken; + // TODO(jtattermusch): Rethink synchronous wait to obtain the result. + return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult(); } - public void InterceptHeaders(Metadata metadata) + public void InterceptHeaders(string authUri, Metadata metadata) { - var accessToken = GetAccessToken(CancellationToken.None); + var accessToken = GetAccessToken(authUri, CancellationToken.None); metadata.Add(CreateBearerTokenHeader(accessToken)); } diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config index 0a82bb4f16c..84d7534d650 100644 --- a/src/csharp/Grpc.Auth/app.config +++ b/src/csharp/Grpc.Auth/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config index 29be953bf3e..7a02c95db91 100644 --- a/src/csharp/Grpc.Auth/packages.config +++ b/src/csharp/Grpc.Auth/packages.config @@ -1,8 +1,8 @@  - - + + diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs index 90f6e570c4c..27875729240 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs @@ -72,11 +72,11 @@ namespace Grpc.Core.Tests } [Test] - public void Target() + public void ResolvedTarget() { using (var channel = new Channel("127.0.0.1", Credentials.Insecure)) { - Assert.IsTrue(channel.Target.Contains("127.0.0.1")); + Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1")); } } diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index f8cbe08466c..64c6adf2bfc 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -49,6 +49,7 @@ namespace Grpc.Core { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + readonly string target; readonly GrpcEnvironment environment; readonly ChannelSafeHandle handle; readonly List options; @@ -58,12 +59,12 @@ namespace Grpc.Core /// Creates a channel that connects to a specific host. /// Port will default to 80 for an unsecure channel and to 443 for a secure channel. /// - /// The name or IP address of the host. + /// Target of the channel. /// Credentials to secure the channel. /// Channel options. - public Channel(string host, Credentials credentials, IEnumerable options = null) + public Channel(string target, Credentials credentials, IEnumerable options = null) { - Preconditions.CheckNotNull(host, "host"); + this.target = Preconditions.CheckNotNull(target, "target"); this.environment = GrpcEnvironment.GetInstance(); this.options = options != null ? new List(options) : new List(); @@ -73,11 +74,11 @@ namespace Grpc.Core { if (nativeCredentials != null) { - this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs); + this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs); } else { - this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs); + this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs); } } } @@ -131,8 +132,8 @@ namespace Grpc.Core return tcs.Task; } - /// Address of the remote endpoint in URI format. - public string Target + /// Resolved address of the remote endpoint in URI format. + public string ResolvedTarget { get { @@ -140,6 +141,15 @@ namespace Grpc.Core } } + /// The original target used to create the channel. + public string Target + { + get + { + return this.target; + } + } + /// /// Allows explicitly requesting channel to connect without starting an RPC. /// Returned task completes once state Ready was seen. If the deadline is reached, diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index 48fc7ed34a5..f46184406c5 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -35,21 +35,26 @@ using System; using System.Collections.Generic; using Grpc.Core.Internal; +using System.Text.RegularExpressions; namespace Grpc.Core { - public delegate void MetadataInterceptorDelegate(Metadata metadata); + public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata); /// /// Base class for client-side stubs. /// public abstract class ClientBase { + static readonly Regex TrailingPortPattern = new Regex(":[0-9]+/?$"); readonly Channel channel; + readonly string authUriBase; public ClientBase(Channel channel) { this.channel = channel; + // TODO(jtattermush): we shouldn't need to hand-curate the channel.Target contents. + this.authUriBase = "https://" + TrailingPortPattern.Replace(channel.Target, "") + "/"; } /// @@ -99,8 +104,8 @@ namespace Grpc.Core { options = options.WithHeaders(new Metadata()); } - interceptor(options.Headers); - options.Headers.Freeze(); + var authUri = authUriBase + method.ServiceName; + interceptor(authUri, options.Headers); } return new CallInvocationDetails(channel, method, Host, options); } diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config index 0a82bb4f16c..84d7534d650 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config index 0a82bb4f16c..84d7534d650 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 06a75a3351e..2020a76d396 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -8,7 +8,7 @@ Grpc.IntegrationTesting Grpc.IntegrationTesting v4.5 - 041c163e + 6566287f true @@ -38,20 +38,33 @@ C:\keys\Grpc.snk - + + False ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll - + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll + + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll + + + False + ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + False - ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - + False - ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - + False - ..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll False @@ -78,15 +91,6 @@ ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll - - ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - - - ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - - - ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index c918f60127a..385ca920862 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -43,6 +43,7 @@ using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; using NUnit.Framework; +using Google.Apis.Auth.OAuth2; namespace Grpc.IntegrationTesting { @@ -97,10 +98,10 @@ namespace Grpc.IntegrationTesting } var interopClient = new InteropClient(options); - interopClient.Run(); + interopClient.Run().Wait(); } - private void Run() + private async Task Run() { Credentials credentials = null; if (options.useTls) @@ -120,17 +121,7 @@ namespace Grpc.IntegrationTesting using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions)) { TestService.TestServiceClient client = new TestService.TestServiceClient(channel); - if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds") - { - var credential = GoogleCredential.GetApplicationDefault(); - if (credential.IsCreateScopedRequired) - { - credential = credential.CreateScoped(new[] { AuthScope }); - } - client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); - } - - RunTestCaseAsync(options.testCase, client).Wait(); + await RunTestCaseAsync(options.testCase, client); } GrpcEnvironment.Shutdown(); } @@ -158,16 +149,19 @@ namespace Grpc.IntegrationTesting await RunEmptyStreamAsync(client); break; case "service_account_creds": - RunServiceAccountCreds(client); + await RunServiceAccountCredsAsync(client); break; case "compute_engine_creds": - RunComputeEngineCreds(client); + await RunComputeEngineCredsAsync(client); + break; + case "jwt_token_creds": + await RunJwtTokenCredsAsync(client); break; case "oauth2_auth_token": - RunOAuth2AuthToken(client); + await RunOAuth2AuthTokenAsync(client); break; case "per_rpc_creds": - RunPerRpcCreds(client); + await RunPerRpcCredsAsync(client); break; case "cancel_after_begin": await RunCancelAfterBeginAsync(client); @@ -309,9 +303,13 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunServiceAccountCreds(TestService.ITestServiceClient client) + public static async Task RunServiceAccountCredsAsync(TestService.TestServiceClient client) { Console.WriteLine("running service_account_creds"); + var credential = await GoogleCredential.GetApplicationDefaultAsync(); + credential = credential.CreateScoped(new[] { AuthScope }); + client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + var request = SimpleRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) .SetResponseSize(314159) @@ -329,9 +327,13 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunComputeEngineCreds(TestService.ITestServiceClient client) + public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client) { Console.WriteLine("running compute_engine_creds"); + var credential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsFalse(credential.IsCreateScopedRequired); + client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + var request = SimpleRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) .SetResponseSize(314159) @@ -349,12 +351,35 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunOAuth2AuthToken(TestService.TestServiceClient client) + public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client) + { + Console.WriteLine("running jwt_token_creds"); + var credential = await GoogleCredential.GetApplicationDefaultAsync(); + // check this a credential with scope support, but don't add the scope. + Assert.IsTrue(credential.IsCreateScopedRequired); + client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + + var request = SimpleRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .SetResponseSize(314159) + .SetPayload(CreateZerosPayload(271828)) + .SetFillUsername(true) + .SetFillOauthScope(true) + .Build(); + + var response = client.UnaryCall(request); + + Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); + Assert.AreEqual(314159, response.Payload.Body.Length); + Assert.AreEqual(ServiceAccountUser, response.Username); + Console.WriteLine("Passed!"); + } + + public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client) { Console.WriteLine("running oauth2_auth_token"); - var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope }); - Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); - string oauth2Token = credential.Token.AccessToken; + ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); + string oauth2Token = await credential.GetAccessTokenForRequestAsync(); client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); @@ -370,13 +395,12 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunPerRpcCreds(TestService.TestServiceClient client) + public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client) { Console.WriteLine("running per_rpc_creds"); - var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope }); - Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); - string oauth2Token = credential.Token.AccessToken; + ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); + string oauth2Token = await credential.GetAccessTokenForRequestAsync(); var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); var request = SimpleRequest.CreateBuilder() @@ -385,7 +409,7 @@ namespace Grpc.IntegrationTesting .Build(); var headers = new Metadata(); - headerInterceptor(headers); + headerInterceptor("", headers); var response = client.UnaryCall(request, headers: headers); Assert.AreEqual(AuthScopeResponse, response.OauthScope); diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config index 0a82bb4f16c..84d7534d650 100644 --- a/src/csharp/Grpc.IntegrationTesting/app.config +++ b/src/csharp/Grpc.IntegrationTesting/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index 7d1f84f3031..0867b091b92 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -1,8 +1,8 @@  - - + + From 94829fb7b1a283c620898573ff0b418c2c16f57f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 12 Aug 2015 10:18:47 -0700 Subject: [PATCH 117/117] remove OperationFailedException also from the project file --- src/csharp/Grpc.Core/Grpc.Core.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 9a8195e9d09..055aff14448 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -83,7 +83,6 @@ -