blob: 39d1e83748bf4d2812278851ed2b1fbd3fef7a56 [file] [log] [blame]
# 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
EventError = GRPC::Core::EventError
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
describe '#run_server_method' do
describe 'for request responses' do
before(:each) do
@call = double('active_call')
allow(@call).to receive(:single_req_view).and_return(@call)
allow(@call).to receive(:gc)
end
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')
@request_response.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)
@request_response.run_server_method(@call, method(:other_error))
end
it 'absorbs EventError with no further action' do
expect(@call).to receive(:remote_read).once.and_raise(EventError)
blk = proc do
@request_response.run_server_method(@call, method(:fake_reqresp))
end
expect(&blk).to_not raise_error
end
it 'absorbs CallError with no further action' do
expect(@call).to receive(:remote_read).once.and_raise(CallError)
blk = proc do
@request_response.run_server_method(@call, method(:fake_reqresp))
end
expect(&blk).to_not raise_error
end
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(:send_status).once.with(OK, 'OK')
expect(@call).to receive(:finished).once
@request_response.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)
allow(@call).to receive(:gc)
end
it 'sends the specified status if BadStatus is raised' do
expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
@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)
@client_streamer.run_server_method(@call, method(:other_error_alt))
end
it 'absorbs EventError with no further action' do
expect(@call).to receive(:remote_send).once.and_raise(EventError)
blk = proc do
@client_streamer.run_server_method(@call, method(:fake_clstream))
end
expect(&blk).to_not raise_error
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(:send_status).once.with(OK, 'OK')
expect(@call).to receive(:finished).once
@client_streamer.run_server_method(@call, method(:fake_clstream))
end
end
describe 'for server streaming' do
before(:each) do
@call = double('active_call')
allow(@call).to receive(:single_req_view).and_return(@call)
allow(@call).to receive(:gc)
end
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')
@server_streamer.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)
@server_streamer.run_server_method(@call, method(:other_error))
end
it 'absorbs EventError with no further action' do
expect(@call).to receive(:remote_read).once.and_raise(EventError)
blk = proc do
@server_streamer.run_server_method(@call, method(:fake_svstream))
end
expect(&blk).to_not raise_error
end
it 'absorbs CallError with no further action' do
expect(@call).to receive(:remote_read).once.and_raise(CallError)
blk = proc do
@server_streamer.run_server_method(@call, method(:fake_svstream))
end
expect(&blk).to_not raise_error
end
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(:send_status).once.with(OK, 'OK')
expect(@call).to receive(:finished).once
@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)
allow(@call).to receive(:gc)
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')
@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)
@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(:send_status).once.with(OK, 'OK')
expect(@call).to receive(:finished).once
@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