Craig Tiller | 6169d5f | 2016-03-31 07:46:18 -0700 | [diff] [blame] | 1 | # Copyright 2015, Google Inc. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 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' |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 31 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 32 | def load_test_certs |
temiola | 6919c75 | 2014-12-10 13:22:00 -0800 | [diff] [blame] | 33 | test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata') |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 34 | files = ['ca.pem', 'server1.key', 'server1.pem'] |
| 35 | files.map { |f| File.open(File.join(test_root, f)).read } |
| 36 | end |
| 37 | |
Craig Tiller | 83ac705 | 2015-07-15 11:53:13 -0700 | [diff] [blame] | 38 | def check_md(wanted_md, received_md) |
| 39 | wanted_md.zip(received_md).each do |w, r| |
| 40 | w.each do |key, value| |
| 41 | expect(r[key]).to eq(value) |
| 42 | end |
| 43 | end |
| 44 | end |
| 45 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 46 | # A test message |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 47 | class EchoMsg |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 48 | def self.marshal(_o) |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 49 | '' |
| 50 | end |
| 51 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 52 | def self.unmarshal(_o) |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 53 | EchoMsg.new |
| 54 | end |
| 55 | end |
| 56 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 57 | # A test service with no methods. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 58 | class EmptyService |
| 59 | include GRPC::GenericService |
| 60 | end |
| 61 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 62 | # A test service without an implementation. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 63 | class NoRpcImplementation |
| 64 | include GRPC::GenericService |
| 65 | rpc :an_rpc, EchoMsg, EchoMsg |
| 66 | end |
| 67 | |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 68 | # A test service with an echo implementation. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 69 | class EchoService |
| 70 | include GRPC::GenericService |
| 71 | rpc :an_rpc, EchoMsg, EchoMsg |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 72 | attr_reader :received_md |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 73 | |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 74 | def initialize(**kw) |
| 75 | @trailing_metadata = kw |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 76 | @received_md = [] |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 77 | end |
| 78 | |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 79 | def an_rpc(req, call) |
Nick Gauthier | f233d96 | 2015-05-20 14:02:50 -0400 | [diff] [blame] | 80 | GRPC.logger.info('echo service received a request') |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 81 | call.output_metadata.update(@trailing_metadata) |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 82 | @received_md << call.metadata unless call.metadata.nil? |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 83 | req |
| 84 | end |
| 85 | end |
| 86 | |
| 87 | EchoStub = EchoService.rpc_stub_class |
| 88 | |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 89 | # A test service with an implementation that fails with BadStatus |
| 90 | class FailingService |
| 91 | include GRPC::GenericService |
| 92 | rpc :an_rpc, EchoMsg, EchoMsg |
| 93 | attr_reader :details, :code, :md |
| 94 | |
| 95 | def initialize(_default_var = 'ignored') |
| 96 | @details = 'app error' |
| 97 | @code = 101 |
murgatroid99 | e69f088 | 2016-07-07 15:52:27 -0700 | [diff] [blame] | 98 | @md = { 'failed_method' => 'an_rpc' } |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 99 | end |
| 100 | |
| 101 | def an_rpc(_req, _call) |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 102 | fail GRPC::BadStatus.new(@code, @details, @md) |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 103 | end |
| 104 | end |
| 105 | |
| 106 | FailingStub = FailingService.rpc_stub_class |
| 107 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 108 | # A slow test service. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 109 | class SlowService |
| 110 | include GRPC::GenericService |
| 111 | rpc :an_rpc, EchoMsg, EchoMsg |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 112 | attr_reader :received_md, :delay |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 113 | |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 114 | def initialize(_default_var = 'ignored') |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 115 | @delay = 0.25 |
| 116 | @received_md = [] |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 117 | end |
| 118 | |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 119 | def an_rpc(req, call) |
Nick Gauthier | f233d96 | 2015-05-20 14:02:50 -0400 | [diff] [blame] | 120 | GRPC.logger.info("starting a slow #{@delay} rpc") |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 121 | sleep @delay |
| 122 | @received_md << call.metadata unless call.metadata.nil? |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 123 | req # send back the req as the response |
| 124 | end |
| 125 | end |
| 126 | |
| 127 | SlowStub = SlowService.rpc_stub_class |
| 128 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 129 | describe GRPC::RpcServer do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 130 | RpcServer = GRPC::RpcServer |
temiola | 6919c75 | 2014-12-10 13:22:00 -0800 | [diff] [blame] | 131 | StatusCodes = GRPC::Core::StatusCodes |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 132 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 133 | before(:each) do |
| 134 | @method = 'an_rpc_method' |
| 135 | @pass = 0 |
| 136 | @fail = 1 |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 137 | @noop = proc { |x| x } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 138 | end |
| 139 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 140 | describe '#new' do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 141 | it 'can be created with just some args' do |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 142 | opts = { server_args: { a_channel_arg: 'an_arg' } } |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 143 | blk = proc do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 144 | RpcServer.new(**opts) |
| 145 | end |
| 146 | expect(&blk).not_to raise_error |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 147 | end |
| 148 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 149 | it 'cannot be created with invalid ServerCredentials' do |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 150 | blk = proc do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 151 | opts = { |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 152 | server_args: { a_channel_arg: 'an_arg' }, |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 153 | creds: Object.new |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 154 | } |
| 155 | RpcServer.new(**opts) |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 156 | end |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 157 | expect(&blk).to raise_error |
| 158 | end |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 159 | end |
| 160 | |
| 161 | describe '#stopped?' do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 162 | before(:each) do |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 163 | opts = { server_args: { a_channel_arg: 'an_arg' }, poll_period: 1.5 } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 164 | @srv = RpcServer.new(**opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 165 | @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 166 | end |
| 167 | |
| 168 | it 'starts out false' do |
| 169 | expect(@srv.stopped?).to be(false) |
| 170 | end |
| 171 | |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 172 | it 'stays false after the server starts running', server: true do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 173 | @srv.handle(EchoService) |
| 174 | t = Thread.new { @srv.run } |
| 175 | @srv.wait_till_running |
| 176 | expect(@srv.stopped?).to be(false) |
| 177 | @srv.stop |
| 178 | t.join |
| 179 | end |
| 180 | |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 181 | it 'is true after a running server is stopped', server: true do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 182 | @srv.handle(EchoService) |
| 183 | t = Thread.new { @srv.run } |
| 184 | @srv.wait_till_running |
| 185 | @srv.stop |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 186 | t.join |
murgatroid99 | d48d84d | 2016-03-09 11:10:20 -0800 | [diff] [blame] | 187 | expect(@srv.stopped?).to be(true) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 188 | end |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 189 | end |
| 190 | |
| 191 | describe '#running?' do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 192 | it 'starts out false' do |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 193 | opts = { |
| 194 | server_args: { a_channel_arg: 'an_arg' } |
| 195 | } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 196 | r = RpcServer.new(**opts) |
| 197 | expect(r.running?).to be(false) |
| 198 | end |
| 199 | |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 200 | it 'is false if run is called with no services registered', server: true do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 201 | opts = { |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 202 | server_args: { a_channel_arg: 'an_arg' }, |
| 203 | poll_period: 2 |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 204 | } |
| 205 | r = RpcServer.new(**opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 206 | r.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
murgatroid99 | d48d84d | 2016-03-09 11:10:20 -0800 | [diff] [blame] | 207 | expect { r.run }.to raise_error(RuntimeError) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 208 | end |
| 209 | |
| 210 | it 'is true after run is called with a registered service' do |
| 211 | opts = { |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 212 | server_args: { a_channel_arg: 'an_arg' }, |
| 213 | poll_period: 2.5 |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 214 | } |
| 215 | r = RpcServer.new(**opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 216 | r.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 217 | r.handle(EchoService) |
| 218 | t = Thread.new { r.run } |
| 219 | r.wait_till_running |
| 220 | expect(r.running?).to be(true) |
| 221 | r.stop |
| 222 | t.join |
| 223 | end |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 224 | end |
| 225 | |
| 226 | describe '#handle' do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 227 | before(:each) do |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 228 | @opts = { server_args: { a_channel_arg: 'an_arg' }, poll_period: 1 } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 229 | @srv = RpcServer.new(**@opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 230 | @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 231 | end |
| 232 | |
| 233 | it 'raises if #run has already been called' do |
| 234 | @srv.handle(EchoService) |
| 235 | t = Thread.new { @srv.run } |
| 236 | @srv.wait_till_running |
| 237 | expect { @srv.handle(EchoService) }.to raise_error |
| 238 | @srv.stop |
| 239 | t.join |
| 240 | end |
| 241 | |
| 242 | it 'raises if the server has been run and stopped' do |
| 243 | @srv.handle(EchoService) |
| 244 | t = Thread.new { @srv.run } |
| 245 | @srv.wait_till_running |
| 246 | @srv.stop |
| 247 | t.join |
| 248 | expect { @srv.handle(EchoService) }.to raise_error |
| 249 | end |
| 250 | |
| 251 | it 'raises if the service does not include GenericService ' do |
| 252 | expect { @srv.handle(Object) }.to raise_error |
| 253 | end |
| 254 | |
| 255 | it 'raises if the service does not declare any rpc methods' do |
| 256 | expect { @srv.handle(EmptyService) }.to raise_error |
| 257 | end |
| 258 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 259 | it 'raises if a handler method is already registered' do |
| 260 | @srv.handle(EchoService) |
| 261 | expect { r.handle(EchoService) }.to raise_error |
| 262 | end |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 263 | end |
| 264 | |
| 265 | describe '#run' do |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 266 | let(:client_opts) { { channel_override: @ch } } |
| 267 | let(:marshal) { EchoService.rpc_descs[:an_rpc].marshal_proc } |
| 268 | let(:unmarshal) { EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output) } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 269 | |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 270 | context 'with no connect_metadata' do |
| 271 | before(:each) do |
| 272 | server_opts = { |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 273 | poll_period: 1 |
| 274 | } |
| 275 | @srv = RpcServer.new(**server_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 276 | server_port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
murgatroid99 | b19f181 | 2016-05-16 12:21:39 -0700 | [diff] [blame] | 277 | @host = "localhost:#{server_port}" |
| 278 | @ch = GRPC::Core::Channel.new(@host, nil, :this_channel_is_insecure) |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 279 | end |
| 280 | |
Tim Emiola | 91044c1 | 2015-01-29 13:25:08 -0800 | [diff] [blame] | 281 | it 'should return NOT_FOUND status on unknown methods', server: true do |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 282 | @srv.handle(EchoService) |
| 283 | t = Thread.new { @srv.run } |
| 284 | @srv.wait_till_running |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 285 | req = EchoMsg.new |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 286 | blk = proc do |
murgatroid99 | 5ea4a99 | 2016-06-13 10:36:41 -0700 | [diff] [blame] | 287 | stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure, |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 288 | **client_opts) |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 289 | stub.request_response('/unknown', req, marshal, unmarshal) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 290 | end |
temiola | 6919c75 | 2014-12-10 13:22:00 -0800 | [diff] [blame] | 291 | expect(&blk).to raise_error GRPC::BadStatus |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 292 | @srv.stop |
| 293 | t.join |
| 294 | end |
| 295 | |
murgatroid99 | cf239e7 | 2016-05-06 14:48:21 -0700 | [diff] [blame] | 296 | it 'should return UNIMPLEMENTED on unimplemented methods', server: true do |
| 297 | @srv.handle(NoRpcImplementation) |
| 298 | t = Thread.new { @srv.run } |
| 299 | @srv.wait_till_running |
| 300 | req = EchoMsg.new |
| 301 | blk = proc do |
murgatroid99 | 5ea4a99 | 2016-06-13 10:36:41 -0700 | [diff] [blame] | 302 | stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure, |
murgatroid99 | cf239e7 | 2016-05-06 14:48:21 -0700 | [diff] [blame] | 303 | **client_opts) |
| 304 | stub.request_response('/an_rpc', req, marshal, unmarshal) |
| 305 | end |
| 306 | expect(&blk).to raise_error do |error| |
| 307 | expect(error).to be_a(GRPC::BadStatus) |
| 308 | expect(error.code).to be(GRPC::Core::StatusCodes::UNIMPLEMENTED) |
| 309 | end |
| 310 | @srv.stop |
| 311 | t.join |
| 312 | end |
| 313 | |
Tim Emiola | 91044c1 | 2015-01-29 13:25:08 -0800 | [diff] [blame] | 314 | it 'should handle multiple sequential requests', server: true do |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 315 | @srv.handle(EchoService) |
| 316 | t = Thread.new { @srv.run } |
| 317 | @srv.wait_till_running |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 318 | req = EchoMsg.new |
| 319 | n = 5 # arbitrary |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 320 | stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts) |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 321 | n.times { expect(stub.an_rpc(req)).to be_a(EchoMsg) } |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 322 | @srv.stop |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 323 | t.join |
| 324 | end |
| 325 | |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 326 | it 'should receive metadata sent as rpc keyword args', server: true do |
| 327 | service = EchoService.new |
| 328 | @srv.handle(service) |
| 329 | t = Thread.new { @srv.run } |
| 330 | @srv.wait_till_running |
| 331 | req = EchoMsg.new |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 332 | stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 333 | expect(stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' })) |
| 334 | .to be_a(EchoMsg) |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 335 | wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }] |
Craig Tiller | 83ac705 | 2015-07-15 11:53:13 -0700 | [diff] [blame] | 336 | check_md(wanted_md, service.received_md) |
Tim Emiola | 62e3cc8 | 2015-03-17 21:20:47 -0700 | [diff] [blame] | 337 | @srv.stop |
| 338 | t.join |
| 339 | end |
| 340 | |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 341 | it 'should receive metadata if a deadline is specified', server: true do |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 342 | service = SlowService.new |
| 343 | @srv.handle(service) |
| 344 | t = Thread.new { @srv.run } |
| 345 | @srv.wait_till_running |
| 346 | req = EchoMsg.new |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 347 | stub = SlowStub.new(@host, :this_channel_is_insecure, **client_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 348 | timeout = service.delay + 1.0 |
| 349 | deadline = GRPC::Core::TimeConsts.from_relative_time(timeout) |
| 350 | resp = stub.an_rpc(req, |
| 351 | deadline: deadline, |
| 352 | metadata: { k1: 'v1', k2: 'v2' }) |
Tim Emiola | 49b7650 | 2015-08-13 14:12:15 -0700 | [diff] [blame] | 353 | expect(resp).to be_a(EchoMsg) |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 354 | wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }] |
Craig Tiller | 83ac705 | 2015-07-15 11:53:13 -0700 | [diff] [blame] | 355 | check_md(wanted_md, service.received_md) |
Tim Emiola | 77e2fb0 | 2015-03-19 23:10:10 -0700 | [diff] [blame] | 356 | @srv.stop |
| 357 | t.join |
| 358 | end |
| 359 | |
Tim Emiola | 72d70fc | 2015-04-15 08:06:16 -0700 | [diff] [blame] | 360 | it 'should handle cancellation correctly', server: true do |
| 361 | service = SlowService.new |
| 362 | @srv.handle(service) |
| 363 | t = Thread.new { @srv.run } |
| 364 | @srv.wait_till_running |
| 365 | req = EchoMsg.new |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 366 | stub = SlowStub.new(@host, :this_channel_is_insecure, **client_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 367 | op = stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }, return_op: true) |
Tim Emiola | 1b39916 | 2015-04-15 08:09:25 -0700 | [diff] [blame] | 368 | Thread.new do # cancel the call |
Tim Emiola | 72d70fc | 2015-04-15 08:06:16 -0700 | [diff] [blame] | 369 | sleep 0.1 |
| 370 | op.cancel |
| 371 | end |
Tim Emiola | 1b39916 | 2015-04-15 08:09:25 -0700 | [diff] [blame] | 372 | expect { op.execute }.to raise_error GRPC::Cancelled |
Tim Emiola | 72d70fc | 2015-04-15 08:06:16 -0700 | [diff] [blame] | 373 | @srv.stop |
| 374 | t.join |
| 375 | end |
| 376 | |
Tim Emiola | 91044c1 | 2015-01-29 13:25:08 -0800 | [diff] [blame] | 377 | it 'should handle multiple parallel requests', server: true do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 378 | @srv.handle(EchoService) |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 379 | t = Thread.new { @srv.run } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 380 | @srv.wait_till_running |
| 381 | req, q = EchoMsg.new, Queue.new |
| 382 | n = 5 # arbitrary |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 383 | threads = [t] |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 384 | n.times do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 385 | threads << Thread.new do |
murgatroid99 | afe3974 | 2015-12-16 13:04:37 -0800 | [diff] [blame] | 386 | stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 387 | q << stub.an_rpc(req) |
| 388 | end |
| 389 | end |
| 390 | n.times { expect(q.pop).to be_a(EchoMsg) } |
| 391 | @srv.stop |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 392 | threads.each(&:join) |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 393 | end |
| 394 | |
murgatroid99 | 895c111 | 2016-04-04 11:27:51 -0700 | [diff] [blame] | 395 | it 'should return RESOURCE_EXHAUSTED on too many jobs', server: true do |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 396 | opts = { |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 397 | server_args: { a_channel_arg: 'an_arg' }, |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 398 | pool_size: 2, |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 399 | poll_period: 1, |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 400 | max_waiting_requests: 1 |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 401 | } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 402 | alt_srv = RpcServer.new(**opts) |
| 403 | alt_srv.handle(SlowService) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 404 | alt_port = alt_srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
| 405 | alt_host = "0.0.0.0:#{alt_port}" |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 406 | t = Thread.new { alt_srv.run } |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 407 | alt_srv.wait_till_running |
| 408 | req = EchoMsg.new |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 409 | n = 20 # arbitrary, use as many to ensure the server pool is exceeded |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 410 | threads = [] |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 411 | bad_status_code = nil |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 412 | n.times do |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 413 | threads << Thread.new do |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 414 | stub = SlowStub.new(alt_host, :this_channel_is_insecure) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 415 | begin |
| 416 | stub.an_rpc(req) |
temiola | 6919c75 | 2014-12-10 13:22:00 -0800 | [diff] [blame] | 417 | rescue GRPC::BadStatus => e |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 418 | bad_status_code = e.code |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 419 | end |
| 420 | end |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 421 | end |
Tim Emiola | e2860c5 | 2015-01-16 02:58:41 -0800 | [diff] [blame] | 422 | threads.each(&:join) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 423 | alt_srv.stop |
Tim Emiola | 4aba356 | 2015-05-22 17:25:49 -0700 | [diff] [blame] | 424 | t.join |
Alexander Polcyn | 9c74487 | 2016-08-12 14:58:10 -0700 | [diff] [blame] | 425 | expect(bad_status_code).to be(StatusCodes::RESOURCE_EXHAUSTED) |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 426 | end |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 427 | end |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 428 | |
| 429 | context 'with connect metadata' do |
| 430 | let(:test_md_proc) do |
| 431 | proc do |mth, md| |
| 432 | res = md.clone |
| 433 | res['method'] = mth |
| 434 | res['connect_k1'] = 'connect_v1' |
| 435 | res |
| 436 | end |
| 437 | end |
| 438 | before(:each) do |
| 439 | server_opts = { |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 440 | poll_period: 1, |
| 441 | connect_md_proc: test_md_proc |
| 442 | } |
| 443 | @srv = RpcServer.new(**server_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 444 | alt_port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
| 445 | @alt_host = "0.0.0.0:#{alt_port}" |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 446 | end |
| 447 | |
| 448 | it 'should send connect metadata to the client', server: true do |
| 449 | service = EchoService.new |
| 450 | @srv.handle(service) |
| 451 | t = Thread.new { @srv.run } |
| 452 | @srv.wait_till_running |
| 453 | req = EchoMsg.new |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 454 | stub = EchoStub.new(@alt_host, :this_channel_is_insecure) |
| 455 | op = stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }, return_op: true) |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 456 | expect(op.metadata).to be nil |
| 457 | expect(op.execute).to be_a(EchoMsg) |
| 458 | wanted_md = { |
| 459 | 'k1' => 'v1', |
| 460 | 'k2' => 'v2', |
| 461 | 'method' => '/EchoService/an_rpc', |
| 462 | 'connect_k1' => 'connect_v1' |
| 463 | } |
Craig Tiller | 83ac705 | 2015-07-15 11:53:13 -0700 | [diff] [blame] | 464 | wanted_md.each do |key, value| |
| 465 | expect(op.metadata[key]).to eq(value) |
| 466 | end |
Tim Emiola | 3fd2be2 | 2015-04-16 17:43:59 -0700 | [diff] [blame] | 467 | @srv.stop |
| 468 | t.join |
| 469 | end |
| 470 | end |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 471 | |
Tim Emiola | a80aa7d | 2015-04-17 16:49:30 -0700 | [diff] [blame] | 472 | context 'with trailing metadata' do |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 473 | before(:each) do |
| 474 | server_opts = { |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 475 | poll_period: 1 |
| 476 | } |
| 477 | @srv = RpcServer.new(**server_opts) |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 478 | alt_port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) |
| 479 | @alt_host = "0.0.0.0:#{alt_port}" |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 480 | end |
| 481 | |
Tim Emiola | a80aa7d | 2015-04-17 16:49:30 -0700 | [diff] [blame] | 482 | it 'should be added to BadStatus when requests fail', server: true do |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 483 | service = FailingService.new |
| 484 | @srv.handle(service) |
| 485 | t = Thread.new { @srv.run } |
| 486 | @srv.wait_till_running |
| 487 | req = EchoMsg.new |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 488 | stub = FailingStub.new(@alt_host, :this_channel_is_insecure) |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 489 | blk = proc { stub.an_rpc(req) } |
| 490 | |
| 491 | # confirm it raise the expected error |
| 492 | expect(&blk).to raise_error GRPC::BadStatus |
| 493 | |
Tim Emiola | a80aa7d | 2015-04-17 16:49:30 -0700 | [diff] [blame] | 494 | # call again and confirm exception contained the trailing metadata. |
Tim Emiola | 8661a43 | 2015-04-17 13:29:59 -0700 | [diff] [blame] | 495 | begin |
| 496 | blk.call |
| 497 | rescue GRPC::BadStatus => e |
| 498 | expect(e.code).to eq(service.code) |
| 499 | expect(e.details).to eq(service.details) |
| 500 | expect(e.metadata).to eq(service.md) |
| 501 | end |
| 502 | @srv.stop |
| 503 | t.join |
| 504 | end |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 505 | |
Tim Emiola | a80aa7d | 2015-04-17 16:49:30 -0700 | [diff] [blame] | 506 | it 'should be received by the client', server: true do |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 507 | wanted_trailers = { 'k1' => 'out_v1', 'k2' => 'out_v2' } |
| 508 | service = EchoService.new(k1: 'out_v1', k2: 'out_v2') |
| 509 | @srv.handle(service) |
| 510 | t = Thread.new { @srv.run } |
| 511 | @srv.wait_till_running |
| 512 | req = EchoMsg.new |
murgatroid99 | ae34a37 | 2016-05-19 17:58:33 -0700 | [diff] [blame] | 513 | stub = EchoStub.new(@alt_host, :this_channel_is_insecure) |
| 514 | op = stub.an_rpc(req, return_op: true, metadata: { k1: 'v1', k2: 'v2' }) |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 515 | expect(op.metadata).to be nil |
| 516 | expect(op.execute).to be_a(EchoMsg) |
murgatroid99 | e69f088 | 2016-07-07 15:52:27 -0700 | [diff] [blame] | 517 | expect(op.trailing_metadata).to eq(wanted_trailers) |
Tim Emiola | 9a0ae03 | 2015-04-17 14:46:36 -0700 | [diff] [blame] | 518 | @srv.stop |
| 519 | t.join |
| 520 | end |
| 521 | end |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 522 | end |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 523 | end |