diff options
author | Craig Tiller <craig.tiller@gmail.com> | 2015-01-27 10:18:09 -0800 |
---|---|---|
committer | Craig Tiller <craig.tiller@gmail.com> | 2015-01-27 10:18:09 -0800 |
commit | 6437bd5037518953b159ae5321cd72eaaeb4ed03 (patch) | |
tree | 6df55f3880b5c6a4fb77bf737cb834467a24fae6 /src/ruby | |
parent | 103481ec8a7d93e0b120c639aa0c879e5e0aff88 (diff) | |
parent | 1159dcf5bc98460e0408cb30609dd1dafa8d31a4 (diff) |
Merge github.com:google/grpc into javascript
Diffstat (limited to 'src/ruby')
-rwxr-xr-x | src/ruby/README.md | 27 | ||||
-rwxr-xr-x | src/ruby/bin/interop/interop_client.rb | 99 | ||||
-rwxr-xr-x | src/ruby/bin/interop/interop_server.rb | 19 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_call.c | 20 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_credentials.c | 6 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_event.c | 6 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_server.c | 12 | ||||
-rwxr-xr-x | src/ruby/grpc.gemspec | 1 | ||||
-rw-r--r-- | src/ruby/lib/grpc/generic/active_call.rb | 30 | ||||
-rw-r--r-- | src/ruby/lib/grpc/generic/bidi_call.rb | 4 | ||||
-rw-r--r-- | src/ruby/spec/call_spec.rb | 40 | ||||
-rw-r--r-- | src/ruby/spec/channel_spec.rb | 21 | ||||
-rw-r--r-- | src/ruby/spec/client_server_spec.rb | 106 | ||||
-rw-r--r-- | src/ruby/spec/event_spec.rb | 3 | ||||
-rw-r--r-- | src/ruby/spec/generic/active_call_spec.rb | 66 | ||||
-rw-r--r-- | src/ruby/spec/generic/client_stub_spec.rb | 144 | ||||
-rw-r--r-- | src/ruby/spec/generic/rpc_server_spec.rb | 7 | ||||
-rw-r--r-- | src/ruby/spec/port_picker.rb | 45 | ||||
-rw-r--r-- | src/ruby/spec/server_spec.rb | 5 |
19 files changed, 313 insertions, 348 deletions
diff --git a/src/ruby/README.md b/src/ruby/README.md index 7f7558dc67..7ece7e2706 100755 --- a/src/ruby/README.md +++ b/src/ruby/README.md @@ -14,9 +14,10 @@ INSTALLING ---------- - Install the gRPC core library -TODO: describe this, once the core distribution mechanism is defined. - + TODO: describe this, once the core distribution mechanism is defined. +``` $ gem install grpc +``` Installing from source @@ -24,37 +25,47 @@ Installing from source - Build or Install the gRPC core E.g, from the root of the grpc [git repo](https://github.com/google/grpc) +``` $ cd ../.. $ make && sudo make install +``` - Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling the exact ruby version that's used. +``` $ command curl -sSL https://rvm.io/mpapis.asc | gpg --import - $ \curl -sSL https://get.rvm.io | bash -s stable --ruby $ $ # follow the instructions to ensure that your're using the latest stable version of Ruby $ # and that the rvm command is installed +``` - Install [bundler](http://bundler.io/) +``` $ gem install bundler +``` - Finally, install grpc ruby locally. +``` $ cd <install_dir> $ bundle install $ rake # compiles the extension, runs the unit tests, see rake -T for other options - +``` CONTENTS -------- Directory structure is the layout for [ruby extensions](http://guides.rubygems.org/gems-with-extensions/) - * ext: the extension code - * lib: the entrypoint grpc ruby library to be used in a 'require' statement - * spec: tests - * bin: example gRPC clients and servers, e.g, +- ext: + the gRPC ruby extension +- lib: + the entrypoint grpc ruby library to be used in a 'require' statement +- spec: + Rspec unittest +- bin: + example gRPC clients and servers, e.g, ```ruby -# client stub = Math::Math::Stub.new('my.test.math.server.com:8080') req = Math::DivArgs.new(dividend: 7, divisor: 3) logger.info("div(7/3): req=#{req.inspect}") diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index 0ea7f376be..86739b7b67 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -54,6 +54,8 @@ require 'test/cpp/interop/test_services' require 'test/cpp/interop/messages' require 'test/cpp/interop/empty' +require 'signet/ssl_config' + # loads the certificates used to access the test server securely. def load_test_certs this_dir = File.expand_path(File.dirname(__FILE__)) @@ -62,21 +64,49 @@ def load_test_certs files.map { |f| File.open(File.join(data_dir, f)).read } end +# loads the certificates used to access the test server securely. +def load_prod_cert + fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil? + p "loading prod certs from #{ENV['SSL_CERT_FILE']}" + File.open(ENV['SSL_CERT_FILE']).read +end + # creates a Credentials from the test certificates. def test_creds certs = load_test_certs GRPC::Core::Credentials.new(certs[0]) end +RX_CERT = /-----BEGIN CERTIFICATE-----\n.*?-----END CERTIFICATE-----\n/m + + +# creates a Credentials from the production certificates. +def prod_creds + cert_text = load_prod_cert + GRPC::Core::Credentials.new(cert_text) +end + # creates a test stub that accesses host:port securely. -def create_stub(host, port) +def create_stub(host, port, is_secure, host_override, use_test_ca) address = "#{host}:#{port}" - stub_opts = { - :creds => test_creds, - GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com' - } - logger.info("... connecting securely to #{address}") - Grpc::Testing::TestService::Stub.new(address, **stub_opts) + if is_secure + creds = nil + if use_test_ca + creds = test_creds + else + creds = prod_creds + end + + stub_opts = { + :creds => creds, + GRPC::Core::Channel::SSL_TARGET => host_override + } + logger.info("... connecting securely to #{address}") + Grpc::Testing::TestService::Stub.new(address, **stub_opts) + else + logger.info("... connecting insecurely to #{address}") + Grpc::Testing::TestService::Stub.new(address) + end end # produces a string of null chars (\0) of length l. @@ -133,20 +163,12 @@ class NamedTests @stub = stub end - # TESTING - # PASSED - # FAIL - # ruby server: fails protobuf-ruby can't pass an empty message def empty_unary resp = @stub.empty_call(Empty.new) assert resp.is_a?(Empty), 'empty_unary: invalid response' p 'OK: empty_unary' end - # TESTING - # PASSED - # ruby server - # FAILED def large_unary req_size, wanted_response_size = 271_828, 314_159 payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size)) @@ -163,10 +185,6 @@ class NamedTests p 'OK: large_unary' end - # TESTING: - # PASSED - # ruby server - # FAILED def client_streaming msg_sizes = [27_182, 8, 1828, 45_904] wanted_aggregate_size = 74_922 @@ -180,10 +198,6 @@ class NamedTests p 'OK: client_streaming' end - # TESTING: - # PASSED - # ruby server - # FAILED def server_streaming msg_sizes = [31_415, 9, 2653, 58_979] response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) } @@ -200,10 +214,6 @@ class NamedTests p 'OK: server_streaming' end - # TESTING: - # PASSED - # ruby server - # FAILED def ping_pong msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] ppp = PingPongPlayer.new(msg_sizes) @@ -211,12 +221,23 @@ class NamedTests resps.each { |r| ppp.queue.push(r) } p 'OK: ping_pong' end + + def all + all_methods = NamedTests.instance_methods(false).map(&:to_s) + all_methods.each do |m| + next if m == 'all' || m.start_with?('assert') + p "TESTCASE: #{m}" + method(m).call + end + end end # validates the the command line options, returning them as a Hash. def parse_options options = { + 'secure' => false, 'server_host' => nil, + 'server_host_override' => nil, 'server_port' => nil, 'test_case' => nil } @@ -225,6 +246,10 @@ def parse_options opts.on('--server_host SERVER_HOST', 'server hostname') do |v| options['server_host'] = v end + opts.on('--server_host_override HOST_OVERRIDE', + 'override host via a HTTP header') do |v| + options['server_host_override'] = v + end opts.on('--server_port SERVER_PORT', 'server port') do |v| options['server_port'] = v end @@ -235,19 +260,33 @@ def parse_options " (#{test_case_list})") do |v| options['test_case'] = v end + opts.on('-s', '--use_tls', 'require a secure connection?') do |v| + options['secure'] = v + end + opts.on('-t', '--use_test_ca', + 'if secure, use the test certificate?') do |v| + options['use_test_ca'] = v + end end.parse! + _check_options(options) +end +def _check_options(opts) %w(server_host server_port test_case).each do |arg| - if options[arg].nil? + if opts[arg].nil? fail(OptionParser::MissingArgument, "please specify --#{arg}") end end - options + if opts['server_host_override'].nil? + opts['server_host_override'] = opts['server_host'] + end + opts end def main opts = parse_options - stub = create_stub(opts['server_host'], opts['server_port']) + stub = create_stub(opts['server_host'], opts['server_port'], opts['secure'], + opts['server_host_override'], opts['use_test_ca']) NamedTests.new(stub).method(opts['test_case']).call end diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 83212823f6..cc4d260879 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -154,13 +154,17 @@ end # validates the the command line options, returning them as a Hash. def parse_options options = { - 'port' => nil + 'port' => nil, + 'secure' => false } OptionParser.new do |opts| opts.banner = 'Usage: --port port' opts.on('--port PORT', 'server port') do |v| options['port'] = v end + opts.on('-s', '--use_tls', 'require a secure connection?') do |v| + options['secure'] = v + end end.parse! if options['port'].nil? @@ -172,10 +176,15 @@ end def main opts = parse_options host = "0.0.0.0:#{opts['port']}" - s = GRPC::RpcServer.new(creds: test_server_creds) - s.add_http2_port(host, true) - logger.info("... running securely on #{host}") - + if opts['secure'] + s = GRPC::RpcServer.new(creds: test_server_creds) + s.add_http2_port(host, true) + logger.info("... running securely on #{host}") + else + s = GRPC::RpcServer.new + s.add_http2_port(host) + logger.info("... running insecurely on #{host}") + end s.handle(TestTarget) s.run end diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 76b80bcaa1..1b6565f729 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -153,7 +153,7 @@ int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) { Add metadata elements to the call from a ruby hash, to be sent upon invocation. flags is a bit-field combination of the write flags defined - above. REQUIRES: grpc_call_start_invoke/grpc_call_accept have not been + above. REQUIRES: grpc_call_invoke/grpc_call_accept have not been called on this call. Produces no events. */ static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) { @@ -196,16 +196,15 @@ static VALUE grpc_rb_call_cancel(VALUE self) { /* call-seq: - call.start_invoke(completion_queue, tag, flags=nil) + call.invoke(completion_queue, tag, flags=nil) Invoke the RPC. Starts sending metadata and request headers on the wire. flags is a bit-field combination of the write flags defined above. REQUIRES: Can be called at most once per call. Can only be called on the client. Produces a GRPC_INVOKE_ACCEPTED event on completion. */ -static VALUE grpc_rb_call_start_invoke(int argc, VALUE *argv, VALUE self) { +static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) { VALUE cqueue = Qnil; - VALUE invoke_accepted_tag = Qnil; VALUE metadata_read_tag = Qnil; VALUE finished_tag = Qnil; VALUE flags = Qnil; @@ -213,17 +212,16 @@ static VALUE grpc_rb_call_start_invoke(int argc, VALUE *argv, VALUE self) { grpc_completion_queue *cq = NULL; grpc_call_error err; - /* "41" == 4 mandatory args, 1 (flags) is optional */ - rb_scan_args(argc, argv, "41", &cqueue, &invoke_accepted_tag, - &metadata_read_tag, &finished_tag, &flags); + /* "31" == 3 mandatory args, 1 (flags) is optional */ + rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag, + &flags); if (NIL_P(flags)) { flags = UINT2NUM(0); /* Default to no flags */ } cq = grpc_rb_get_wrapped_completion_queue(cqueue); Data_Get_Struct(self, grpc_call, call); - err = grpc_call_start_invoke(call, cq, ROBJECT(invoke_accepted_tag), - ROBJECT(metadata_read_tag), - ROBJECT(finished_tag), NUM2UINT(flags)); + err = grpc_call_invoke(call, cq, ROBJECT(metadata_read_tag), + ROBJECT(finished_tag), NUM2UINT(flags)); if (err != GRPC_CALL_OK) { rb_raise(rb_eCallError, "invoke failed: %s (code=%d)", grpc_call_error_detail_of(err), err); @@ -519,7 +517,7 @@ void Init_google_rpc_call() { grpc_rb_call_server_end_initial_metadata, -1); rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1); rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0); - rb_define_method(rb_cCall, "start_invoke", grpc_rb_call_start_invoke, -1); + rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1); rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1); rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1); rb_define_method(rb_cCall, "start_write_status", diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c index 31f47f3b76..43cc21aeca 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_credentials.c @@ -214,6 +214,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { VALUE pem_cert_chain = Qnil; grpc_rb_credentials *wrapper = NULL; grpc_credentials *creds = NULL; + grpc_ssl_pem_key_cert_pair key_cert_pair; + MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1); /* TODO: Remove mandatory arg when we support default roots. */ /* "12" == 1 mandatory arg, 2 (credentials) is optional */ rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, @@ -228,8 +230,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { if (pem_private_key == Qnil && pem_cert_chain == Qnil) { creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL); } else { - grpc_ssl_pem_key_cert_pair key_cert_pair = {RSTRING_PTR(pem_private_key), - RSTRING_PTR(pem_cert_chain)}; + key_cert_pair.private_key = RSTRING_PTR(pem_private_key); + key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); creds = grpc_ssl_credentials_create( RSTRING_PTR(pem_root_certs), &key_cert_pair); } diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c index 0fae9502c3..a1ab6251c8 100644 --- a/src/ruby/ext/grpc/rb_event.c +++ b/src/ruby/ext/grpc/rb_event.c @@ -105,10 +105,6 @@ static VALUE grpc_rb_event_type(VALUE self) { case GRPC_READ: return rb_const_get(rb_mCompletionType, rb_intern("READ")); - case GRPC_INVOKE_ACCEPTED: - grpc_rb_event_result(self); /* validates the result */ - return rb_const_get(rb_mCompletionType, rb_intern("INVOKE_ACCEPTED")); - case GRPC_WRITE_ACCEPTED: grpc_rb_event_result(self); /* validates the result */ return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED")); @@ -359,6 +355,8 @@ void Init_google_rpc_event() { rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED)); rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW", INT2NUM(GRPC_SERVER_RPC_NEW)); + rb_define_const(rb_mCompletionType, "SERVER_SHUTDOWN", + INT2NUM(GRPC_SERVER_SHUTDOWN)); rb_define_const(rb_mCompletionType, "RESERVED", INT2NUM(GRPC_COMPLETION_DO_NOT_USE)); } diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index ef2a9f107b..436d006760 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -223,7 +223,7 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { VALUE port = Qnil; VALUE is_secure = Qnil; grpc_rb_server *s = NULL; - int added_ok = 0; + int recvd_port = 0; /* "11" == 1 mandatory args, 1 (is_secure) is optional */ rb_scan_args(argc, argv, "11", &port, &is_secure); @@ -233,22 +233,22 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } else if (is_secure == Qnil || TYPE(is_secure) != T_TRUE) { - added_ok = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port)); - if (added_ok == 0) { + recvd_port = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port)); + if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add port %s to server, not sure why", StringValueCStr(port)); } } else if (TYPE(is_secure) != T_FALSE) { - added_ok = + recvd_port = grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port)); - if (added_ok == 0) { + if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add secure port %s to server, not sure why", StringValueCStr(port)); } } - return Qnil; + return INT2NUM(recvd_port); } void Init_google_rpc_server() { diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index 450362f5a8..ffd084dc91 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -22,6 +22,7 @@ Gem::Specification.new do |s| s.add_dependency 'xray' s.add_dependency 'logging', '~> 1.8' s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1' + s.add_dependency 'signet', '~> 0.5.1' s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests s.add_development_dependency 'bundler', '~> 1.7' diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index bd684a8d07..6c2b6e91c2 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -47,7 +47,7 @@ module Google include Core::TimeConsts attr_reader(:deadline) - # client_start_invoke begins a client invocation. + # client_invoke begins a client invocation. # # Flow Control note: this blocks until flow control accepts that client # request can go ahead. @@ -59,34 +59,26 @@ module Google # if a keyword value is a list, multiple metadata for it's key are sent # # @param call [Call] a call on which to start and invocation - # @param q [CompletionQueue] used to wait for INVOKE_ACCEPTED - # @param deadline [Fixnum,TimeSpec] the deadline for INVOKE_ACCEPTED - def self.client_start_invoke(call, q, _deadline, **kw) + # @param q [CompletionQueue] the completion queue + # @param deadline [Fixnum,TimeSpec] the deadline + def self.client_invoke(call, q, _deadline, **kw) fail(ArgumentError, 'not a call') unless call.is_a? Core::Call unless q.is_a? Core::CompletionQueue fail(ArgumentError, 'not a CompletionQueue') end call.add_metadata(kw) if kw.length > 0 - invoke_accepted, client_metadata_read = Object.new, Object.new + client_metadata_read = Object.new finished_tag = Object.new - call.start_invoke(q, invoke_accepted, client_metadata_read, - finished_tag) - - # wait for the invocation to be accepted - ev = q.pluck(invoke_accepted, INFINITE_FUTURE) - fail OutOfTime if ev.nil? - ev.close - + call.invoke(q, client_metadata_read, finished_tag) [finished_tag, client_metadata_read] end # Creates an ActiveCall. # - # ActiveCall should only be created after a call is accepted. That means - # different things on a client and a server. On the client, the call is - # accepted after call.start_invoke followed by receipt of the - # corresponding INVOKE_ACCEPTED. on the server, this is after - # call.accept. + # ActiveCall should only be created after a call is accepted. That + # means different things on a client and a server. On the client, the + # call is accepted after calling call.invoke. On the server, this is + # after call.accept. # # #initialize cannot determine if the call is accepted or not; so if a # call that's not accepted is used here, the error won't be visible until @@ -495,7 +487,7 @@ module Google private def start_call(**kw) - tags = ActiveCall.client_start_invoke(@call, @cq, @deadline, **kw) + tags = ActiveCall.client_invoke(@call, @cq, @deadline, **kw) @finished_tag, @read_metadata_tag = tags @started = true end diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb index 36877dc648..099d57151c 100644 --- a/src/ruby/lib/grpc/generic/bidi_call.rb +++ b/src/ruby/lib/grpc/generic/bidi_call.rb @@ -50,9 +50,7 @@ module Google # # BidiCall should only be created after a call is accepted. That means # different things on a client and a server. On the client, the call is - # accepted after call.start_invoke followed by receipt of the - # corresponding INVOKE_ACCEPTED. On the server, this is after - # call.accept. + # accepted after call.invoke. On the server, this is after call.accept. # # #initialize cannot determine if the call is accepted or not; so if a # call that's not accepted is used here, the error won't be visible until diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb index b8ecd64f39..c793284488 100644 --- a/src/ruby/spec/call_spec.rb +++ b/src/ruby/spec/call_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' include GRPC::Core::StatusCodes @@ -71,16 +70,8 @@ describe GRPC::Core::Call do before(:each) do @tag = Object.new @client_queue = GRPC::Core::CompletionQueue.new - @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - host = "localhost:#{port}" - @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) - @ch = GRPC::Core::Channel.new(host, nil) - end - - after(:each) do - @server.close + fake_host = 'localhost:10101' + @ch = GRPC::Core::Channel.new(fake_host, nil) end describe '#start_read' do @@ -122,33 +113,6 @@ describe GRPC::Core::Call do end end - describe '#start_invoke' do - it 'should cause the INVOKE_ACCEPTED event' do - call = make_test_call - expect(call.start_invoke(@client_queue, @tag, @tag, @tag)).to be_nil - ev = @client_queue.next(deadline) - expect(ev.call).to be_a(GRPC::Core::Call) - expect(ev.tag).to be(@tag) - expect(ev.type).to be(GRPC::Core::CompletionType::INVOKE_ACCEPTED) - expect(ev.call).to_not be(call) - end - end - - describe '#start_write' do - it 'should cause the WRITE_ACCEPTED event' do - call = make_test_call - call.start_invoke(@client_queue, @tag, @tag, @tag) - ev = @client_queue.next(deadline) - expect(ev.type).to be(GRPC::Core::CompletionType::INVOKE_ACCEPTED) - expect(call.start_write(GRPC::Core::ByteBuffer.new('test_start_write'), - @tag)).to be_nil - ev = @client_queue.next(deadline) - expect(ev.call).to be_a(GRPC::Core::Call) - expect(ev.type).to be(GRPC::Core::CompletionType::WRITE_ACCEPTED) - expect(ev.tag).to be(@tag) - end - end - describe '#status' do it 'can save the status and read it back' do call = make_test_call diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index 820dbd39e9..189d1c67ab 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -28,7 +28,8 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' + +FAKE_HOST='localhost:0' def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -114,8 +115,7 @@ describe GRPC::Core::Channel do describe '#create_call' do it 'creates a call OK' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) deadline = Time.now + 5 @@ -127,8 +127,7 @@ describe GRPC::Core::Channel do end it 'raises an error if called on a closed channel' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) ch.close @@ -142,16 +141,14 @@ describe GRPC::Core::Channel do describe '#destroy' do it 'destroys a channel ok' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.destroy } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.destroy } blk.call @@ -167,16 +164,14 @@ describe GRPC::Core::Channel do describe '#close' do it 'closes a channel ok' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.close } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.close } blk.call diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index df70e56bca..96b8ef4300 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' require 'spec_helper' include GRPC::Core::CompletionType @@ -44,12 +43,13 @@ shared_context 'setup: tags' do before(:example) do @server_finished_tag = Object.new @client_finished_tag = Object.new + @client_metadata_tag = Object.new @server_tag = Object.new @tag = Object.new end def deadline - Time.now + 0.05 + Time.now + 2 end def expect_next_event_on(queue, type, tag) @@ -63,30 +63,30 @@ shared_context 'setup: tags' do ev end - def server_receives_and_responds_with(reply_text) - reply = ByteBuffer.new(reply_text) + def server_allows_client_to_proceed @server.request_call(@server_tag) - ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) + ev = @server_queue.pluck(@server_tag, deadline) expect(ev).not_to be_nil expect(ev.type).to be(SERVER_RPC_NEW) - ev.call.server_accept(@server_queue, @server_finished_tag) - ev.call.server_end_initial_metadata - ev.call.start_read(@server_tag) + server_call = ev.call + server_call.server_accept(@server_queue, @server_finished_tag) + server_call.server_end_initial_metadata + server_call + end + + def server_responds_with(server_call, reply_text) + reply = ByteBuffer.new(reply_text) + server_call.start_read(@server_tag) ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) expect(ev.type).to be(READ) - ev.call.start_write(reply, @server_tag) + server_call.start_write(reply, @server_tag) ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) expect(ev).not_to be_nil expect(ev.type).to be(WRITE_ACCEPTED) - ev.call end def client_sends(call, sent = 'a message') req = ByteBuffer.new(sent) - call.start_invoke(@client_queue, @tag, @tag, @client_finished_tag) - ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE) - expect(ev).not_to be_nil - expect(ev.type).to be(INVOKE_ACCEPTED) call.start_write(req, @tag) ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE) expect(ev).not_to be_nil @@ -105,16 +105,20 @@ shared_examples 'basic GRPC message delivery is OK' do it 'servers receive requests from clients and start responding' do reply = ByteBuffer.new('the server payload') call = new_client_call - msg = client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # check the server rpc new was received - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) + # @server.request_call(@server_tag) + # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) # accept the call - server_call = ev.call - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata + # server_call = ev.call + # server_call.server_accept(@server_queue, @server_finished_tag) + # server_call.server_end_initial_metadata + server_call = server_allows_client_to_proceed + + # client sends a message + msg = client_sends(call) # confirm the server can read the inbound message server_call.start_read(@server_tag) @@ -128,18 +132,19 @@ shared_examples 'basic GRPC message delivery is OK' do it 'responses written by servers are received by the client' do call = new_client_call + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + server_call = server_allows_client_to_proceed client_sends(call) - server_receives_and_responds_with('server_response') + server_responds_with(server_call, 'server_response') call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) ev = expect_next_event_on(@client_queue, READ, @tag) expect(ev.result.to_s).to eq('server_response') end it 'servers can ignore a client write and send a status' do call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # check the server rpc new was received @server.request_call(@server_tag) @@ -153,9 +158,13 @@ shared_examples 'basic GRPC message delivery is OK' do server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found', @server_tag) + # Client sends some data + client_sends(call) + # client gets an empty response for the read, preceeded by some metadata. call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) ev = expect_next_event_on(@client_queue, READ, @tag) expect(ev.tag).to be(@tag) expect(ev.result.to_s).to eq('') @@ -169,13 +178,14 @@ shared_examples 'basic GRPC message delivery is OK' do it 'completes calls by sending status to client and server' do call = new_client_call + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + server_call = server_allows_client_to_proceed client_sends(call) - server_call = server_receives_and_responds_with('server_response') + server_responds_with(server_call, 'server_response') server_call.start_write_status(10_101, 'status code is 10101', @server_tag) # first the client says writes are done call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) expect_next_event_on(@client_queue, READ, @tag) call.writes_done(@tag) @@ -218,23 +228,13 @@ shared_examples 'GRPC metadata delivery works OK' do end end - it 'sends an empty hash when no metadata is added' do - call = new_client_call - client_sends(call) - - # Server gets a response - @server.request_call(@server_tag) - expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - end - it 'sends all the metadata pairs when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call call.add_metadata(md) # Client begins a call OK - call.start_invoke(@client_queue, @tag, @tag, @client_finished_tag) - expect_next_event_on(@client_queue, INVOKE_ACCEPTED, @tag) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # ... server has all metadata available even though the client did not # send a write @@ -266,7 +266,7 @@ shared_examples 'GRPC metadata delivery works OK' do it 'raises an exception if a metadata key is invalid' do @bad_keys.each do |md| call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -277,7 +277,7 @@ shared_examples 'GRPC metadata delivery works OK' do it 'sends a hash that contains the status when no metadata is added' do call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -288,21 +288,17 @@ shared_examples 'GRPC metadata delivery works OK' do server_call.server_accept(@server_queue, @server_finished_tag) server_call.server_end_initial_metadata - # ... these server sends some data, allowing the metadata read - server_call.start_write(ByteBuffer.new('reply with metadata'), - @server_tag) - expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag) - # there is the HTTP status metadata, though there should not be any # TODO: update this with the bug number to be resolved - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) expect(ev.result).to eq(':status' => '200') end it 'sends all the pairs and status:200 when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -315,7 +311,8 @@ shared_examples 'GRPC metadata delivery works OK' do server_call.server_end_initial_metadata # Now the client can read the metadata - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] replace_symbols[':status'] = '200' expect(ev.result).to eq(replace_symbols) @@ -326,17 +323,17 @@ end describe 'the http client/server' do before(:example) do - port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = '0.0.0.0:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) + server_port = @server.add_http2_port(server_host) @server.start - @ch = Channel.new(host, nil) + @ch = Channel.new("0.0.0.0:#{server_port}", nil) end after(:example) do + @ch.close @server.close end @@ -350,16 +347,15 @@ end describe 'the secure http client/server' do before(:example) do certs = load_test_certs - port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = 'localhost:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2]) @server = GRPC::Core::Server.new(@server_queue, nil, server_creds) - @server.add_http2_port(host, true) + server_port = @server.add_http2_port(server_host, true) @server.start args = { Channel::SSL_TARGET => 'foo.test.google.com' } - @ch = Channel.new(host, args, + @ch = Channel.new("0.0.0.0:#{server_port}", args, GRPC::Core::Credentials.new(certs[0], nil, nil)) end diff --git a/src/ruby/spec/event_spec.rb b/src/ruby/spec/event_spec.rb index 5dec07e1ed..7ef08d021b 100644 --- a/src/ruby/spec/event_spec.rb +++ b/src/ruby/spec/event_spec.rb @@ -40,7 +40,8 @@ describe GRPC::Core::CompletionType do CLIENT_METADATA_READ: 5, FINISHED: 6, SERVER_RPC_NEW: 7, - RESERVED: 8 + SERVER_SHUTDOWN: 8, + RESERVED: 9 } end diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 898022f185..e81b2168b0 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require_relative '../port_picker' include GRPC::Core::StatusCodes @@ -45,12 +44,11 @@ describe GRPC::ActiveCall do @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - host = "localhost:#{port}" + host = '0.0.0.0:0' @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) + server_port = @server.add_http2_port(host) @server.start - @ch = GRPC::Core::Channel.new(host, nil) + @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil) end after(:each) do @@ -60,8 +58,8 @@ describe GRPC::ActiveCall do describe 'restricted view methods' do before(:each) do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) @client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -92,8 +90,8 @@ describe GRPC::ActiveCall do describe '#remote_send' do it 'allows a client to send a payload to the server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) @client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -118,8 +116,8 @@ describe GRPC::ActiveCall do it 'marshals the payload using the marshal func' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) marshal = proc { |x| 'marshalled:' + x } client_call = ActiveCall.new(call, @client_queue, marshal, @pass_through, deadline, @@ -139,11 +137,11 @@ describe GRPC::ActiveCall do end end - describe '#client_start_invoke' do + describe '#client_invoke' do it 'sends keywords as metadata to the server when the are present' do call = make_test_call - ActiveCall.client_start_invoke(call, @client_queue, deadline, - k1: 'v1', k2: 'v2') + ActiveCall.client_invoke(call, @client_queue, deadline, + k1: 'v1', k2: 'v2') @server.request_call(@server_tag) ev = @server_queue.next(deadline) expect(ev).to_not be_nil @@ -155,8 +153,8 @@ describe GRPC::ActiveCall do describe '#remote_read' do it 'reads the response sent by a server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -170,8 +168,8 @@ describe GRPC::ActiveCall do it 'saves metadata { status=200 } when the server adds no metadata' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -187,8 +185,8 @@ describe GRPC::ActiveCall do it 'saves metadata add by the server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -205,8 +203,8 @@ describe GRPC::ActiveCall do it 'get a nil msg before a status when an OK status is sent' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -224,8 +222,8 @@ describe GRPC::ActiveCall do it 'unmarshals the response using the unmarshal func' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) unmarshal = proc { |x| 'unmarshalled:' + x } client_call = ActiveCall.new(call, @client_queue, @pass_through, unmarshal, deadline, @@ -251,8 +249,8 @@ describe GRPC::ActiveCall do it 'the returns an enumerator that can read n responses' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -271,8 +269,8 @@ describe GRPC::ActiveCall do it 'the returns an enumerator that stops after an OK Status' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, read_metadata_tag: meta_tag, @@ -296,8 +294,8 @@ describe GRPC::ActiveCall do describe '#writes_done' do it 'finishes ok if the server sends a status response' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, @@ -315,8 +313,8 @@ describe GRPC::ActiveCall do it 'finishes ok if the server sends an early status response' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, read_metadata_tag: meta_tag, @@ -334,8 +332,8 @@ describe GRPC::ActiveCall do it 'finishes ok if writes_done is true' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_start_invoke(call, @client_queue, - deadline) + done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, read_metadata_tag: meta_tag, diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 8ebe48bc4c..f1500fbd44 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -29,9 +29,9 @@ require 'grpc' require 'xray/thread_dump_signal_handler' -require_relative '../port_picker' NOOP = proc { |x| x } +FAKE_HOST = 'localhost:0' def wakey_thread(&blk) awake_mutex, awake_cond = Mutex.new, ConditionVariable.new @@ -67,7 +67,7 @@ describe 'ClientStub' do describe '#new' do it 'can be created from a host and args' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg' } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -76,7 +76,7 @@ describe 'ClientStub' do end it 'can be created with a default deadline' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg', deadline: 5 } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -85,7 +85,7 @@ describe 'ClientStub' do end it 'can be created with an channel override' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg', channel_override: @ch } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -94,7 +94,7 @@ describe 'ClientStub' do end it 'cannot be created with a bad channel override' do - host = new_test_host + host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', channel_override: Object.new } GRPC::ClientStub.new(host, @cq, **opts) @@ -103,7 +103,7 @@ describe 'ClientStub' do end it 'cannot be created with bad credentials' do - host = new_test_host + host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', creds: Object.new } GRPC::ClientStub.new(host, @cq, **opts) @@ -113,7 +113,7 @@ describe 'ClientStub' do it 'can be created with test test credentials' do certs = load_test_certs - host = new_test_host + host = FAKE_HOST blk = proc do opts = { GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com', @@ -133,16 +133,17 @@ describe 'ClientStub' do shared_examples 'request response' do it 'should send a request to/receive a reply from a server' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass) - stub = GRPC::ClientStub.new(host, @cq) + server_port = create_test_server + th = run_request_response(@sent_msg, @resp, @pass) + stub = GRPC::ClientStub.new("localhost:#{server_port}", @cq) expect(get_response(stub)).to eq(@resp) th.join end it 'should send metadata to the server ok' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, @cq) expect(get_response(stub)).to eq(@resp) @@ -150,8 +151,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -163,8 +165,9 @@ describe 'ClientStub' do end it 'should send a request when configured using an override channel' do - alt_host = new_test_host - th = run_request_response(alt_host, @sent_msg, @resp, @pass) + server_port = create_test_server + alt_host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass) ch = GRPC::Core::Channel.new(alt_host, nil) stub = GRPC::ClientStub.new('ignored-host', @cq, channel_override: ch) expect(get_response(stub)).to eq(@resp) @@ -172,8 +175,9 @@ describe 'ClientStub' do end it 'should raise an error if the status is not OK' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @fail) stub = GRPC::ClientStub.new(host, @cq) blk = proc { get_response(stub) } expect(&blk).to raise_error(GRPC::BadStatus) @@ -210,16 +214,18 @@ describe 'ClientStub' do end it 'should send requests to/receive a reply from a server' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @pass) stub = GRPC::ClientStub.new(host, @cq) expect(get_response(stub)).to eq(@resp) th.join end it 'should send metadata to the server ok' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass, + 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) expect(get_response(stub)).to eq(@resp) @@ -227,8 +233,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -240,8 +247,9 @@ describe 'ClientStub' do end it 'should raise an error if the status is not ok' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @fail) stub = GRPC::ClientStub.new(host, @cq) blk = proc { get_response(stub) } expect(&blk).to raise_error(GRPC::BadStatus) @@ -278,16 +286,18 @@ describe 'ClientStub' do end it 'should send a request to/receive replies from a server' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @pass) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @pass) stub = GRPC::ClientStub.new(host, @cq) expect(get_responses(stub).collect { |r| r }).to eq(@replys) th.join end it 'should raise an error if the status is not ok' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @fail) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) @@ -295,8 +305,9 @@ describe 'ClientStub' do end it 'should send metadata to the server ok' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @fail, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @fail, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) @@ -305,8 +316,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -352,8 +364,9 @@ describe 'ClientStub' do end it 'supports sending all the requests first', bidi: true do - host = new_test_host - th = run_bidi_streamer_handle_inputs_first(host, @sent_msgs, @replys, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, @pass) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) @@ -362,8 +375,9 @@ describe 'ClientStub' do end it 'supports client-initiated ping pong', bidi: true do - host = new_test_host - th = run_bidi_streamer_echo_ping_pong(host, @sent_msgs, @pass, true) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) @@ -377,8 +391,9 @@ describe 'ClientStub' do # they receive a message from the client. Without receiving all the # metadata, the server does not accept the call, so this test hangs. xit 'supports a server-initiated ping pong', bidi: true do - host = new_test_host - th = run_bidi_streamer_echo_ping_pong(host, @sent_msgs, @pass, false) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) @@ -410,10 +425,10 @@ describe 'ClientStub' do end end - def run_server_streamer(hostname, expected_input, replys, status, **kw) + def run_server_streamer(expected_input, replys, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end @@ -423,20 +438,19 @@ describe 'ClientStub' do end end - def run_bidi_streamer_handle_inputs_first(hostname, expected_inputs, replys, + def run_bidi_streamer_handle_inputs_first(expected_inputs, replys, status) wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } replys.each { |r| c.remote_send(r) } c.send_status(status, status == @pass ? 'OK' : 'NOK', true) end end - def run_bidi_streamer_echo_ping_pong(hostname, expected_inputs, status, - client_starts) + def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts) wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each do |i| if client_starts expect(c.remote_read).to eq(i) @@ -450,10 +464,10 @@ describe 'ClientStub' do end end - def run_client_streamer(hostname, expected_inputs, resp, status, **kw) + def run_client_streamer(expected_inputs, resp, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -463,10 +477,10 @@ describe 'ClientStub' do end end - def run_request_response(hostname, expected_input, resp, status, **kw) + def run_request_response(expected_input, resp, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expect(c.remote_read).to eq(expected_input) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -476,32 +490,30 @@ describe 'ClientStub' do end end - def start_test_server(hostname, awake_mutex, awake_cond) - server_queue = GRPC::Core::CompletionQueue.new - @server = GRPC::Core::Server.new(server_queue, nil) - @server.add_http2_port(hostname) + def create_test_server + @server_queue = GRPC::Core::CompletionQueue.new + @server = GRPC::Core::Server.new(@server_queue, nil) + @server.add_http2_port('0.0.0.0:0') + end + + def start_test_server(awake_mutex, awake_cond) @server.start @server_tag = Object.new @server.request_call(@server_tag) awake_mutex.synchronize { awake_cond.signal } - server_queue end - def expect_server_to_be_invoked(hostname, awake_mutex, awake_cond) - server_queue = start_test_server(hostname, awake_mutex, awake_cond) - ev = server_queue.pluck(@server_tag, INFINITE_FUTURE) + def expect_server_to_be_invoked(awake_mutex, awake_cond) + start_test_server(awake_mutex, awake_cond) + ev = @server_queue.pluck(@server_tag, INFINITE_FUTURE) fail OutOfTime if ev.nil? server_call = ev.call server_call.metadata = ev.result.metadata finished_tag = Object.new - server_call.server_accept(server_queue, finished_tag) + server_call.server_accept(@server_queue, finished_tag) server_call.server_end_initial_metadata - GRPC::ActiveCall.new(server_call, server_queue, NOOP, NOOP, INFINITE_FUTURE, + GRPC::ActiveCall.new(server_call, @server_queue, NOOP, NOOP, + INFINITE_FUTURE, finished_tag: finished_tag) end - - def new_test_host - port = find_unused_tcp_port - "localhost:#{port}" - end end diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index cd4888a3b4..e083bc1e9d 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -29,7 +29,6 @@ require 'grpc' require 'xray/thread_dump_signal_handler' -require_relative '../port_picker' def load_test_certs test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata') @@ -104,10 +103,10 @@ describe GRPC::RpcServer do @noop = proc { |x| x } @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - @host = "localhost:#{port}" + server_host = '0.0.0.0:0' @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(@host) + server_port = @server.add_http2_port(server_host) + @host = "localhost:#{server_port}" @ch = GRPC::Core::Channel.new(@host, nil) end diff --git a/src/ruby/spec/port_picker.rb b/src/ruby/spec/port_picker.rb deleted file mode 100644 index 98ffbacc1b..0000000000 --- a/src/ruby/spec/port_picker.rb +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2014, 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 'socket' - -# @param [Fixnum] the minimum port number to accept -# @param [Fixnum] the maximum port number to accept -# @return [Fixnum ]a free tcp port -def find_unused_tcp_port(min = 32_768, max = 60_000) - # Allow the system to assign a port, by specifying 0. - # Loop until a port is assigned in the required range - loop do - socket = Socket.new(:INET, :STREAM, 0) - socket.bind(Addrinfo.tcp('127.0.0.1', 0)) - p = socket.local_address.ip_port - socket.close - return p if p > min && p < max - end -end diff --git a/src/ruby/spec/server_spec.rb b/src/ruby/spec/server_spec.rb index 6e5bb523de..1550ba6566 100644 --- a/src/ruby/spec/server_spec.rb +++ b/src/ruby/spec/server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -205,10 +204,8 @@ describe Server do end def start_a_server - port = find_unused_tcp_port - host = "localhost:#{port}" s = Server.new(@cq, nil) - s.add_http2_port(host) + s.add_http2_port('0.0.0.0:0') s.start s end |