OLD | NEW |
(Empty) | |
| 1 # Copyright 2015, Google Inc. |
| 2 # All rights reserved. |
| 3 # |
| 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are |
| 6 # met: |
| 7 # |
| 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above |
| 11 # copyright notice, this list of conditions and the following disclaimer |
| 12 # in the documentation and/or other materials provided with the |
| 13 # distribution. |
| 14 # * Neither the name of Google Inc. nor the names of its |
| 15 # contributors may be used to endorse or promote products derived from |
| 16 # this software without specific prior written permission. |
| 17 # |
| 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 |
| 30 require 'grpc' |
| 31 require 'grpc/generic/rpc_desc' |
| 32 |
| 33 describe GRPC::RpcDesc do |
| 34 RpcDesc = GRPC::RpcDesc |
| 35 Stream = RpcDesc::Stream |
| 36 OK = GRPC::Core::StatusCodes::OK |
| 37 INTERNAL = GRPC::Core::StatusCodes::INTERNAL |
| 38 UNKNOWN = GRPC::Core::StatusCodes::UNKNOWN |
| 39 CallError = GRPC::Core::CallError |
| 40 |
| 41 before(:each) do |
| 42 @request_response = RpcDesc.new('rr', Object.new, Object.new, 'encode', |
| 43 'decode') |
| 44 @client_streamer = RpcDesc.new('cs', Stream.new(Object.new), Object.new, |
| 45 'encode', 'decode') |
| 46 @server_streamer = RpcDesc.new('ss', Object.new, Stream.new(Object.new), |
| 47 'encode', 'decode') |
| 48 @bidi_streamer = RpcDesc.new('ss', Stream.new(Object.new), |
| 49 Stream.new(Object.new), 'encode', 'decode') |
| 50 @bs_code = INTERNAL |
| 51 @no_reason = 'no reason given' |
| 52 @ok_response = Object.new |
| 53 end |
| 54 |
| 55 shared_examples 'it handles errors' do |
| 56 it 'sends the specified status if BadStatus is raised' do |
| 57 expect(@call).to receive(:remote_read).once.and_return(Object.new) |
| 58 expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
| 59 {}) |
| 60 this_desc.run_server_method(@call, method(:bad_status)) |
| 61 end |
| 62 |
| 63 it 'sends status UNKNOWN if other StandardErrors are raised' do |
| 64 expect(@call).to receive(:remote_read).once.and_return(Object.new) |
| 65 expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, |
| 66 false, {}) |
| 67 this_desc.run_server_method(@call, method(:other_error)) |
| 68 end |
| 69 |
| 70 it 'absorbs CallError with no further action' do |
| 71 expect(@call).to receive(:remote_read).once.and_raise(CallError) |
| 72 blk = proc do |
| 73 this_desc.run_server_method(@call, method(:fake_reqresp)) |
| 74 end |
| 75 expect(&blk).to_not raise_error |
| 76 end |
| 77 end |
| 78 |
| 79 describe '#run_server_method' do |
| 80 let(:fake_md) { { k1: 'v1', k2: 'v2' } } |
| 81 describe 'for request responses' do |
| 82 let(:this_desc) { @request_response } |
| 83 before(:each) do |
| 84 @call = double('active_call') |
| 85 allow(@call).to receive(:single_req_view).and_return(@call) |
| 86 end |
| 87 |
| 88 it_behaves_like 'it handles errors' |
| 89 |
| 90 it 'sends a response and closes the stream if there no errors' do |
| 91 req = Object.new |
| 92 expect(@call).to receive(:remote_read).once.and_return(req) |
| 93 expect(@call).to receive(:remote_send).once.with(@ok_response) |
| 94 expect(@call).to receive(:output_metadata).and_return(fake_md) |
| 95 expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
| 96 **fake_md) |
| 97 this_desc.run_server_method(@call, method(:fake_reqresp)) |
| 98 end |
| 99 end |
| 100 |
| 101 describe 'for client streamers' do |
| 102 before(:each) do |
| 103 @call = double('active_call') |
| 104 allow(@call).to receive(:multi_req_view).and_return(@call) |
| 105 end |
| 106 |
| 107 it 'sends the specified status if BadStatus is raised' do |
| 108 expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
| 109 {}) |
| 110 @client_streamer.run_server_method(@call, method(:bad_status_alt)) |
| 111 end |
| 112 |
| 113 it 'sends status UNKNOWN if other StandardErrors are raised' do |
| 114 expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, |
| 115 false, {}) |
| 116 @client_streamer.run_server_method(@call, method(:other_error_alt)) |
| 117 end |
| 118 |
| 119 it 'absorbs CallError with no further action' do |
| 120 expect(@call).to receive(:remote_send).once.and_raise(CallError) |
| 121 blk = proc do |
| 122 @client_streamer.run_server_method(@call, method(:fake_clstream)) |
| 123 end |
| 124 expect(&blk).to_not raise_error |
| 125 end |
| 126 |
| 127 it 'sends a response and closes the stream if there no errors' do |
| 128 expect(@call).to receive(:remote_send).once.with(@ok_response) |
| 129 expect(@call).to receive(:output_metadata).and_return(fake_md) |
| 130 expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
| 131 **fake_md) |
| 132 @client_streamer.run_server_method(@call, method(:fake_clstream)) |
| 133 end |
| 134 end |
| 135 |
| 136 describe 'for server streaming' do |
| 137 let(:this_desc) { @request_response } |
| 138 before(:each) do |
| 139 @call = double('active_call') |
| 140 allow(@call).to receive(:single_req_view).and_return(@call) |
| 141 end |
| 142 |
| 143 it_behaves_like 'it handles errors' |
| 144 |
| 145 it 'sends a response and closes the stream if there no errors' do |
| 146 req = Object.new |
| 147 expect(@call).to receive(:remote_read).once.and_return(req) |
| 148 expect(@call).to receive(:remote_send).twice.with(@ok_response) |
| 149 expect(@call).to receive(:output_metadata).and_return(fake_md) |
| 150 expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
| 151 **fake_md) |
| 152 @server_streamer.run_server_method(@call, method(:fake_svstream)) |
| 153 end |
| 154 end |
| 155 |
| 156 describe 'for bidi streamers' do |
| 157 before(:each) do |
| 158 @call = double('active_call') |
| 159 enq_th, rwl_th = double('enqueue_th'), ('read_write_loop_th') |
| 160 allow(enq_th).to receive(:join) |
| 161 allow(rwl_th).to receive(:join) |
| 162 end |
| 163 |
| 164 it 'sends the specified status if BadStatus is raised' do |
| 165 e = GRPC::BadStatus.new(@bs_code, 'NOK') |
| 166 expect(@call).to receive(:run_server_bidi).and_raise(e) |
| 167 expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, |
| 168 {}) |
| 169 @bidi_streamer.run_server_method(@call, method(:bad_status_alt)) |
| 170 end |
| 171 |
| 172 it 'sends status UNKNOWN if other StandardErrors are raised' do |
| 173 expect(@call).to receive(:run_server_bidi).and_raise(StandardError) |
| 174 expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason, |
| 175 false, {}) |
| 176 @bidi_streamer.run_server_method(@call, method(:other_error_alt)) |
| 177 end |
| 178 |
| 179 it 'closes the stream if there no errors' do |
| 180 expect(@call).to receive(:run_server_bidi) |
| 181 expect(@call).to receive(:output_metadata).and_return(fake_md) |
| 182 expect(@call).to receive(:send_status).once.with(OK, 'OK', true, |
| 183 **fake_md) |
| 184 @bidi_streamer.run_server_method(@call, method(:fake_bidistream)) |
| 185 end |
| 186 end |
| 187 end |
| 188 |
| 189 describe '#assert_arity_matches' do |
| 190 def no_arg |
| 191 end |
| 192 |
| 193 def fake_clstream(_arg) |
| 194 end |
| 195 |
| 196 def fake_svstream(_arg1, _arg2) |
| 197 end |
| 198 |
| 199 it 'raises when a request_response does not have 2 args' do |
| 200 [:fake_clstream, :no_arg].each do |mth| |
| 201 blk = proc do |
| 202 @request_response.assert_arity_matches(method(mth)) |
| 203 end |
| 204 expect(&blk).to raise_error |
| 205 end |
| 206 end |
| 207 |
| 208 it 'passes when a request_response has 2 args' do |
| 209 blk = proc do |
| 210 @request_response.assert_arity_matches(method(:fake_svstream)) |
| 211 end |
| 212 expect(&blk).to_not raise_error |
| 213 end |
| 214 |
| 215 it 'raises when a server_streamer does not have 2 args' do |
| 216 [:fake_clstream, :no_arg].each do |mth| |
| 217 blk = proc do |
| 218 @server_streamer.assert_arity_matches(method(mth)) |
| 219 end |
| 220 expect(&blk).to raise_error |
| 221 end |
| 222 end |
| 223 |
| 224 it 'passes when a server_streamer has 2 args' do |
| 225 blk = proc do |
| 226 @server_streamer.assert_arity_matches(method(:fake_svstream)) |
| 227 end |
| 228 expect(&blk).to_not raise_error |
| 229 end |
| 230 |
| 231 it 'raises when a client streamer does not have 1 arg' do |
| 232 [:fake_svstream, :no_arg].each do |mth| |
| 233 blk = proc do |
| 234 @client_streamer.assert_arity_matches(method(mth)) |
| 235 end |
| 236 expect(&blk).to raise_error |
| 237 end |
| 238 end |
| 239 |
| 240 it 'passes when a client_streamer has 1 arg' do |
| 241 blk = proc do |
| 242 @client_streamer.assert_arity_matches(method(:fake_clstream)) |
| 243 end |
| 244 expect(&blk).to_not raise_error |
| 245 end |
| 246 |
| 247 it 'raises when a bidi streamer does not have 1 arg' do |
| 248 [:fake_svstream, :no_arg].each do |mth| |
| 249 blk = proc do |
| 250 @bidi_streamer.assert_arity_matches(method(mth)) |
| 251 end |
| 252 expect(&blk).to raise_error |
| 253 end |
| 254 end |
| 255 |
| 256 it 'passes when a bidi streamer has 1 arg' do |
| 257 blk = proc do |
| 258 @bidi_streamer.assert_arity_matches(method(:fake_clstream)) |
| 259 end |
| 260 expect(&blk).to_not raise_error |
| 261 end |
| 262 end |
| 263 |
| 264 describe '#request_response?' do |
| 265 it 'is true only input and output are both not Streams' do |
| 266 expect(@request_response.request_response?).to be(true) |
| 267 expect(@client_streamer.request_response?).to be(false) |
| 268 expect(@bidi_streamer.request_response?).to be(false) |
| 269 expect(@server_streamer.request_response?).to be(false) |
| 270 end |
| 271 end |
| 272 |
| 273 describe '#client_streamer?' do |
| 274 it 'is true only when input is a Stream and output is not a Stream' do |
| 275 expect(@client_streamer.client_streamer?).to be(true) |
| 276 expect(@request_response.client_streamer?).to be(false) |
| 277 expect(@server_streamer.client_streamer?).to be(false) |
| 278 expect(@bidi_streamer.client_streamer?).to be(false) |
| 279 end |
| 280 end |
| 281 |
| 282 describe '#server_streamer?' do |
| 283 it 'is true only when output is a Stream and input is not a Stream' do |
| 284 expect(@server_streamer.server_streamer?).to be(true) |
| 285 expect(@client_streamer.server_streamer?).to be(false) |
| 286 expect(@request_response.server_streamer?).to be(false) |
| 287 expect(@bidi_streamer.server_streamer?).to be(false) |
| 288 end |
| 289 end |
| 290 |
| 291 describe '#bidi_streamer?' do |
| 292 it 'is true only when output is a Stream and input is a Stream' do |
| 293 expect(@bidi_streamer.bidi_streamer?).to be(true) |
| 294 expect(@server_streamer.bidi_streamer?).to be(false) |
| 295 expect(@client_streamer.bidi_streamer?).to be(false) |
| 296 expect(@request_response.bidi_streamer?).to be(false) |
| 297 end |
| 298 end |
| 299 |
| 300 def fake_reqresp(_req, _call) |
| 301 @ok_response |
| 302 end |
| 303 |
| 304 def fake_clstream(_call) |
| 305 @ok_response |
| 306 end |
| 307 |
| 308 def fake_svstream(_req, _call) |
| 309 [@ok_response, @ok_response] |
| 310 end |
| 311 |
| 312 def fake_bidistream(an_array) |
| 313 an_array |
| 314 end |
| 315 |
| 316 def bad_status(_req, _call) |
| 317 fail GRPC::BadStatus.new(@bs_code, 'NOK') |
| 318 end |
| 319 |
| 320 def other_error(_req, _call) |
| 321 fail(ArgumentError, 'other error') |
| 322 end |
| 323 |
| 324 def bad_status_alt(_call) |
| 325 fail GRPC::BadStatus.new(@bs_code, 'NOK') |
| 326 end |
| 327 |
| 328 def other_error_alt(_call) |
| 329 fail(ArgumentError, 'other error') |
| 330 end |
| 331 end |
OLD | NEW |