Index: third_party/grpc/src/ruby/spec/generic/rpc_desc_spec.rb |
diff --git a/third_party/grpc/src/ruby/spec/generic/rpc_desc_spec.rb b/third_party/grpc/src/ruby/spec/generic/rpc_desc_spec.rb |
new file mode 100644 |
index 0000000000000000000000000000000000000000..083632a080fbe3f4b7a6e1688f1b412500c93c28 |
--- /dev/null |
+++ b/third_party/grpc/src/ruby/spec/generic/rpc_desc_spec.rb |
@@ -0,0 +1,331 @@ |
+# Copyright 2015, Google Inc. |
+# All rights reserved. |
+# |
+# Redistribution and use in source and binary forms, with or without |
+# modification, are permitted provided that the following conditions are |
+# met: |
+# |
+# * Redistributions of source code must retain the above copyright |
+# notice, this list of conditions and the following disclaimer. |
+# * Redistributions in binary form must reproduce the above |
+# copyright notice, this list of conditions and the following disclaimer |
+# in the documentation and/or other materials provided with the |
+# distribution. |
+# * Neither the name of Google Inc. nor the names of its |
+# contributors may be used to endorse or promote products derived from |
+# this software without specific prior written permission. |
+# |
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+require 'grpc' |
+require 'grpc/generic/rpc_desc' |
+ |
+describe GRPC::RpcDesc do |
+ RpcDesc = GRPC::RpcDesc |
+ Stream = RpcDesc::Stream |
+ OK = GRPC::Core::StatusCodes::OK |
+ INTERNAL = GRPC::Core::StatusCodes::INTERNAL |
+ UNKNOWN = GRPC::Core::StatusCodes::UNKNOWN |
+ CallError = GRPC::Core::CallError |
+ |
+ before(:each) do |
+ @request_response = RpcDesc.new('rr', Object.new, Object.new, 'encode', |
+ 'decode') |
+ @client_streamer = RpcDesc.new('cs', Stream.new(Object.new), Object.new, |
+ 'encode', 'decode') |
+ @server_streamer = RpcDesc.new('ss', Object.new, Stream.new(Object.new), |
+ 'encode', 'decode') |
+ @bidi_streamer = RpcDesc.new('ss', Stream.new(Object.new), |
+ Stream.new(Object.new), 'encode', 'decode') |
+ @bs_code = INTERNAL |
+ @no_reason = 'no reason given' |
+ @ok_response = Object.new |
+ end |
+ |
+ shared_examples 'it handles errors' do |
+ it 'sends the specified status if BadStatus is raised' do |
+ expect(@call).to receive(:remote_read).once.and_return(Object.new) |
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
+ {}) |
+ this_desc.run_server_method(@call, method(:bad_status)) |
+ end |
+ |
+ it 'sends status UNKNOWN if other StandardErrors are raised' do |
+ expect(@call).to receive(:remote_read).once.and_return(Object.new) |
+ expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, |
+ false, {}) |
+ this_desc.run_server_method(@call, method(:other_error)) |
+ end |
+ |
+ it 'absorbs CallError with no further action' do |
+ expect(@call).to receive(:remote_read).once.and_raise(CallError) |
+ blk = proc do |
+ this_desc.run_server_method(@call, method(:fake_reqresp)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ end |
+ |
+ describe '#run_server_method' do |
+ let(:fake_md) { { k1: 'v1', k2: 'v2' } } |
+ describe 'for request responses' do |
+ let(:this_desc) { @request_response } |
+ before(:each) do |
+ @call = double('active_call') |
+ allow(@call).to receive(:single_req_view).and_return(@call) |
+ end |
+ |
+ it_behaves_like 'it handles errors' |
+ |
+ it 'sends a response and closes the stream if there no errors' do |
+ req = Object.new |
+ expect(@call).to receive(:remote_read).once.and_return(req) |
+ expect(@call).to receive(:remote_send).once.with(@ok_response) |
+ expect(@call).to receive(:output_metadata).and_return(fake_md) |
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
+ **fake_md) |
+ this_desc.run_server_method(@call, method(:fake_reqresp)) |
+ end |
+ end |
+ |
+ describe 'for client streamers' do |
+ before(:each) do |
+ @call = double('active_call') |
+ allow(@call).to receive(:multi_req_view).and_return(@call) |
+ end |
+ |
+ it 'sends the specified status if BadStatus is raised' do |
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
+ {}) |
+ @client_streamer.run_server_method(@call, method(:bad_status_alt)) |
+ end |
+ |
+ it 'sends status UNKNOWN if other StandardErrors are raised' do |
+ expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, |
+ false, {}) |
+ @client_streamer.run_server_method(@call, method(:other_error_alt)) |
+ end |
+ |
+ it 'absorbs CallError with no further action' do |
+ expect(@call).to receive(:remote_send).once.and_raise(CallError) |
+ blk = proc do |
+ @client_streamer.run_server_method(@call, method(:fake_clstream)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ |
+ it 'sends a response and closes the stream if there no errors' do |
+ expect(@call).to receive(:remote_send).once.with(@ok_response) |
+ expect(@call).to receive(:output_metadata).and_return(fake_md) |
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
+ **fake_md) |
+ @client_streamer.run_server_method(@call, method(:fake_clstream)) |
+ end |
+ end |
+ |
+ describe 'for server streaming' do |
+ let(:this_desc) { @request_response } |
+ before(:each) do |
+ @call = double('active_call') |
+ allow(@call).to receive(:single_req_view).and_return(@call) |
+ end |
+ |
+ it_behaves_like 'it handles errors' |
+ |
+ it 'sends a response and closes the stream if there no errors' do |
+ req = Object.new |
+ expect(@call).to receive(:remote_read).once.and_return(req) |
+ expect(@call).to receive(:remote_send).twice.with(@ok_response) |
+ expect(@call).to receive(:output_metadata).and_return(fake_md) |
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
+ **fake_md) |
+ @server_streamer.run_server_method(@call, method(:fake_svstream)) |
+ end |
+ end |
+ |
+ describe 'for bidi streamers' do |
+ before(:each) do |
+ @call = double('active_call') |
+ enq_th, rwl_th = double('enqueue_th'), ('read_write_loop_th') |
+ allow(enq_th).to receive(:join) |
+ allow(rwl_th).to receive(:join) |
+ end |
+ |
+ it 'sends the specified status if BadStatus is raised' do |
+ e = GRPC::BadStatus.new(@bs_code, 'NOK') |
+ expect(@call).to receive(:run_server_bidi).and_raise(e) |
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
+ {}) |
+ @bidi_streamer.run_server_method(@call, method(:bad_status_alt)) |
+ end |
+ |
+ it 'sends status UNKNOWN if other StandardErrors are raised' do |
+ expect(@call).to receive(:run_server_bidi).and_raise(StandardError) |
+ expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason, |
+ false, {}) |
+ @bidi_streamer.run_server_method(@call, method(:other_error_alt)) |
+ end |
+ |
+ it 'closes the stream if there no errors' do |
+ expect(@call).to receive(:run_server_bidi) |
+ expect(@call).to receive(:output_metadata).and_return(fake_md) |
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
+ **fake_md) |
+ @bidi_streamer.run_server_method(@call, method(:fake_bidistream)) |
+ end |
+ end |
+ end |
+ |
+ describe '#assert_arity_matches' do |
+ def no_arg |
+ end |
+ |
+ def fake_clstream(_arg) |
+ end |
+ |
+ def fake_svstream(_arg1, _arg2) |
+ end |
+ |
+ it 'raises when a request_response does not have 2 args' do |
+ [:fake_clstream, :no_arg].each do |mth| |
+ blk = proc do |
+ @request_response.assert_arity_matches(method(mth)) |
+ end |
+ expect(&blk).to raise_error |
+ end |
+ end |
+ |
+ it 'passes when a request_response has 2 args' do |
+ blk = proc do |
+ @request_response.assert_arity_matches(method(:fake_svstream)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ |
+ it 'raises when a server_streamer does not have 2 args' do |
+ [:fake_clstream, :no_arg].each do |mth| |
+ blk = proc do |
+ @server_streamer.assert_arity_matches(method(mth)) |
+ end |
+ expect(&blk).to raise_error |
+ end |
+ end |
+ |
+ it 'passes when a server_streamer has 2 args' do |
+ blk = proc do |
+ @server_streamer.assert_arity_matches(method(:fake_svstream)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ |
+ it 'raises when a client streamer does not have 1 arg' do |
+ [:fake_svstream, :no_arg].each do |mth| |
+ blk = proc do |
+ @client_streamer.assert_arity_matches(method(mth)) |
+ end |
+ expect(&blk).to raise_error |
+ end |
+ end |
+ |
+ it 'passes when a client_streamer has 1 arg' do |
+ blk = proc do |
+ @client_streamer.assert_arity_matches(method(:fake_clstream)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ |
+ it 'raises when a bidi streamer does not have 1 arg' do |
+ [:fake_svstream, :no_arg].each do |mth| |
+ blk = proc do |
+ @bidi_streamer.assert_arity_matches(method(mth)) |
+ end |
+ expect(&blk).to raise_error |
+ end |
+ end |
+ |
+ it 'passes when a bidi streamer has 1 arg' do |
+ blk = proc do |
+ @bidi_streamer.assert_arity_matches(method(:fake_clstream)) |
+ end |
+ expect(&blk).to_not raise_error |
+ end |
+ end |
+ |
+ describe '#request_response?' do |
+ it 'is true only input and output are both not Streams' do |
+ expect(@request_response.request_response?).to be(true) |
+ expect(@client_streamer.request_response?).to be(false) |
+ expect(@bidi_streamer.request_response?).to be(false) |
+ expect(@server_streamer.request_response?).to be(false) |
+ end |
+ end |
+ |
+ describe '#client_streamer?' do |
+ it 'is true only when input is a Stream and output is not a Stream' do |
+ expect(@client_streamer.client_streamer?).to be(true) |
+ expect(@request_response.client_streamer?).to be(false) |
+ expect(@server_streamer.client_streamer?).to be(false) |
+ expect(@bidi_streamer.client_streamer?).to be(false) |
+ end |
+ end |
+ |
+ describe '#server_streamer?' do |
+ it 'is true only when output is a Stream and input is not a Stream' do |
+ expect(@server_streamer.server_streamer?).to be(true) |
+ expect(@client_streamer.server_streamer?).to be(false) |
+ expect(@request_response.server_streamer?).to be(false) |
+ expect(@bidi_streamer.server_streamer?).to be(false) |
+ end |
+ end |
+ |
+ describe '#bidi_streamer?' do |
+ it 'is true only when output is a Stream and input is a Stream' do |
+ expect(@bidi_streamer.bidi_streamer?).to be(true) |
+ expect(@server_streamer.bidi_streamer?).to be(false) |
+ expect(@client_streamer.bidi_streamer?).to be(false) |
+ expect(@request_response.bidi_streamer?).to be(false) |
+ end |
+ end |
+ |
+ def fake_reqresp(_req, _call) |
+ @ok_response |
+ end |
+ |
+ def fake_clstream(_call) |
+ @ok_response |
+ end |
+ |
+ def fake_svstream(_req, _call) |
+ [@ok_response, @ok_response] |
+ end |
+ |
+ def fake_bidistream(an_array) |
+ an_array |
+ end |
+ |
+ def bad_status(_req, _call) |
+ fail GRPC::BadStatus.new(@bs_code, 'NOK') |
+ end |
+ |
+ def other_error(_req, _call) |
+ fail(ArgumentError, 'other error') |
+ end |
+ |
+ def bad_status_alt(_call) |
+ fail GRPC::BadStatus.new(@bs_code, 'NOK') |
+ end |
+ |
+ def other_error_alt(_call) |
+ fail(ArgumentError, 'other error') |
+ end |
+end |