aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'src/ruby')
-rw-r--r--src/ruby/ext/grpc/extconf.rb2
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.c17
-rw-r--r--src/ruby/ext/grpc/rb_call.c58
-rw-r--r--src/ruby/ext/grpc/rb_call_credentials.c40
-rw-r--r--src/ruby/ext/grpc/rb_channel.c24
-rw-r--r--src/ruby/ext/grpc/rb_channel_args.c2
-rw-r--r--src/ruby/ext/grpc/rb_channel_credentials.c25
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c6
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h13
-rw-r--r--src/ruby/ext/grpc/rb_server.c2
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.c26
-rw-r--r--src/ruby/lib/grpc.rb22
-rw-r--r--src/ruby/lib/grpc/core/time_consts.rb4
-rw-r--r--src/ruby/lib/grpc/errors.rb4
-rw-r--r--src/ruby/lib/grpc/generic/active_call.rb7
-rw-r--r--src/ruby/lib/grpc/generic/bidi_call.rb4
-rw-r--r--src/ruby/lib/grpc/generic/client_stub.rb17
-rw-r--r--src/ruby/lib/grpc/generic/rpc_desc.rb4
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb20
-rw-r--r--src/ruby/lib/grpc/generic/service.rb4
-rw-r--r--src/ruby/lib/grpc/grpc.rb6
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rwxr-xr-xsrc/ruby/pb/generate_proto_ruby.sh11
-rw-r--r--src/ruby/pb/grpc/health/checker.rb2
-rw-r--r--src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb28
-rw-r--r--src/ruby/pb/grpc/testing/metrics.rb28
-rw-r--r--src/ruby/pb/grpc/testing/metrics_services.rb27
-rwxr-xr-xsrc/ruby/pb/test/client.rb35
-rwxr-xr-xsrc/ruby/pb/test/server.rb2
-rw-r--r--src/ruby/qps/client.rb164
-rw-r--r--[-rwxr-xr-x]src/ruby/qps/histogram.rb (renamed from src/ruby/bin/grpc_ruby_interop_client)61
-rw-r--r--[-rwxr-xr-x]src/ruby/qps/qps-common.rb (renamed from src/ruby/bin/interop/interop_server.rb)60
-rw-r--r--src/ruby/qps/server.rb94
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/control.rb154
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/messages.rb84
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/payloads.rb33
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/services.rb14
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/services_services.rb46
-rw-r--r--src/ruby/qps/src/proto/grpc/testing/stats.rb39
-rwxr-xr-xsrc/ruby/qps/worker.rb128
-rw-r--r--src/ruby/spec/client_server_spec.rb2
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb35
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb7
-rw-r--r--[-rwxr-xr-x]src/ruby/spec/pb/duplicate/codegen_spec.rb (renamed from src/ruby/bin/grpc_ruby_interop_server)48
-rw-r--r--src/ruby/spec/pb/health/checker_spec.rb2
-rw-r--r--[-rwxr-xr-x]src/ruby/stress/metrics_server.rb (renamed from src/ruby/bin/interop/interop_client.rb)74
-rwxr-xr-xsrc/ruby/stress/stress_client.rb155
49 files changed, 1433 insertions, 213 deletions
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 6b7001a489..82b6d313c8 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index db7cac363a..cba910d832 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,21 +50,18 @@ grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) {
}
VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
- size_t length = 0;
- char *string = NULL;
- size_t offset = 0;
+ VALUE rb_string;
grpc_byte_buffer_reader reader;
gpr_slice next;
if (buffer == NULL) {
return Qnil;
-
}
- length = grpc_byte_buffer_length(buffer);
- string = xmalloc(length + 1);
+ rb_string = rb_str_buf_new(grpc_byte_buffer_length(buffer));
grpc_byte_buffer_reader_init(&reader, buffer);
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
- memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
- offset += GPR_SLICE_LENGTH(next);
+ rb_str_cat(rb_string, (const char *) GPR_SLICE_START_PTR(next),
+ GPR_SLICE_LENGTH(next));
+ gpr_slice_unref(next);
}
- return rb_str_new(string, length);
+ return rb_string;
}
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index af05ddf6e7..48c49a21e9 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -72,6 +72,10 @@ static ID id_cq;
* the flags used to create metadata from a Hash */
static ID id_flags;
+/* id_credentials is the name of the hidden ivar that preserves the value
+ * of the credentials added to the call */
+static ID id_credentials;
+
/* id_input_md is the name of the hidden ivar that preserves the hash used to
* create metadata, so that references to the strings it contains last as long
* as the call the metadata is added to. */
@@ -210,6 +214,35 @@ static VALUE grpc_rb_call_get_peer(VALUE self) {
return res;
}
+/* Called to obtain the x509 cert of an authenticated peer. */
+static VALUE grpc_rb_call_get_peer_cert(VALUE self) {
+ grpc_call *call = NULL;
+ VALUE res = Qnil;
+ grpc_auth_context *ctx = NULL;
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
+
+ ctx = grpc_call_auth_context(call);
+
+ if (!ctx || !grpc_auth_context_peer_is_authenticated(ctx)) {
+ return Qnil;
+ }
+
+ {
+ grpc_auth_property_iterator it =
+ grpc_auth_context_find_properties_by_name(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
+ const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+ if (prop == NULL) {
+ return Qnil;
+ }
+
+ res = rb_str_new2(prop->value);
+ }
+
+ grpc_auth_context_release(ctx);
+
+ return res;
+}
+
/*
call-seq:
status = call.status
@@ -299,6 +332,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
"grpc_call_set_credentials failed with %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
+ rb_ivar_set(self, id_credentials, credentials);
return Qnil;
}
@@ -354,7 +388,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
md_ary->metadata[md_ary->count].value_length = value_len;
md_ary->count += 1;
}
- } else {
+ } else if (TYPE(val) == T_STRING) {
value_str = RSTRING_PTR(val);
value_len = RSTRING_LEN(val);
if (!grpc_is_binary_header(key_str, key_len) &&
@@ -368,6 +402,10 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
md_ary->metadata[md_ary->count].value = value_str;
md_ary->metadata[md_ary->count].value_length = value_len;
md_ary->count += 1;
+ } else {
+ rb_raise(rb_eArgError,
+ "Header values must be of type string or array");
+ return ST_STOP;
}
return ST_CONTINUE;
@@ -546,13 +584,26 @@ static void grpc_run_batch_stack_init(run_batch_stack *st,
/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
* cleaned up */
static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
+ size_t i = 0;
+
grpc_metadata_array_destroy(&st->send_metadata);
grpc_metadata_array_destroy(&st->send_trailing_metadata);
grpc_metadata_array_destroy(&st->recv_metadata);
grpc_metadata_array_destroy(&st->recv_trailing_metadata);
+
if (st->recv_status_details != NULL) {
gpr_free(st->recv_status_details);
}
+
+ if (st->recv_message != NULL) {
+ grpc_byte_buffer_destroy(st->recv_message);
+ }
+
+ for (i = 0; i < st->op_num; i++) {
+ if (st->ops[i].op == GRPC_OP_SEND_MESSAGE) {
+ grpc_byte_buffer_destroy(st->ops[i].data.send_message);
+ }
+ }
}
/* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
@@ -638,7 +689,6 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
break;
case GRPC_OP_SEND_MESSAGE:
rb_struct_aset(result, sym_send_message, Qtrue);
- grpc_byte_buffer_destroy(st->ops[i].data.send_message);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
rb_struct_aset(result, sym_send_close, Qtrue);
@@ -840,6 +890,7 @@ void Init_grpc_call() {
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, "peer_cert", grpc_rb_call_get_peer_cert, 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);
@@ -859,6 +910,7 @@ void Init_grpc_call() {
id_cq = rb_intern("__cq");
id_flags = rb_intern("__flags");
id_input_md = rb_intern("__input_md");
+ id_credentials = rb_intern("__credentials");
/* Ids used in constructing the batch result. */
sym_send_message = ID2SYM(rb_intern("send_message"));
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index 2426f106a9..38bf1f7710 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include "rb_call.h"
#include "rb_event_thread.h"
@@ -50,9 +51,9 @@
* grpc_call_credentials */
static VALUE grpc_rb_cCallCredentials = Qnil;
-/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a peer
- * ruby object, 'mark' to minimize copying when a credential is created from
- * ruby. */
+/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a mark
+ * object that is used to hold references to any objects used to create the
+ * credentials. */
typedef struct grpc_rb_call_credentials {
/* Holder of ruby objects involved in contructing the credentials */
VALUE mark;
@@ -81,14 +82,23 @@ static VALUE grpc_rb_call_credentials_callback(VALUE callback_args) {
static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args,
VALUE exception_object) {
VALUE result = rb_hash_new();
+ VALUE backtrace = rb_funcall(
+ rb_funcall(exception_object, rb_intern("backtrace"), 0),
+ rb_intern("join"),
+ 1, rb_str_new2("\n\tfrom "));
+ VALUE exception_info = rb_funcall(exception_object, rb_intern("to_s"), 0);
+ const char *exception_classname = rb_obj_classname(exception_object);
(void)args;
+ gpr_log(GPR_INFO, "Call credentials callback failed: %s: %s\n%s",
+ exception_classname, StringValueCStr(exception_info),
+ StringValueCStr(backtrace));
rb_hash_aset(result, rb_str_new2("metadata"), Qnil);
/* Currently only gives the exception class name. It should be possible get
more details */
rb_hash_aset(result, rb_str_new2("status"),
INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
rb_hash_aset(result, rb_str_new2("details"),
- rb_str_new2(rb_obj_classname(exception_object)));
+ rb_str_new2(exception_classname));
return result;
}
@@ -146,13 +156,8 @@ static void grpc_rb_call_credentials_free(void *p) {
return;
}
wrapper = (grpc_rb_call_credentials *)p;
-
- /* Delete the wrapped object if the mark object is Qnil, which indicates that
- * no other object is the actual owner. */
- if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
- grpc_call_credentials_release(wrapper->wrapped);
- wrapper->wrapped = NULL;
- }
+ grpc_call_credentials_release(wrapper->wrapped);
+ wrapper->wrapped = NULL;
xfree(p);
}
@@ -164,8 +169,6 @@ static void grpc_rb_call_credentials_mark(void *p) {
return;
}
wrapper = (grpc_rb_call_credentials *)p;
-
- /* If it's not already cleaned up, mark the mark object */
if (wrapper->mark != Qnil) {
rb_gc_mark(wrapper->mark);
}
@@ -194,7 +197,7 @@ static VALUE grpc_rb_call_credentials_alloc(VALUE cls) {
/* Creates a wrapping object for a given call credentials. This should only be
* called with grpc_call_credentials objects that are not already associated
* with any Ruby object */
-VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) {
+VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c, VALUE mark) {
VALUE rb_wrapper;
grpc_rb_call_credentials *wrapper;
if (c == NULL) {
@@ -204,6 +207,7 @@ VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) {
TypedData_Get_Struct(rb_wrapper, grpc_rb_call_credentials,
&grpc_rb_call_credentials_data_type, wrapper);
wrapper->wrapped = c;
+ wrapper->mark = mark;
return rb_wrapper;
}
@@ -267,6 +271,7 @@ static VALUE grpc_rb_call_credentials_init(VALUE self, VALUE proc) {
return Qnil;
}
+ wrapper->mark = proc;
wrapper->wrapped = creds;
rb_ivar_set(self, id_callback, proc);
@@ -277,15 +282,18 @@ static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv,
VALUE self) {
grpc_call_credentials *creds;
grpc_call_credentials *other;
+ VALUE mark;
if (argc == 0) {
return self;
}
+ mark = rb_ary_new();
creds = grpc_rb_get_wrapped_call_credentials(self);
for (int i = 0; i < argc; i++) {
+ rb_ary_push(mark, argv[i]);
other = grpc_rb_get_wrapped_call_credentials(argv[i]);
creds = grpc_composite_call_credentials_create(creds, other, NULL);
}
- return grpc_rb_wrap_call_credentials(creds);
+ return grpc_rb_wrap_call_credentials(creds, mark);
}
void Init_grpc_call_credentials() {
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 0e6badbdaf..984afad107 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,11 +70,10 @@ static VALUE grpc_rb_cChannel = Qnil;
/* Used during the conversion of a hash to channel args during channel setup */
static VALUE grpc_rb_cChannelArgs;
-/* grpc_rb_channel wraps a grpc_channel. It provides a peer ruby object,
- * 'mark' to minimize copying when a channel is created from ruby. */
+/* grpc_rb_channel wraps a grpc_channel. */
typedef struct grpc_rb_channel {
- /* Holder of ruby objects involved in constructing the channel */
- VALUE mark;
+ VALUE credentials;
+
/* The actual channel */
grpc_channel *wrapped;
} grpc_rb_channel;
@@ -87,13 +86,8 @@ static void grpc_rb_channel_free(void *p) {
};
ch = (grpc_rb_channel *)p;
- /* Deletes the wrapped object if the mark object is Qnil, which indicates
- * that no other object is the actual owner. */
- if (ch->wrapped != NULL && ch->mark == Qnil) {
+ if (ch->wrapped != NULL) {
grpc_channel_destroy(ch->wrapped);
- rb_warning("channel gc: destroyed the c channel");
- } else {
- rb_warning("channel gc: did not destroy the c channel");
}
xfree(p);
@@ -106,8 +100,8 @@ static void grpc_rb_channel_mark(void *p) {
return;
}
channel = (grpc_rb_channel *)p;
- if (channel->mark != Qnil) {
- rb_gc_mark(channel->mark);
+ if (channel->credentials != Qnil) {
+ rb_gc_mark(channel->credentials);
}
}
@@ -125,7 +119,7 @@ static rb_data_type_t grpc_channel_data_type = {
static VALUE grpc_rb_channel_alloc(VALUE cls) {
grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel);
wrapper->wrapped = NULL;
- wrapper->mark = Qnil;
+ wrapper->credentials = Qnil;
return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper);
}
@@ -162,6 +156,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
}
ch = grpc_insecure_channel_create(target_chars, &args, NULL);
} else {
+ wrapper->credentials = credentials;
creds = grpc_rb_get_wrapped_channel_credentials(credentials);
ch = grpc_secure_channel_create(creds, target_chars, &args, NULL);
}
@@ -330,7 +325,6 @@ static VALUE grpc_rb_channel_destroy(VALUE self) {
if (ch != NULL) {
grpc_channel_destroy(ch);
wrapper->wrapped = NULL;
- wrapper->mark = Qnil;
}
return Qnil;
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 69827cea1c..2ffb8f41da 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 8c6fc3b7eb..10391bc963 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,8 +49,8 @@
static VALUE grpc_rb_cChannelCredentials = Qnil;
/* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a
- * peer ruby object, 'mark' to minimize copying when a credential is
- * created from ruby. */
+ * mark object that is used to hold references to any objects used to create
+ * the credentials. */
typedef struct grpc_rb_channel_credentials {
/* Holder of ruby objects involved in constructing the credentials */
VALUE mark;
@@ -66,13 +66,8 @@ static void grpc_rb_channel_credentials_free(void *p) {
return;
};
wrapper = (grpc_rb_channel_credentials *)p;
-
- /* Delete the wrapped object if the mark object is Qnil, which indicates that
- * no other object is the actual owner. */
- if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
- grpc_channel_credentials_release(wrapper->wrapped);
- wrapper->wrapped = NULL;
- }
+ grpc_channel_credentials_release(wrapper->wrapped);
+ wrapper->wrapped = NULL;
xfree(p);
}
@@ -85,7 +80,6 @@ static void grpc_rb_channel_credentials_mark(void *p) {
}
wrapper = (grpc_rb_channel_credentials *)p;
- /* If it's not already cleaned up, mark the mark object */
if (wrapper->mark != Qnil) {
rb_gc_mark(wrapper->mark);
}
@@ -114,7 +108,7 @@ static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) {
/* Creates a wrapping object for a given channel credentials. This should only
* be called with grpc_channel_credentials objects that are not already
* associated with any Ruby object. */
-VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) {
+VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c, VALUE mark) {
VALUE rb_wrapper;
grpc_rb_channel_credentials *wrapper;
if (c == NULL) {
@@ -124,6 +118,7 @@ VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) {
TypedData_Get_Struct(rb_wrapper, grpc_rb_channel_credentials,
&grpc_rb_channel_credentials_data_type, wrapper);
wrapper->wrapped = c;
+ wrapper->mark = mark;
return rb_wrapper;
}
@@ -222,11 +217,15 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
VALUE self) {
grpc_channel_credentials *creds;
grpc_call_credentials *other;
+ VALUE mark;
if (argc == 0) {
return self;
}
+ mark = rb_ary_new();
+ rb_ary_push(mark, self);
creds = grpc_rb_get_wrapped_channel_credentials(self);
for (int i = 0; i < argc; i++) {
+ rb_ary_push(mark, argv[i]);
other = grpc_rb_get_wrapped_call_credentials(argv[i]);
creds = grpc_composite_channel_credentials_create(creds, other, NULL);
if (creds == NULL) {
@@ -234,7 +233,7 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
"Failed to compose channel and call credentials");
}
}
- return grpc_rb_wrap_channel_credentials(creds);
+ return grpc_rb_wrap_channel_credentials(creds, mark);
}
void Init_grpc_channel_credentials() {
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 1eb5a28750..2a2eee190c 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 0f9b18fa21..acb47b0055 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 56db4ec686..e2068d752a 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -152,6 +152,7 @@ grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_crea
grpc_secure_channel_create_type grpc_secure_channel_create_import;
grpc_server_credentials_release_type grpc_server_credentials_release_import;
grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
+grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import;
grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
grpc_call_set_credentials_type grpc_call_set_credentials_import;
grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
@@ -174,6 +175,8 @@ grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
gpr_log_type gpr_log_import;
gpr_log_message_type gpr_log_message_import;
+gpr_set_log_verbosity_type gpr_set_log_verbosity_import;
+gpr_log_verbosity_init_type gpr_log_verbosity_init_import;
gpr_set_log_function_type gpr_set_log_function_import;
gpr_slice_ref_type gpr_slice_ref_import;
gpr_slice_unref_type gpr_slice_unref_import;
@@ -414,6 +417,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_secure_channel_create_import = (grpc_secure_channel_create_type) GetProcAddress(library, "grpc_secure_channel_create");
grpc_server_credentials_release_import = (grpc_server_credentials_release_type) GetProcAddress(library, "grpc_server_credentials_release");
grpc_ssl_server_credentials_create_import = (grpc_ssl_server_credentials_create_type) GetProcAddress(library, "grpc_ssl_server_credentials_create");
+ grpc_ssl_server_credentials_create_ex_import = (grpc_ssl_server_credentials_create_ex_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_ex");
grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port");
grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials");
grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor");
@@ -436,6 +440,8 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_raw_byte_buffer_from_reader_import = (grpc_raw_byte_buffer_from_reader_type) GetProcAddress(library, "grpc_raw_byte_buffer_from_reader");
gpr_log_import = (gpr_log_type) GetProcAddress(library, "gpr_log");
gpr_log_message_import = (gpr_log_message_type) GetProcAddress(library, "gpr_log_message");
+ gpr_set_log_verbosity_import = (gpr_set_log_verbosity_type) GetProcAddress(library, "gpr_set_log_verbosity");
+ gpr_log_verbosity_init_import = (gpr_log_verbosity_init_type) GetProcAddress(library, "gpr_log_verbosity_init");
gpr_set_log_function_import = (gpr_set_log_function_type) GetProcAddress(library, "gpr_set_log_function");
gpr_slice_ref_import = (gpr_slice_ref_type) GetProcAddress(library, "gpr_slice_ref");
gpr_slice_unref_import = (gpr_slice_unref_type) GetProcAddress(library, "gpr_slice_unref");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index b972f60fc3..c8d21333ba 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -166,7 +166,7 @@ extern grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_im
typedef int(*grpc_compression_algorithm_name_type)(grpc_compression_algorithm algorithm, char **name);
extern grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
#define grpc_compression_algorithm_name grpc_compression_algorithm_name_import
-typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level);
+typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level, uint32_t accepted_encodings);
extern grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
#define grpc_compression_algorithm_for_level grpc_compression_algorithm_for_level_import
typedef void(*grpc_compression_options_init_type)(grpc_compression_options *opts);
@@ -283,7 +283,7 @@ extern grpc_call_destroy_type grpc_call_destroy_import;
typedef grpc_call_error(*grpc_server_request_call_type)(grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *request_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
extern grpc_server_request_call_type grpc_server_request_call_import;
#define grpc_server_request_call grpc_server_request_call_import
-typedef void *(*grpc_server_register_method_type)(grpc_server *server, const char *method, const char *host);
+typedef void *(*grpc_server_register_method_type)(grpc_server *server, const char *method, const char *host, grpc_server_register_method_payload_handling payload_handling, uint32_t flags);
extern grpc_server_register_method_type grpc_server_register_method_import;
#define grpc_server_register_method grpc_server_register_method_import
typedef grpc_call_error(*grpc_server_request_registered_call_type)(grpc_server *server, void *registered_method, grpc_call **call, gpr_timespec *deadline, grpc_metadata_array *request_metadata, grpc_byte_buffer **optional_payload, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
@@ -406,6 +406,9 @@ extern grpc_server_credentials_release_type grpc_server_credentials_release_impo
typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved);
extern grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
#define grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_import
+typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_ex_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved);
+extern grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import;
+#define grpc_ssl_server_credentials_create_ex grpc_ssl_server_credentials_create_ex_import
typedef int(*grpc_server_add_secure_http2_port_type)(grpc_server *server, const char *addr, grpc_server_credentials *creds);
extern grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
#define grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port_import
@@ -472,6 +475,12 @@ extern gpr_log_type gpr_log_import;
typedef void(*gpr_log_message_type)(const char *file, int line, gpr_log_severity severity, const char *message);
extern gpr_log_message_type gpr_log_message_import;
#define gpr_log_message gpr_log_message_import
+typedef void(*gpr_set_log_verbosity_type)(gpr_log_severity min_severity_to_print);
+extern gpr_set_log_verbosity_type gpr_set_log_verbosity_import;
+#define gpr_set_log_verbosity gpr_set_log_verbosity_import
+typedef void(*gpr_log_verbosity_init_type)();
+extern gpr_log_verbosity_init_type gpr_log_verbosity_init_import;
+#define gpr_log_verbosity_init gpr_log_verbosity_init_import
typedef void(*gpr_set_log_function_type)(gpr_log_func func);
extern gpr_set_log_function_type gpr_set_log_function_import;
#define gpr_set_log_function gpr_set_log_function_import
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 37cc55a651..96e60c6776 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index 4ea59b6b27..b2d7280a30 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -90,9 +90,12 @@ static void grpc_rb_server_credentials_mark(void *p) {
static const rb_data_type_t grpc_rb_server_credentials_data_type = {
"grpc_server_credentials",
- {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free,
- GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
- NULL, NULL,
+ {grpc_rb_server_credentials_mark,
+ grpc_rb_server_credentials_free,
+ GRPC_RB_MEMSIZE_UNAVAILABLE,
+ {NULL, NULL}},
+ NULL,
+ NULL,
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
RUBY_TYPED_FREE_IMMEDIATELY
#endif
@@ -219,7 +222,9 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
}
}
- auth_client = TYPE(force_client_auth) == T_TRUE;
+ auth_client = TYPE(force_client_auth) == T_TRUE
+ ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+ : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
key_cert_pairs = ALLOC_N(grpc_ssl_pem_key_cert_pair, num_key_certs);
for (i = 0; i < num_key_certs; i++) {
key_cert = rb_ary_entry(pem_key_certs, i);
@@ -233,13 +238,12 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
&grpc_rb_server_credentials_data_type, wrapper);
if (pem_root_certs == Qnil) {
- creds = grpc_ssl_server_credentials_create(NULL, key_cert_pairs,
- num_key_certs,
- auth_client, NULL);
+ creds = grpc_ssl_server_credentials_create_ex(
+ NULL, key_cert_pairs, num_key_certs, auth_client, NULL);
} else {
- creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs),
- key_cert_pairs, num_key_certs,
- auth_client, NULL);
+ creds = grpc_ssl_server_credentials_create_ex(RSTRING_PTR(pem_root_certs),
+ key_cert_pairs, num_key_certs,
+ auth_client, NULL);
}
xfree(key_cert_pairs);
if (creds == NULL) {
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index 1671ba3550..a56c49ff59 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,13 @@ unless ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH']
ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = ssl_roots_path
end
-require 'grpc/errors'
-require 'grpc/grpc'
-require 'grpc/logconfig'
-require 'grpc/notifier'
-require 'grpc/version'
-require 'grpc/core/time_consts'
-require 'grpc/generic/active_call'
-require 'grpc/generic/client_stub'
-require 'grpc/generic/service'
-require 'grpc/generic/rpc_server'
+require_relative 'grpc/errors'
+require_relative 'grpc/grpc'
+require_relative 'grpc/logconfig'
+require_relative 'grpc/notifier'
+require_relative 'grpc/version'
+require_relative 'grpc/core/time_consts'
+require_relative 'grpc/generic/active_call'
+require_relative 'grpc/generic/client_stub'
+require_relative 'grpc/generic/service'
+require_relative 'grpc/generic/rpc_server'
diff --git a/src/ruby/lib/grpc/core/time_consts.rb b/src/ruby/lib/grpc/core/time_consts.rb
index c8eae7806b..5be7ed2cb7 100644
--- a/src/ruby/lib/grpc/core/time_consts.rb
+++ b/src/ruby/lib/grpc/core/time_consts.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc/grpc'
+require_relative '../grpc'
# GRPC contains the General RPC module.
module GRPC
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 2227ee1f12..a1dd1e3e9d 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc/grpc'
+require_relative './grpc'
# GRPC contains the General RPC module.
module GRPC
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index e80d24edc9..ecf3cc3293 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'forwardable'
-require 'grpc/generic/bidi_call'
+require_relative 'bidi_call'
class Struct
# BatchResult is the struct returned by calls to call#start_batch.
@@ -59,7 +59,8 @@ module GRPC
include Core::CallOps
extend Forwardable
attr_reader(:deadline)
- def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=
+ def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=,
+ :peer, :peer_cert
# client_invoke begins a client invocation.
#
@@ -472,7 +473,7 @@ module GRPC
# SingleReqView limits access to an ActiveCall's methods for use in server
# handlers that receive just one request.
SingleReqView = view_class(:cancelled, :deadline, :metadata,
- :output_metadata)
+ :output_metadata, :peer, :peer_cert)
# MultiReqView limits access to an ActiveCall's methods for use in
# server client_streamer handlers.
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 213176bd48..1f6d5f365d 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'forwardable'
-require 'grpc/grpc'
+require_relative '../grpc'
# GRPC contains the General RPC module.
module GRPC
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 4da9ff086a..68e167a69f 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,8 +27,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.
-require 'grpc/generic/active_call'
-require 'grpc/version'
+require_relative 'active_call'
+require_relative '../version'
# GRPC contains the General RPC module.
module GRPC
@@ -85,7 +85,8 @@ module GRPC
# when present, this is the default timeout used for calls
#
# @param host [String] the host the stub connects to
- # @param q [Core::CompletionQueue] used to wait for events
+ # @param q [Core::CompletionQueue] used to wait for events - now deprecated
+ # since each new active call gets its own separately
# @param creds [Core::ChannelCredentials|Symbol] the channel credentials, or
# :this_channel_is_insecure
# @param channel_override [Core::Channel] a pre-created channel
@@ -97,7 +98,6 @@ module GRPC
propagate_mask: nil,
**kw)
fail(TypeError, '!CompletionQueue') unless q.is_a?(Core::CompletionQueue)
- @queue = q
@ch = ClientStub.setup_channel(channel_override, host, creds, **kw)
alt_host = kw[Core::Channel::SSL_TARGET]
@host = alt_host.nil? ? host : alt_host
@@ -458,14 +458,17 @@ module GRPC
if deadline.nil?
deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
end
- call = @ch.create_call(@queue,
+ # Provide each new client call with its own completion queue
+ call_queue = Core::CompletionQueue.new
+ call = @ch.create_call(call_queue,
parent, # parent call
@propagate_mask, # propagation options
method,
nil, # host use nil,
deadline)
call.set_credentials! credentials unless credentials.nil?
- ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false)
+ ActiveCall.new(call, call_queue, marshal, unmarshal, deadline,
+ started: false)
end
end
end
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 526b2ba5b6..cc21ffd3c5 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc/grpc'
+require_relative '../grpc'
# GRPC contains the General RPC module.
module GRPC
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index b30d19dd2b..7f3a38a9f4 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,9 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc/grpc'
-require 'grpc/generic/active_call'
-require 'grpc/generic/service'
+require_relative '../grpc'
+require_relative 'active_call'
+require_relative 'service'
require 'thread'
# A global that contains signals the gRPC servers should respond to.
@@ -332,10 +332,15 @@ module GRPC
# the current thread to terminate it.
def run_till_terminated
GRPC.trap_signals
- t = Thread.new { run }
+ stopped = false
+ t = Thread.new do
+ run
+ stopped = true
+ end
wait_till_running
loop do
sleep SIGNAL_CHECK_PERIOD
+ break if stopped
break unless GRPC.handle_signals
end
stop
@@ -403,7 +408,7 @@ module GRPC
loop_handle_server_calls
end
- # Sends UNAVAILABLE if there are too many unprocessed jobs
+ # Sends RESOURCE_EXHAUSTED if there are too many unprocessed jobs
def available?(an_rpc)
jobs_count, max = @pool.jobs_waiting, @max_waiting_requests
GRPC.logger.info("waiting: #{jobs_count}, max: #{max}")
@@ -411,7 +416,7 @@ module GRPC
GRPC.logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
noop = proc { |x| x }
c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
- c.send_status(StatusCodes::UNAVAILABLE, '')
+ c.send_status(StatusCodes::RESOURCE_EXHAUSTED, '')
nil
end
@@ -434,7 +439,6 @@ module GRPC
begin
an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE)
break if (!an_rpc.nil?) && an_rpc.call.nil?
-
active_call = new_active_server_call(an_rpc)
unless active_call.nil?
@pool.schedule(active_call) do |ac|
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 410e1add7d..8e940b5b13 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -27,8 +27,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.
-require 'grpc/generic/client_stub'
-require 'grpc/generic/rpc_desc'
+require_relative 'client_stub'
+require_relative 'rpc_desc'
# GRPC contains the General RPC module.
module GRPC
diff --git a/src/ruby/lib/grpc/grpc.rb b/src/ruby/lib/grpc/grpc.rb
index d8a4947494..b60a828d66 100644
--- a/src/ruby/lib/grpc/grpc.rb
+++ b/src/ruby/lib/grpc/grpc.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
begin
- require "grpc/#{RUBY_VERSION.sub(/\.\d$/, '')}/grpc_c"
+ require_relative "#{RUBY_VERSION.sub(/\.\d$/, '')}/grpc_c"
rescue LoadError
- require 'grpc/grpc_c'
+ require_relative 'grpc_c'
end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index ef0876159d..67c6a5d5a1 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/pb/generate_proto_ruby.sh b/src/ruby/pb/generate_proto_ruby.sh
index 86c082099d..82dad18ad0 100755
--- a/src/ruby/pb/generate_proto_ruby.sh
+++ b/src/ruby/pb/generate_proto_ruby.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -40,11 +40,18 @@ $PROTOC -I src/proto src/proto/grpc/health/v1/health.proto \
--ruby_out=src/ruby/pb \
--plugin=$PLUGIN
-$PROTOC -I . test/proto/{messages,test,empty}.proto \
+$PROTOC -I . \
+ src/proto/grpc/testing/{messages,test,empty}.proto \
--grpc_out=src/ruby/pb \
--ruby_out=src/ruby/pb \
--plugin=$PLUGIN
+$PROTOC -I . \
+ src/proto/grpc/testing/{messages,payloads,stats,services,control}.proto \
+ --grpc_out=src/ruby/qps \
+ --ruby_out=src/ruby/qps \
+ --plugin=$PLUGIN
+
$PROTOC -I src/proto/math src/proto/math/math.proto \
--grpc_out=src/ruby/bin \
--ruby_out=src/ruby/bin \
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index 9f1ee65c41..f7310d9289 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
new file mode 100644
index 0000000000..9f6e7e0e42
--- /dev/null
+++ b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
@@ -0,0 +1,28 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: src/proto/grpc/testing/duplicate/echo_duplicate.proto for package 'grpc.testing.duplicate'
+
+require 'grpc'
+require 'src/proto/grpc/testing/duplicate/echo_duplicate'
+
+module Grpc
+ module Testing
+ module Duplicate
+ module EchoTestService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.duplicate.EchoTestService'
+
+ rpc :Echo, Grpc::Testing::EchoRequest, Grpc::Testing::EchoResponse
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+ end
+end
diff --git a/src/ruby/pb/grpc/testing/metrics.rb b/src/ruby/pb/grpc/testing/metrics.rb
new file mode 100644
index 0000000000..3b3c8cd61b
--- /dev/null
+++ b/src/ruby/pb/grpc/testing/metrics.rb
@@ -0,0 +1,28 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: grpc/testing/metrics.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.GaugeResponse" do
+ optional :name, :string, 1
+ oneof :value do
+ optional :long_value, :int64, 2
+ optional :double_value, :double, 3
+ optional :string_value, :string, 4
+ end
+ end
+ add_message "grpc.testing.GaugeRequest" do
+ optional :name, :string, 1
+ end
+ add_message "grpc.testing.EmptyMessage" do
+ end
+end
+
+module Grpc
+ module Testing
+ GaugeResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeResponse").msgclass
+ GaugeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeRequest").msgclass
+ EmptyMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EmptyMessage").msgclass
+ end
+end
diff --git a/src/ruby/pb/grpc/testing/metrics_services.rb b/src/ruby/pb/grpc/testing/metrics_services.rb
new file mode 100644
index 0000000000..f5778bbbb1
--- /dev/null
+++ b/src/ruby/pb/grpc/testing/metrics_services.rb
@@ -0,0 +1,27 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: grpc/testing/metrics.proto for package 'grpc.testing'
+
+require 'grpc'
+require 'grpc/testing/metrics'
+
+module Grpc
+ module Testing
+ module MetricsService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.MetricsService'
+
+ rpc :GetAllGauges, EmptyMessage, stream(GaugeResponse)
+ rpc :GetGauge, GaugeRequest, GaugeResponse
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 684ee80771..95b059a18e 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -38,23 +38,23 @@
# --server_port=<port> \
# --test_case=<testcase_name>
+# These lines are required for the generated files to load grpc
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-pb_dir = File.dirname(File.dirname(this_dir))
+pb_dir = File.dirname(this_dir)
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
require 'optparse'
require 'logger'
-require 'grpc'
+require_relative '../../lib/grpc'
require 'googleauth'
require 'google/protobuf'
-require 'test/proto/empty'
-require 'test/proto/messages'
-require 'test/proto/test_services'
+require_relative 'proto/empty'
+require_relative 'proto/messages'
+require_relative 'proto/test_services'
AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
@@ -208,12 +208,10 @@ class NamedTests
def empty_unary
resp = @stub.empty_call(Empty.new)
assert('empty_unary: invalid response') { resp.is_a?(Empty) }
- p 'OK: empty_unary'
end
def large_unary
perform_large_unary
- p 'OK: large_unary'
end
def service_account_creds
@@ -230,7 +228,6 @@ class NamedTests
assert("#{__callee__}: bad oauth scope") do
@args.oauth_scope.include?(resp.oauth_scope)
end
- p "OK: #{__callee__}"
end
def jwt_token_creds
@@ -238,7 +235,6 @@ class NamedTests
wanted_email = MultiJson.load(json_key)['client_email']
resp = perform_large_unary(fill_username: true)
assert("#{__callee__}: bad username") { wanted_email == resp.username }
- p "OK: #{__callee__}"
end
def compute_engine_creds
@@ -247,7 +243,6 @@ class NamedTests
assert("#{__callee__}: bad username") do
@args.default_service_account == resp.username
end
- p "OK: #{__callee__}"
end
def oauth2_auth_token
@@ -259,7 +254,6 @@ class NamedTests
assert("#{__callee__}: bad oauth scope") do
@args.oauth_scope.include?(resp.oauth_scope)
end
- p "OK: #{__callee__}"
end
def per_rpc_creds
@@ -279,7 +273,6 @@ class NamedTests
assert("#{__callee__}: bad oauth scope") do
@args.oauth_scope.include?(resp.oauth_scope)
end
- p "OK: #{__callee__}"
end
def client_streaming
@@ -293,7 +286,6 @@ class NamedTests
assert("#{__callee__}: aggregate payload size is incorrect") do
wanted_aggregate_size == resp.aggregated_payload_size
end
- p "OK: #{__callee__}"
end
def server_streaming
@@ -311,7 +303,6 @@ class NamedTests
:COMPRESSABLE == r.payload.type
end
end
- p "OK: #{__callee__}"
end
def ping_pong
@@ -319,7 +310,6 @@ class NamedTests
ppp = PingPongPlayer.new(msg_sizes)
resps = @stub.full_duplex_call(ppp.each_item)
resps.each { |r| ppp.queue.push(r) }
- p "OK: #{__callee__}"
end
def timeout_on_sleeping_server
@@ -332,7 +322,6 @@ class NamedTests
assert("#{__callee__}: status was wrong") do
e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
end
- p "OK: #{__callee__}"
end
def empty_stream
@@ -346,7 +335,6 @@ class NamedTests
assert("#{__callee__}: too many responses expected 0") do
count == 0
end
- p "OK: #{__callee__}"
end
def cancel_after_begin
@@ -361,7 +349,6 @@ class NamedTests
fail 'Should have raised GRPC:Cancelled'
rescue GRPC::Cancelled
assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
- p "OK: #{__callee__}"
end
def cancel_after_first_response
@@ -374,7 +361,6 @@ class NamedTests
rescue GRPC::Cancelled
assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
op.wait
- p "OK: #{__callee__}"
end
def all
@@ -442,7 +428,7 @@ def parse_args
opts.on('--use_tls USE_TLS', ['false', 'true'],
'require a secure connection?') do |v|
args['secure'] = v == 'true'
- end
+p end
opts.on('--use_test_ca USE_TEST_CA', ['false', 'true'],
'if secure, use the test certificate?') do |v|
args['use_test_ca'] = v == 'true'
@@ -464,6 +450,9 @@ def main
opts = parse_args
stub = create_stub(opts)
NamedTests.new(stub, opts).method(opts['test_case']).call
+ p "OK: #{opts['test_case']}"
end
-main
+if __FILE__ == $0
+ main
+end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 851e815222..914c7cc79d 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -39,7 +39,7 @@
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-pb_dir = File.dirname(File.dirname(this_dir))
+pb_dir = File.dirname(this_dir)
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
diff --git a/src/ruby/qps/client.rb b/src/ruby/qps/client.rb
new file mode 100644
index 0000000000..d04f707479
--- /dev/null
+++ b/src/ruby/qps/client.rb
@@ -0,0 +1,164 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Worker and worker service implementation
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'grpc'
+require 'histogram'
+require 'src/proto/grpc/testing/services_services'
+
+class Poisson
+ def interarrival
+ @lambda_recip * (-Math.log(1.0-rand))
+ end
+ def advance
+ t = @next_time
+ @next_time += interarrival
+ t
+ end
+ def initialize(lambda)
+ @lambda_recip = 1.0/lambda
+ @next_time = Time.now + interarrival
+ end
+end
+
+class BenchmarkClient
+ def initialize(config)
+ opts = {}
+ if config.security_params
+ if config.security_params.use_test_ca
+ certs = load_test_certs
+ cred = GRPC::Core::ChannelCredentials.new(certs[0])
+ else
+ cred = GRPC::Core::ChannelCredentials.new()
+ end
+ if config.security_params.server_host_override
+ opts[GRPC::Core::Channel::SSL_TARGET] =
+ config.security_params.server_host_override
+ end
+ else
+ cred = :this_channel_is_insecure
+ end
+ @histres = config.histogram_params.resolution
+ @histmax = config.histogram_params.max_possible
+ @start_time = Time.now
+ @histogram = Histogram.new(@histres, @histmax)
+ @done = false
+
+ gtsr = Grpc::Testing::SimpleRequest
+ gtpt = Grpc::Testing::PayloadType
+ gtp = Grpc::Testing::Payload
+ simple_params = config.payload_config.simple_params
+ req = gtsr.new(response_type: gtpt::COMPRESSABLE,
+ response_size: simple_params.resp_size,
+ payload: gtp.new(type: gtpt::COMPRESSABLE,
+ body: nulls(simple_params.req_size)))
+
+ (0..config.client_channels-1).each do |chan|
+ gtbss = Grpc::Testing::BenchmarkService::Stub
+ st = config.server_targets
+ stub = gtbss.new(st[chan % st.length], cred, **opts)
+ (0..config.outstanding_rpcs_per_channel-1).each do |r|
+ Thread.new {
+ case config.load_params.load.to_s
+ when 'closed_loop'
+ waiter = nil
+ when 'poisson'
+ waiter = Poisson.new(config.load_params.poisson.offered_load /
+ (config.client_channels *
+ config.outstanding_rpcs_per_channel))
+ end
+ case config.rpc_type
+ when :UNARY
+ unary_ping_ponger(req,stub,config,waiter)
+ when :STREAMING
+ streaming_ping_ponger(req,stub,config,waiter)
+ end
+ }
+ end
+ end
+ end
+ def wait_to_issue(waiter)
+ if waiter
+ delay = waiter.advance-Time.now
+ sleep delay if delay > 0
+ end
+ end
+ def unary_ping_ponger(req, stub, config,waiter)
+ while !@done
+ wait_to_issue(waiter)
+ start = Time.now
+ resp = stub.unary_call(req)
+ @histogram.add((Time.now-start)*1e9)
+ end
+ end
+ def streaming_ping_ponger(req, stub, config, waiter)
+ q = EnumeratorQueue.new(self)
+ resp = stub.streaming_call(q.each_item)
+ start = Time.now
+ q.push(req)
+ resp.each do |r|
+ @histogram.add((Time.now-start)*1e9)
+ if !@done
+ wait_to_issue(waiter)
+ start = Time.now
+ q.push(req)
+ else
+ q.push(self)
+ break
+ end
+ end
+ end
+ def mark(reset)
+ lat = Grpc::Testing::HistogramData.new(
+ bucket: @histogram.contents,
+ min_seen: @histogram.minimum,
+ max_seen: @histogram.maximum,
+ sum: @histogram.sum,
+ sum_of_squares: @histogram.sum_of_squares,
+ count: @histogram.count
+ )
+ elapsed = Time.now-@start_time
+ if reset
+ @start_time = Time.now
+ @histogram = Histogram.new(@histres, @histmax)
+ end
+ Grpc::Testing::ClientStats.new(latencies: lat, time_elapsed: elapsed)
+ end
+ def shutdown
+ @done = true
+ end
+end
diff --git a/src/ruby/bin/grpc_ruby_interop_client b/src/ruby/qps/histogram.rb
index e79fd33aa5..bf7a89ac46 100755..100644
--- a/src/ruby/bin/grpc_ruby_interop_client
+++ b/src/ruby/qps/histogram.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -29,5 +29,60 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Provides a gem binary entry point for the interop client.
-require 'test/client'
+# Histogram class for use in performance testing and measurement
+
+class Histogram
+ # Determine the bucket index for a given value
+ # @param {number} value The value to check
+ # @return {number} The bucket index
+ def bucket_for(value)
+ (Math.log(value)/Math.log(@multiplier)).to_i
+ end
+ # Initialize an empty histogram
+ # @param {number} resolution The resolution of the histogram
+ # @param {number} max_possible The maximum value for the histogram
+ def initialize(resolution, max_possible)
+ @resolution=resolution
+ @max_possible=max_possible
+ @sum=0
+ @sum_of_squares=0
+ @multiplier=1+resolution
+ @count=0
+ @min_seen=max_possible
+ @max_seen=0
+ @buckets=Array.new(bucket_for(max_possible)+1, 0)
+ end
+ # Add a value to the histogram. This updates all statistics with the new
+ # value. Those statistics should not be modified except with this function
+ # @param {number} value The value to add
+ def add(value)
+ @sum += value
+ @sum_of_squares += value * value
+ @count += 1
+ if value < @min_seen
+ @min_seen = value
+ end
+ if value > @max_seen
+ @max_seen = value
+ end
+ @buckets[bucket_for(value)] += 1
+ end
+ def minimum
+ @min_seen
+ end
+ def maximum
+ @max_seen
+ end
+ def sum
+ @sum
+ end
+ def sum_of_squares
+ @sum_of_squares
+ end
+ def count
+ @count
+ end
+ def contents
+ @buckets
+ end
+end
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/qps/qps-common.rb
index c6b0d00ec6..4119d600b1 100755..100644
--- a/src/ruby/bin/interop/interop_server.rb
+++ b/src/ruby/qps/qps-common.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -29,22 +29,48 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# #######################################################################
-# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb
-#
-# This file remains to support existing tools and scripts that use it.
-# ######################################################################
-#
-# interop_server is a Testing app that runs a gRPC interop testing server.
-#
-# It helps validate interoperation b/w gRPC in different environments
-#
-# Helps validate interoperation b/w different gRPC implementations.
-#
-# Usage: $ path/to/interop_server.rb --port
+# Worker and worker service implementation
this_dir = File.expand_path(File.dirname(__FILE__))
-pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
-$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'grpc'
+
+# produces a string of null chars (\0 aka pack 'x') of length l.
+def nulls(l)
+ fail 'requires #{l} to be +ve' if l < 0
+ [].pack('x' * l).force_encoding('ascii-8bit')
+end
+
+# load the test-only certificates
+def load_test_certs
+ this_dir = File.expand_path(File.dirname(__FILE__))
+ data_dir = File.join(File.dirname(this_dir), 'spec/testdata')
+ files = ['ca.pem', 'server1.key', 'server1.pem']
+ files.map { |f| File.open(File.join(data_dir, f)).read }
+end
+
+# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
+class EnumeratorQueue
+ extend Forwardable
+ def_delegators :@q, :push
+
+ def initialize(sentinel)
+ @q = Queue.new
+ @sentinel = sentinel
+ end
+
+ def each_item
+ return enum_for(:each_item) unless block_given?
+ loop do
+ r = @q.pop
+ break if r.equal?(@sentinel)
+ fail r if r.is_a? Exception
+ yield r
+ end
+ end
+end
+
-require 'test/server'
diff --git a/src/ruby/qps/server.rb b/src/ruby/qps/server.rb
new file mode 100644
index 0000000000..f05fbbdaaf
--- /dev/null
+++ b/src/ruby/qps/server.rb
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Worker and worker service implementation
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'grpc'
+require 'qps-common'
+require 'src/proto/grpc/testing/messages'
+require 'src/proto/grpc/testing/services_services'
+require 'src/proto/grpc/testing/stats'
+
+class BenchmarkServiceImpl < Grpc::Testing::BenchmarkService::Service
+ def unary_call(req, _call)
+ sr = Grpc::Testing::SimpleResponse
+ pl = Grpc::Testing::Payload
+ sr.new(payload: pl.new(body: nulls(req.response_size)))
+ end
+ def streaming_call(reqs)
+ q = EnumeratorQueue.new(self)
+ Thread.new {
+ sr = Grpc::Testing::SimpleResponse
+ pl = Grpc::Testing::Payload
+ reqs.each do |req|
+ q.push(sr.new(payload: pl.new(body: nulls(req.response_size))))
+ end
+ q.push(self)
+ }
+ q.each_item
+ end
+end
+
+class BenchmarkServer
+ def initialize(config, port)
+ if config.security_params
+ certs = load_test_certs
+ cred = GRPC::Core::ServerCredentials.new(
+ nil, [{private_key: certs[1], cert_chain: certs[2]}], false)
+ else
+ cred = :this_port_is_insecure
+ end
+ @server = GRPC::RpcServer.new
+ @port = @server.add_http2_port("0.0.0.0:" + port.to_s, cred)
+ @server.handle(BenchmarkServiceImpl.new)
+ @start_time = Time.now
+ Thread.new {
+ @server.run
+ }
+ end
+ def mark(reset)
+ s = Grpc::Testing::ServerStats.new(time_elapsed:
+ (Time.now-@start_time).to_f)
+ @start_time = Time.now if reset
+ s
+ end
+ def get_port
+ @port
+ end
+ def stop
+ @server.stop
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/control.rb b/src/ruby/qps/src/proto/grpc/testing/control.rb
new file mode 100644
index 0000000000..958fca320b
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/control.rb
@@ -0,0 +1,154 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/control.proto
+
+require 'google/protobuf'
+
+require 'src/proto/grpc/testing/payloads'
+require 'src/proto/grpc/testing/stats'
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.PoissonParams" do
+ optional :offered_load, :double, 1
+ end
+ add_message "grpc.testing.ClosedLoopParams" do
+ end
+ add_message "grpc.testing.LoadParams" do
+ oneof :load do
+ optional :closed_loop, :message, 1, "grpc.testing.ClosedLoopParams"
+ optional :poisson, :message, 2, "grpc.testing.PoissonParams"
+ end
+ end
+ add_message "grpc.testing.SecurityParams" do
+ optional :use_test_ca, :bool, 1
+ optional :server_host_override, :string, 2
+ end
+ add_message "grpc.testing.ClientConfig" do
+ repeated :server_targets, :string, 1
+ optional :client_type, :enum, 2, "grpc.testing.ClientType"
+ optional :security_params, :message, 3, "grpc.testing.SecurityParams"
+ optional :outstanding_rpcs_per_channel, :int32, 4
+ optional :client_channels, :int32, 5
+ optional :async_client_threads, :int32, 7
+ optional :rpc_type, :enum, 8, "grpc.testing.RpcType"
+ optional :load_params, :message, 10, "grpc.testing.LoadParams"
+ optional :payload_config, :message, 11, "grpc.testing.PayloadConfig"
+ optional :histogram_params, :message, 12, "grpc.testing.HistogramParams"
+ repeated :core_list, :int32, 13
+ optional :core_limit, :int32, 14
+ optional :other_client_api, :string, 15
+ end
+ add_message "grpc.testing.ClientStatus" do
+ optional :stats, :message, 1, "grpc.testing.ClientStats"
+ end
+ add_message "grpc.testing.Mark" do
+ optional :reset, :bool, 1
+ end
+ add_message "grpc.testing.ClientArgs" do
+ oneof :argtype do
+ optional :setup, :message, 1, "grpc.testing.ClientConfig"
+ optional :mark, :message, 2, "grpc.testing.Mark"
+ end
+ end
+ add_message "grpc.testing.ServerConfig" do
+ optional :server_type, :enum, 1, "grpc.testing.ServerType"
+ optional :security_params, :message, 2, "grpc.testing.SecurityParams"
+ optional :port, :int32, 4
+ optional :async_server_threads, :int32, 7
+ optional :core_limit, :int32, 8
+ optional :payload_config, :message, 9, "grpc.testing.PayloadConfig"
+ repeated :core_list, :int32, 10
+ optional :other_server_api, :string, 11
+ end
+ add_message "grpc.testing.ServerArgs" do
+ oneof :argtype do
+ optional :setup, :message, 1, "grpc.testing.ServerConfig"
+ optional :mark, :message, 2, "grpc.testing.Mark"
+ end
+ end
+ add_message "grpc.testing.ServerStatus" do
+ optional :stats, :message, 1, "grpc.testing.ServerStats"
+ optional :port, :int32, 2
+ optional :cores, :int32, 3
+ end
+ add_message "grpc.testing.CoreRequest" do
+ end
+ add_message "grpc.testing.CoreResponse" do
+ optional :cores, :int32, 1
+ end
+ add_message "grpc.testing.Void" do
+ end
+ add_message "grpc.testing.Scenario" do
+ optional :name, :string, 1
+ optional :client_config, :message, 2, "grpc.testing.ClientConfig"
+ optional :num_clients, :int32, 3
+ optional :server_config, :message, 4, "grpc.testing.ServerConfig"
+ optional :num_servers, :int32, 5
+ optional :warmup_seconds, :int32, 6
+ optional :benchmark_seconds, :int32, 7
+ optional :spawn_local_worker_count, :int32, 8
+ end
+ add_message "grpc.testing.Scenarios" do
+ repeated :scenarios, :message, 1, "grpc.testing.Scenario"
+ end
+ add_message "grpc.testing.ScenarioResultSummary" do
+ optional :qps, :double, 1
+ optional :qps_per_server_core, :double, 2
+ optional :server_system_time, :double, 3
+ optional :server_user_time, :double, 4
+ optional :client_system_time, :double, 5
+ optional :client_user_time, :double, 6
+ optional :latency_50, :double, 7
+ optional :latency_90, :double, 8
+ optional :latency_95, :double, 9
+ optional :latency_99, :double, 10
+ optional :latency_999, :double, 11
+ end
+ add_message "grpc.testing.ScenarioResult" do
+ optional :scenario, :message, 1, "grpc.testing.Scenario"
+ optional :latencies, :message, 2, "grpc.testing.HistogramData"
+ repeated :client_stats, :message, 3, "grpc.testing.ClientStats"
+ repeated :server_stats, :message, 4, "grpc.testing.ServerStats"
+ repeated :server_cores, :int32, 5
+ optional :summary, :message, 6, "grpc.testing.ScenarioResultSummary"
+ end
+ add_enum "grpc.testing.ClientType" do
+ value :SYNC_CLIENT, 0
+ value :ASYNC_CLIENT, 1
+ value :OTHER_CLIENT, 2
+ end
+ add_enum "grpc.testing.ServerType" do
+ value :SYNC_SERVER, 0
+ value :ASYNC_SERVER, 1
+ value :ASYNC_GENERIC_SERVER, 2
+ value :OTHER_SERVER, 3
+ end
+ add_enum "grpc.testing.RpcType" do
+ value :UNARY, 0
+ value :STREAMING, 1
+ end
+end
+
+module Grpc
+ module Testing
+ PoissonParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PoissonParams").msgclass
+ ClosedLoopParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClosedLoopParams").msgclass
+ LoadParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadParams").msgclass
+ SecurityParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SecurityParams").msgclass
+ ClientConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClientConfig").msgclass
+ ClientStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClientStatus").msgclass
+ Mark = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Mark").msgclass
+ ClientArgs = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClientArgs").msgclass
+ ServerConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ServerConfig").msgclass
+ ServerArgs = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ServerArgs").msgclass
+ ServerStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ServerStatus").msgclass
+ CoreRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CoreRequest").msgclass
+ CoreResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CoreResponse").msgclass
+ Void = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Void").msgclass
+ Scenario = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Scenario").msgclass
+ Scenarios = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Scenarios").msgclass
+ ScenarioResultSummary = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ScenarioResultSummary").msgclass
+ ScenarioResult = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ScenarioResult").msgclass
+ ClientType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClientType").enummodule
+ ServerType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ServerType").enummodule
+ RpcType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.RpcType").enummodule
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/messages.rb b/src/ruby/qps/src/proto/grpc/testing/messages.rb
new file mode 100644
index 0000000000..2bdfe0eade
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/messages.rb
@@ -0,0 +1,84 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/messages.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.Payload" do
+ optional :type, :enum, 1, "grpc.testing.PayloadType"
+ optional :body, :bytes, 2
+ end
+ add_message "grpc.testing.EchoStatus" do
+ optional :code, :int32, 1
+ optional :message, :string, 2
+ end
+ add_message "grpc.testing.SimpleRequest" do
+ optional :response_type, :enum, 1, "grpc.testing.PayloadType"
+ optional :response_size, :int32, 2
+ optional :payload, :message, 3, "grpc.testing.Payload"
+ optional :fill_username, :bool, 4
+ optional :fill_oauth_scope, :bool, 5
+ optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+ optional :response_status, :message, 7, "grpc.testing.EchoStatus"
+ end
+ add_message "grpc.testing.SimpleResponse" do
+ optional :payload, :message, 1, "grpc.testing.Payload"
+ optional :username, :string, 2
+ optional :oauth_scope, :string, 3
+ end
+ add_message "grpc.testing.StreamingInputCallRequest" do
+ optional :payload, :message, 1, "grpc.testing.Payload"
+ end
+ add_message "grpc.testing.StreamingInputCallResponse" do
+ optional :aggregated_payload_size, :int32, 1
+ end
+ add_message "grpc.testing.ResponseParameters" do
+ optional :size, :int32, 1
+ optional :interval_us, :int32, 2
+ end
+ add_message "grpc.testing.StreamingOutputCallRequest" do
+ optional :response_type, :enum, 1, "grpc.testing.PayloadType"
+ repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
+ optional :payload, :message, 3, "grpc.testing.Payload"
+ optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+ optional :response_status, :message, 7, "grpc.testing.EchoStatus"
+ end
+ add_message "grpc.testing.StreamingOutputCallResponse" do
+ optional :payload, :message, 1, "grpc.testing.Payload"
+ end
+ add_message "grpc.testing.ReconnectParams" do
+ optional :max_reconnect_backoff_ms, :int32, 1
+ end
+ add_message "grpc.testing.ReconnectInfo" do
+ optional :passed, :bool, 1
+ repeated :backoff_ms, :int32, 2
+ end
+ add_enum "grpc.testing.PayloadType" do
+ value :COMPRESSABLE, 0
+ value :UNCOMPRESSABLE, 1
+ value :RANDOM, 2
+ end
+ add_enum "grpc.testing.CompressionType" do
+ value :NONE, 0
+ value :GZIP, 1
+ value :DEFLATE, 2
+ end
+end
+
+module Grpc
+ module Testing
+ Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
+ EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
+ SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
+ SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass
+ StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass
+ StreamingInputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallResponse").msgclass
+ ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass
+ StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass
+ StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
+ ReconnectParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectParams").msgclass
+ ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
+ PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
+ CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/payloads.rb b/src/ruby/qps/src/proto/grpc/testing/payloads.rb
new file mode 100644
index 0000000000..ae8855f685
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/payloads.rb
@@ -0,0 +1,33 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/payloads.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.ByteBufferParams" do
+ optional :req_size, :int32, 1
+ optional :resp_size, :int32, 2
+ end
+ add_message "grpc.testing.SimpleProtoParams" do
+ optional :req_size, :int32, 1
+ optional :resp_size, :int32, 2
+ end
+ add_message "grpc.testing.ComplexProtoParams" do
+ end
+ add_message "grpc.testing.PayloadConfig" do
+ oneof :payload do
+ optional :bytebuf_params, :message, 1, "grpc.testing.ByteBufferParams"
+ optional :simple_params, :message, 2, "grpc.testing.SimpleProtoParams"
+ optional :complex_params, :message, 3, "grpc.testing.ComplexProtoParams"
+ end
+ end
+end
+
+module Grpc
+ module Testing
+ ByteBufferParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ByteBufferParams").msgclass
+ SimpleProtoParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleProtoParams").msgclass
+ ComplexProtoParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ComplexProtoParams").msgclass
+ PayloadConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadConfig").msgclass
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/services.rb b/src/ruby/qps/src/proto/grpc/testing/services.rb
new file mode 100644
index 0000000000..b2675c2afe
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/services.rb
@@ -0,0 +1,14 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/services.proto
+
+require 'google/protobuf'
+
+require 'src/proto/grpc/testing/messages'
+require 'src/proto/grpc/testing/control'
+Google::Protobuf::DescriptorPool.generated_pool.build do
+end
+
+module Grpc
+ module Testing
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/services_services.rb b/src/ruby/qps/src/proto/grpc/testing/services_services.rb
new file mode 100644
index 0000000000..3fd9f20f47
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/services_services.rb
@@ -0,0 +1,46 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# Source: src/proto/grpc/testing/services.proto for package 'grpc.testing'
+
+require 'grpc'
+require 'src/proto/grpc/testing/services'
+
+module Grpc
+ module Testing
+ module BenchmarkService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.BenchmarkService'
+
+ rpc :UnaryCall, SimpleRequest, SimpleResponse
+ rpc :StreamingCall, stream(SimpleRequest), stream(SimpleResponse)
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ module WorkerService
+
+ # TODO: add proto service documentation here
+ class Service
+
+ include GRPC::GenericService
+
+ self.marshal_class_method = :encode
+ self.unmarshal_class_method = :decode
+ self.service_name = 'grpc.testing.WorkerService'
+
+ rpc :RunServer, stream(ServerArgs), stream(ServerStatus)
+ rpc :RunClient, stream(ClientArgs), stream(ClientStatus)
+ rpc :CoreCount, CoreRequest, CoreResponse
+ rpc :QuitWorker, Void, Void
+ end
+
+ Stub = Service.rpc_stub_class
+ end
+ end
+end
diff --git a/src/ruby/qps/src/proto/grpc/testing/stats.rb b/src/ruby/qps/src/proto/grpc/testing/stats.rb
new file mode 100644
index 0000000000..41f75bedf0
--- /dev/null
+++ b/src/ruby/qps/src/proto/grpc/testing/stats.rb
@@ -0,0 +1,39 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: src/proto/grpc/testing/stats.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_message "grpc.testing.ServerStats" do
+ optional :time_elapsed, :double, 1
+ optional :time_user, :double, 2
+ optional :time_system, :double, 3
+ end
+ add_message "grpc.testing.HistogramParams" do
+ optional :resolution, :double, 1
+ optional :max_possible, :double, 2
+ end
+ add_message "grpc.testing.HistogramData" do
+ repeated :bucket, :uint32, 1
+ optional :min_seen, :double, 2
+ optional :max_seen, :double, 3
+ optional :sum, :double, 4
+ optional :sum_of_squares, :double, 5
+ optional :count, :double, 6
+ end
+ add_message "grpc.testing.ClientStats" do
+ optional :latencies, :message, 1, "grpc.testing.HistogramData"
+ optional :time_elapsed, :double, 2
+ optional :time_user, :double, 3
+ optional :time_system, :double, 4
+ end
+end
+
+module Grpc
+ module Testing
+ ServerStats = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ServerStats").msgclass
+ HistogramParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.HistogramParams").msgclass
+ HistogramData = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.HistogramData").msgclass
+ ClientStats = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ClientStats").msgclass
+ end
+end
diff --git a/src/ruby/qps/worker.rb b/src/ruby/qps/worker.rb
new file mode 100755
index 0000000000..665fb86352
--- /dev/null
+++ b/src/ruby/qps/worker.rb
@@ -0,0 +1,128 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Worker and worker service implementation
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(this_dir), 'lib')
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'grpc'
+require 'optparse'
+require 'histogram'
+require 'etc'
+require 'facter'
+require 'client'
+require 'qps-common'
+require 'server'
+require 'src/proto/grpc/testing/services_services'
+
+class WorkerServiceImpl < Grpc::Testing::WorkerService::Service
+ def cpu_cores
+ Facter.value('processors')['count']
+ end
+ def run_server(reqs)
+ q = EnumeratorQueue.new(self)
+ Thread.new {
+ bms = ''
+ gtss = Grpc::Testing::ServerStatus
+ reqs.each do |req|
+ case req.argtype.to_s
+ when 'setup'
+ bms = BenchmarkServer.new(req.setup, @server_port)
+ q.push(gtss.new(stats: bms.mark(false), port: bms.get_port))
+ when 'mark'
+ q.push(gtss.new(stats: bms.mark(req.mark.reset), cores: cpu_cores))
+ end
+ end
+ q.push(self)
+ bms.stop
+ }
+ q.each_item
+ end
+ def run_client(reqs)
+ q = EnumeratorQueue.new(self)
+ Thread.new {
+ client = ''
+ reqs.each do |req|
+ case req.argtype.to_s
+ when 'setup'
+ client = BenchmarkClient.new(req.setup)
+ q.push(Grpc::Testing::ClientStatus.new(stats: client.mark(false)))
+ when 'mark'
+ q.push(Grpc::Testing::ClientStatus.new(stats:
+ client.mark(req.mark.reset)))
+ end
+ end
+ q.push(self)
+ client.shutdown
+ }
+ q.each_item
+ end
+ def core_count(_args, _call)
+ Grpc::Testing::CoreResponse.new(cores: cpu_cores)
+ end
+ def quit_worker(_args, _call)
+ Thread.new {
+ sleep 3
+ @server.stop
+ }
+ Grpc::Testing::Void.new
+ end
+ def initialize(s, sp)
+ @server = s
+ @server_port = sp
+ end
+end
+
+def main
+ options = {
+ 'driver_port' => 0,
+ 'server_port' => 0
+ }
+ OptionParser.new do |opts|
+ opts.banner = 'Usage: [--driver_port <port>] [--server_port <port>]'
+ opts.on('--driver_port PORT', '<port>') do |v|
+ options['driver_port'] = v
+ end
+ opts.on('--server_port PORT', '<port>') do |v|
+ options['server_port'] = v
+ end
+ end.parse!
+ s = GRPC::RpcServer.new
+ s.add_http2_port("0.0.0.0:" + options['driver_port'].to_s,
+ :this_port_is_insecure)
+ s.handle(WorkerServiceImpl.new(s, options['server_port'].to_i))
+ s.run
+end
+
+main
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 7ef534571f..aedeca272d 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 5e13c25fcf..dd8e2e9f7a 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -193,44 +193,45 @@ describe 'ClientStub' do
describe '#client_streamer' do
shared_examples 'client streaming' do
before(:each) do
+ server_port = create_test_server
+ host = "localhost:#{server_port}"
+ @stub = GRPC::ClientStub.new(host, @cq, :this_channel_is_insecure)
+ @options = { k1: 'v1', k2: 'v2' }
@sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
@resp = 'a_reply'
end
it 'should send requests to/receive a reply from a server' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
th = run_client_streamer(@sent_msgs, @resp, @pass)
- stub = GRPC::ClientStub.new(host, @cq, :this_channel_is_insecure)
- expect(get_response(stub)).to eq(@resp)
+ expect(get_response(@stub)).to eq(@resp)
th.join
end
it 'should send metadata to the server ok' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
- th = run_client_streamer(@sent_msgs, @resp, @pass,
- k1: 'v1', k2: 'v2')
- stub = GRPC::ClientStub.new(host, @cq, :this_channel_is_insecure)
- expect(get_response(stub)).to eq(@resp)
+ th = run_client_streamer(@sent_msgs, @resp, @pass, @options)
+ expect(get_response(@stub)).to eq(@resp)
th.join
end
it 'should raise an error if the status is not ok' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
th = run_client_streamer(@sent_msgs, @resp, @fail)
- stub = GRPC::ClientStub.new(host, @cq, :this_channel_is_insecure)
- blk = proc { get_response(stub) }
+ blk = proc { get_response(@stub) }
expect(&blk).to raise_error(GRPC::BadStatus)
th.join
end
+
+ it 'should raise ArgumentError if metadata contains invalid values' do
+ @options.merge!(k3: 3)
+ expect do
+ get_response(@stub)
+ end.to raise_error(ArgumentError,
+ /Header values must be of type string or array/)
+ end
end
describe 'without a call operation' do
def get_response(stub)
- stub.client_streamer(@method, @sent_msgs, noop, noop,
- k1: 'v1', k2: 'v2')
+ stub.client_streamer(@method, @sent_msgs, noop, noop, @options)
end
it_behaves_like 'client streaming'
@@ -239,7 +240,7 @@ describe 'ClientStub' do
describe 'via a call operation' do
def get_response(stub)
op = stub.client_streamer(@method, @sent_msgs, noop, noop,
- return_op: true, k1: 'v1', k2: 'v2')
+ @options.merge(return_op: true))
expect(op).to be_a(GRPC::ActiveCall::Operation)
op.execute
end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index dfaec6d6ed..e688057cb1 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -426,7 +426,7 @@ describe GRPC::RpcServer do
threads.each(&:join)
end
- it 'should return UNAVAILABLE on too many jobs', server: true do
+ it 'should return RESOURCE_EXHAUSTED on too many jobs', server: true do
opts = {
a_channel_arg: 'an_arg',
server_override: @server,
@@ -449,7 +449,8 @@ describe GRPC::RpcServer do
begin
stub.an_rpc(req)
rescue GRPC::BadStatus => e
- one_failed_as_unavailable = e.code == StatusCodes::UNAVAILABLE
+ one_failed_as_unavailable =
+ e.code == StatusCodes::RESOURCE_EXHAUSTED
end
end
end
diff --git a/src/ruby/bin/grpc_ruby_interop_server b/src/ruby/spec/pb/duplicate/codegen_spec.rb
index 656a5f7c99..54c136c510 100755..100644
--- a/src/ruby/bin/grpc_ruby_interop_server
+++ b/src/ruby/spec/pb/duplicate/codegen_spec.rb
@@ -1,6 +1,4 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -29,5 +27,45 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Provides a gem binary entry point for the interop server
-require 'test/server'
+require 'open3'
+require 'tmpdir'
+
+def can_run_codegen_check
+ system('which grpc_ruby_plugin') && system('which protoc')
+end
+
+describe 'Ping protobuf code generation' do
+ if !can_run_codegen_check
+ skip 'protoc || grpc_ruby_plugin missing, cannot verify ping code-gen'
+ else
+ it 'should have the same content as created by code generation' do
+ root_dir = File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..')
+
+ # Get the current content
+ service_path = File.join(root_dir, 'src', 'ruby', 'pb', 'grpc',
+ 'testing', 'duplicate',
+ 'echo_duplicate_services.rb')
+ want = nil
+ File.open(service_path) { |f| want = f.read }
+
+ # Regenerate it
+ plugin, = Open3.capture2('which', 'grpc_ruby_plugin')
+ plugin = plugin.strip
+ got = nil
+ Dir.mktmpdir do |tmp_dir|
+ gen_out = File.join(tmp_dir, 'src', 'proto', 'grpc', 'testing',
+ 'duplicate', 'echo_duplicate_services.rb')
+ pid = spawn(
+ 'protoc',
+ '-I.',
+ 'src/proto/grpc/testing/duplicate/echo_duplicate.proto',
+ "--grpc_out=#{tmp_dir}",
+ "--plugin=protoc-gen-grpc=#{plugin}",
+ chdir: root_dir)
+ Process.wait(pid)
+ File.open(gen_out) { |f| got = f.read }
+ end
+ expect(got).to eq(want)
+ end
+ end
+end
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index 9bb79bb4ca..5523347f45 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -1,4 +1,4 @@
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/stress/metrics_server.rb
index 239083f37f..13638c4d21 100755..100644
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/stress/metrics_server.rb
@@ -1,6 +1,4 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -29,23 +27,57 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# #######################################################################
-# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb
-#
-# This file remains to support existing tools and scripts that use it.
-# ######################################################################
-#
-# interop_client is a testing tool that accesses a gRPC interop testing
-# server and runs a test on it.
-#
-# Helps validate interoperation b/w different gRPC implementations.
-#
-# Usage: $ path/to/interop_client.rb --server_host=<hostname> \
-# --server_port=<port> \
-# --test_case=<testcase_name>
+require_relative '../pb/grpc/testing/metrics.rb'
+require_relative '../pb/grpc/testing/metrics_services.rb'
+
+class Gauge
+ def get_name
+ raise NoMethodError.new
+ end
+
+ def get_type
+ raise NoMethodError.new
+ end
+
+ def get_value
+ raise NoMethodError.new
+ end
+end
+
+class MetricsServiceImpl < Grpc::Testing::MetricsService::Service
+ include Grpc::Testing
+ @gauges
+
+ def initialize
+ @gauges = {}
+ end
+
+ def register_gauge(gauge)
+ @gauges[gauge.get_name] = gauge
+ end
+
+ def make_gauge_response(gauge)
+ response = GaugeResponse.new(:name => gauge.get_name)
+ value = gauge.get_value
+ case gauge.get_type
+ when 'long'
+ response.long_value = value
+ when 'double'
+ response.double_value = value
+ when 'string'
+ response.string_value = value
+ end
+ response
+ end
-this_dir = File.expand_path(File.dirname(__FILE__))
-pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
-$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+ def get_all_gauges(_empty, _call)
+ @gauges.values.map do |gauge|
+ make_gauge_response gauge
+ end
+ end
-require 'test/client'
+ def get_gauge(gauge_req, _call)
+ gauge = @gauges[gauge_req.name]
+ make_gauge_response gauge
+ end
+end
diff --git a/src/ruby/stress/stress_client.rb b/src/ruby/stress/stress_client.rb
new file mode 100755
index 0000000000..698f9f1b87
--- /dev/null
+++ b/src/ruby/stress/stress_client.rb
@@ -0,0 +1,155 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+require 'optparse'
+require 'thread'
+require_relative '../pb/test/client'
+require_relative './metrics_server'
+require_relative '../lib/grpc'
+
+class QpsGauge < Gauge
+ @query_count
+ @query_mutex
+ @start_time
+
+ def initialize
+ @query_count = 0
+ @query_mutex = Mutex.new
+ @start_time = Time.now
+ end
+
+ def increment_queries
+ @query_mutex.synchronize { @query_count += 1}
+ end
+
+ def get_name
+ 'qps'
+ end
+
+ def get_type
+ 'long'
+ end
+
+ def get_value
+ (@query_mutex.synchronize { @query_count / (Time.now - @start_time) }).to_i
+ end
+end
+
+def start_metrics_server(port)
+ host = "0.0.0.0:#{port}"
+ server = GRPC::RpcServer.new
+ server.add_http2_port(host, :this_port_is_insecure)
+ service = MetricsServiceImpl.new
+ server.handle(service)
+ server_thread = Thread.new { server.run_till_terminated }
+ [server, service, server_thread]
+end
+
+StressArgs = Struct.new(:server_addresses, :test_cases, :duration,
+ :channels_per_server, :concurrent_calls, :metrics_port)
+
+def start(stress_args)
+ running = true
+ threads = []
+ qps_gauge = QpsGauge.new
+ metrics_server, metrics_service, metrics_thread =
+ start_metrics_server(stress_args.metrics_port)
+ metrics_service.register_gauge(qps_gauge)
+ stress_args.server_addresses.each do |address|
+ stress_args.channels_per_server.times do
+ client_args = Args.new
+ client_args.host, client_args.port = address.split(':')
+ client_args.secure = false
+ client_args.test_case = ''
+ stub = create_stub(client_args)
+ named_tests = NamedTests.new(stub, client_args)
+ stress_args.concurrent_calls.times do
+ threads << Thread.new do
+ while running
+ named_tests.method(stress_args.test_cases.sample).call
+ qps_gauge.increment_queries
+ end
+ end
+ end
+ end
+ end
+ if stress_args.duration >= 0
+ sleep stress_args.duration
+ running = false
+ metrics_server.stop
+ p "QPS: #{qps_gauge.get_value}"
+ threads.each { |thd| thd.join; }
+ end
+ metrics_thread.join
+end
+
+def parse_stress_args
+ stress_args = StressArgs.new
+ stress_args.server_addresses = ['localhost:8080']
+ stress_args.test_cases = []
+ stress_args.duration = -1
+ stress_args.channels_per_server = 1
+ stress_args.concurrent_calls = 1
+ stress_args.metrics_port = '8081'
+ OptionParser.new do |opts|
+ opts.on('--server_addresses [LIST]', Array) do |addrs|
+ stress_args.server_addresses = addrs
+ end
+ opts.on('--test_cases cases', Array) do |cases|
+ stress_args.test_cases = (cases.map do |item|
+ split = item.split(':')
+ [split[0]] * split[1].to_i
+ end).reduce([], :+)
+ end
+ opts.on('--test_duration_secs [INT]', OptionParser::DecimalInteger) do |time|
+ stress_args.duration = time
+ end
+ opts.on('--num_channels_per_server [INT]', OptionParser::DecimalInteger) do |channels|
+ stress_args.channels_per_server = channels
+ end
+ opts.on('--num_stubs_per_channel [INT]', OptionParser::DecimalInteger) do |stubs|
+ stress_args.concurrent_calls = stubs
+ end
+ opts.on('--metrics_port [port]') do |port|
+ stress_args.metrics_port = port
+ end
+ end.parse!
+ stress_args
+end
+
+def main
+ opts = parse_stress_args
+ start(opts)
+end
+
+if __FILE__ == $0
+ main
+end