blob: d362e48deee9f2c3df111bdfd8641c196219dd4a [file] [log] [blame]
Craig Tiller6169d5f2016-03-31 07:46:18 -07001# Copyright 2015, Google Inc.
nnoble097ef9b2014-12-01 17:06:10 -08002# 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
30require 'grpc'
nnoble097ef9b2014-12-01 17:06:10 -080031
nnoble0c475f02014-12-05 15:37:39 -080032def load_test_certs
temiola6919c752014-12-10 13:22:00 -080033 test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata')
nnoble0c475f02014-12-05 15:37:39 -080034 files = ['ca.pem', 'server1.key', 'server1.pem']
35 files.map { |f| File.open(File.join(test_root, f)).read }
36end
37
Craig Tiller83ac7052015-07-15 11:53:13 -070038def 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
44end
45
Tim Emiolae2860c52015-01-16 02:58:41 -080046# A test message
nnoble097ef9b2014-12-01 17:06:10 -080047class EchoMsg
Tim Emiolae2860c52015-01-16 02:58:41 -080048 def self.marshal(_o)
nnoble097ef9b2014-12-01 17:06:10 -080049 ''
50 end
51
Tim Emiolae2860c52015-01-16 02:58:41 -080052 def self.unmarshal(_o)
nnoble097ef9b2014-12-01 17:06:10 -080053 EchoMsg.new
54 end
55end
56
Tim Emiolae2860c52015-01-16 02:58:41 -080057# A test service with no methods.
nnoble097ef9b2014-12-01 17:06:10 -080058class EmptyService
59 include GRPC::GenericService
60end
61
Tim Emiolae2860c52015-01-16 02:58:41 -080062# A test service without an implementation.
nnoble097ef9b2014-12-01 17:06:10 -080063class NoRpcImplementation
64 include GRPC::GenericService
65 rpc :an_rpc, EchoMsg, EchoMsg
66end
67
Tim Emiola8661a432015-04-17 13:29:59 -070068# A test service with an echo implementation.
nnoble097ef9b2014-12-01 17:06:10 -080069class EchoService
70 include GRPC::GenericService
71 rpc :an_rpc, EchoMsg, EchoMsg
Tim Emiola62e3cc82015-03-17 21:20:47 -070072 attr_reader :received_md
nnoble097ef9b2014-12-01 17:06:10 -080073
Tim Emiola9a0ae032015-04-17 14:46:36 -070074 def initialize(**kw)
75 @trailing_metadata = kw
Tim Emiola62e3cc82015-03-17 21:20:47 -070076 @received_md = []
nnoble097ef9b2014-12-01 17:06:10 -080077 end
78
Tim Emiola62e3cc82015-03-17 21:20:47 -070079 def an_rpc(req, call)
Nick Gauthierf233d962015-05-20 14:02:50 -040080 GRPC.logger.info('echo service received a request')
Tim Emiola9a0ae032015-04-17 14:46:36 -070081 call.output_metadata.update(@trailing_metadata)
Tim Emiola62e3cc82015-03-17 21:20:47 -070082 @received_md << call.metadata unless call.metadata.nil?
nnoble097ef9b2014-12-01 17:06:10 -080083 req
84 end
85end
86
87EchoStub = EchoService.rpc_stub_class
88
Tim Emiola8661a432015-04-17 13:29:59 -070089# A test service with an implementation that fails with BadStatus
90class 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
murgatroid99e69f0882016-07-07 15:52:27 -070098 @md = { 'failed_method' => 'an_rpc' }
Tim Emiola8661a432015-04-17 13:29:59 -070099 end
100
101 def an_rpc(_req, _call)
murgatroid99b19f1812016-05-16 12:21:39 -0700102 fail GRPC::BadStatus.new(@code, @details, @md)
Tim Emiola8661a432015-04-17 13:29:59 -0700103 end
104end
105
106FailingStub = FailingService.rpc_stub_class
107
Tim Emiolae2860c52015-01-16 02:58:41 -0800108# A slow test service.
nnoble097ef9b2014-12-01 17:06:10 -0800109class SlowService
110 include GRPC::GenericService
111 rpc :an_rpc, EchoMsg, EchoMsg
Tim Emiola77e2fb02015-03-19 23:10:10 -0700112 attr_reader :received_md, :delay
nnoble097ef9b2014-12-01 17:06:10 -0800113
Tim Emiolae2860c52015-01-16 02:58:41 -0800114 def initialize(_default_var = 'ignored')
Tim Emiola77e2fb02015-03-19 23:10:10 -0700115 @delay = 0.25
116 @received_md = []
nnoble097ef9b2014-12-01 17:06:10 -0800117 end
118
Tim Emiola77e2fb02015-03-19 23:10:10 -0700119 def an_rpc(req, call)
Nick Gauthierf233d962015-05-20 14:02:50 -0400120 GRPC.logger.info("starting a slow #{@delay} rpc")
Tim Emiola77e2fb02015-03-19 23:10:10 -0700121 sleep @delay
122 @received_md << call.metadata unless call.metadata.nil?
nnoble097ef9b2014-12-01 17:06:10 -0800123 req # send back the req as the response
124 end
125end
126
127SlowStub = SlowService.rpc_stub_class
128
nnoble0c475f02014-12-05 15:37:39 -0800129describe GRPC::RpcServer do
nnoble0c475f02014-12-05 15:37:39 -0800130 RpcServer = GRPC::RpcServer
temiola6919c752014-12-10 13:22:00 -0800131 StatusCodes = GRPC::Core::StatusCodes
nnoble097ef9b2014-12-01 17:06:10 -0800132
nnoble0c475f02014-12-05 15:37:39 -0800133 before(:each) do
134 @method = 'an_rpc_method'
135 @pass = 0
136 @fail = 1
Tim Emiolae2860c52015-01-16 02:58:41 -0800137 @noop = proc { |x| x }
nnoble0c475f02014-12-05 15:37:39 -0800138 end
139
nnoble0c475f02014-12-05 15:37:39 -0800140 describe '#new' do
nnoble0c475f02014-12-05 15:37:39 -0800141 it 'can be created with just some args' do
murgatroid99b19f1812016-05-16 12:21:39 -0700142 opts = { server_args: { a_channel_arg: 'an_arg' } }
Tim Emiolae2860c52015-01-16 02:58:41 -0800143 blk = proc do
nnoble0c475f02014-12-05 15:37:39 -0800144 RpcServer.new(**opts)
145 end
146 expect(&blk).not_to raise_error
nnoble097ef9b2014-12-01 17:06:10 -0800147 end
148
nnoble0c475f02014-12-05 15:37:39 -0800149 it 'cannot be created with invalid ServerCredentials' do
Tim Emiolae2860c52015-01-16 02:58:41 -0800150 blk = proc do
nnoble0c475f02014-12-05 15:37:39 -0800151 opts = {
murgatroid99b19f1812016-05-16 12:21:39 -0700152 server_args: { a_channel_arg: 'an_arg' },
Tim Emiolae2860c52015-01-16 02:58:41 -0800153 creds: Object.new
nnoble0c475f02014-12-05 15:37:39 -0800154 }
155 RpcServer.new(**opts)
nnoble097ef9b2014-12-01 17:06:10 -0800156 end
nnoble0c475f02014-12-05 15:37:39 -0800157 expect(&blk).to raise_error
158 end
nnoble0c475f02014-12-05 15:37:39 -0800159 end
160
161 describe '#stopped?' do
nnoble0c475f02014-12-05 15:37:39 -0800162 before(:each) do
murgatroid99b19f1812016-05-16 12:21:39 -0700163 opts = { server_args: { a_channel_arg: 'an_arg' }, poll_period: 1.5 }
nnoble0c475f02014-12-05 15:37:39 -0800164 @srv = RpcServer.new(**opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700165 @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
nnoble0c475f02014-12-05 15:37:39 -0800166 end
167
168 it 'starts out false' do
169 expect(@srv.stopped?).to be(false)
170 end
171
Tim Emiola4aba3562015-05-22 17:25:49 -0700172 it 'stays false after the server starts running', server: true do
nnoble0c475f02014-12-05 15:37:39 -0800173 @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 Emiola4aba3562015-05-22 17:25:49 -0700181 it 'is true after a running server is stopped', server: true do
nnoble0c475f02014-12-05 15:37:39 -0800182 @srv.handle(EchoService)
183 t = Thread.new { @srv.run }
184 @srv.wait_till_running
185 @srv.stop
nnoble0c475f02014-12-05 15:37:39 -0800186 t.join
murgatroid99d48d84d2016-03-09 11:10:20 -0800187 expect(@srv.stopped?).to be(true)
nnoble0c475f02014-12-05 15:37:39 -0800188 end
nnoble0c475f02014-12-05 15:37:39 -0800189 end
190
191 describe '#running?' do
nnoble0c475f02014-12-05 15:37:39 -0800192 it 'starts out false' do
murgatroid99b19f1812016-05-16 12:21:39 -0700193 opts = {
194 server_args: { a_channel_arg: 'an_arg' }
195 }
nnoble0c475f02014-12-05 15:37:39 -0800196 r = RpcServer.new(**opts)
197 expect(r.running?).to be(false)
198 end
199
Tim Emiola4aba3562015-05-22 17:25:49 -0700200 it 'is false if run is called with no services registered', server: true do
nnoble0c475f02014-12-05 15:37:39 -0800201 opts = {
murgatroid99b19f1812016-05-16 12:21:39 -0700202 server_args: { a_channel_arg: 'an_arg' },
203 poll_period: 2
nnoble0c475f02014-12-05 15:37:39 -0800204 }
205 r = RpcServer.new(**opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700206 r.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
murgatroid99d48d84d2016-03-09 11:10:20 -0800207 expect { r.run }.to raise_error(RuntimeError)
nnoble0c475f02014-12-05 15:37:39 -0800208 end
209
210 it 'is true after run is called with a registered service' do
211 opts = {
murgatroid99b19f1812016-05-16 12:21:39 -0700212 server_args: { a_channel_arg: 'an_arg' },
213 poll_period: 2.5
nnoble0c475f02014-12-05 15:37:39 -0800214 }
215 r = RpcServer.new(**opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700216 r.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
nnoble0c475f02014-12-05 15:37:39 -0800217 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
nnoble0c475f02014-12-05 15:37:39 -0800224 end
225
226 describe '#handle' do
nnoble0c475f02014-12-05 15:37:39 -0800227 before(:each) do
murgatroid99ae34a372016-05-19 17:58:33 -0700228 @opts = { server_args: { a_channel_arg: 'an_arg' }, poll_period: 1 }
nnoble0c475f02014-12-05 15:37:39 -0800229 @srv = RpcServer.new(**@opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700230 @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
nnoble0c475f02014-12-05 15:37:39 -0800231 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
nnoble0c475f02014-12-05 15:37:39 -0800259 it 'raises if a handler method is already registered' do
260 @srv.handle(EchoService)
261 expect { r.handle(EchoService) }.to raise_error
262 end
nnoble0c475f02014-12-05 15:37:39 -0800263 end
264
265 describe '#run' do
Tim Emiola3fd2be22015-04-16 17:43:59 -0700266 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) }
nnoble0c475f02014-12-05 15:37:39 -0800269
Tim Emiola3fd2be22015-04-16 17:43:59 -0700270 context 'with no connect_metadata' do
271 before(:each) do
272 server_opts = {
Tim Emiola3fd2be22015-04-16 17:43:59 -0700273 poll_period: 1
274 }
275 @srv = RpcServer.new(**server_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700276 server_port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
murgatroid99b19f1812016-05-16 12:21:39 -0700277 @host = "localhost:#{server_port}"
278 @ch = GRPC::Core::Channel.new(@host, nil, :this_channel_is_insecure)
Tim Emiola3fd2be22015-04-16 17:43:59 -0700279 end
280
Tim Emiola91044c12015-01-29 13:25:08 -0800281 it 'should return NOT_FOUND status on unknown methods', server: true do
nnoble097ef9b2014-12-01 17:06:10 -0800282 @srv.handle(EchoService)
283 t = Thread.new { @srv.run }
284 @srv.wait_till_running
nnoble0c475f02014-12-05 15:37:39 -0800285 req = EchoMsg.new
Tim Emiolae2860c52015-01-16 02:58:41 -0800286 blk = proc do
murgatroid995ea4a992016-06-13 10:36:41 -0700287 stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure,
murgatroid99afe39742015-12-16 13:04:37 -0800288 **client_opts)
Tim Emiola3fd2be22015-04-16 17:43:59 -0700289 stub.request_response('/unknown', req, marshal, unmarshal)
nnoble0c475f02014-12-05 15:37:39 -0800290 end
temiola6919c752014-12-10 13:22:00 -0800291 expect(&blk).to raise_error GRPC::BadStatus
nnoble097ef9b2014-12-01 17:06:10 -0800292 @srv.stop
293 t.join
294 end
295
murgatroid99cf239e72016-05-06 14:48:21 -0700296 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
murgatroid995ea4a992016-06-13 10:36:41 -0700302 stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure,
murgatroid99cf239e72016-05-06 14:48:21 -0700303 **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 Emiola91044c12015-01-29 13:25:08 -0800314 it 'should handle multiple sequential requests', server: true do
nnoble097ef9b2014-12-01 17:06:10 -0800315 @srv.handle(EchoService)
316 t = Thread.new { @srv.run }
317 @srv.wait_till_running
nnoble0c475f02014-12-05 15:37:39 -0800318 req = EchoMsg.new
319 n = 5 # arbitrary
murgatroid99afe39742015-12-16 13:04:37 -0800320 stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts)
Tim Emiolae2860c52015-01-16 02:58:41 -0800321 n.times { expect(stub.an_rpc(req)).to be_a(EchoMsg) }
nnoble097ef9b2014-12-01 17:06:10 -0800322 @srv.stop
nnoble097ef9b2014-12-01 17:06:10 -0800323 t.join
324 end
325
Tim Emiola62e3cc82015-03-17 21:20:47 -0700326 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
murgatroid99afe39742015-12-16 13:04:37 -0800332 stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700333 expect(stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }))
334 .to be_a(EchoMsg)
Tim Emiola62e3cc82015-03-17 21:20:47 -0700335 wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
Craig Tiller83ac7052015-07-15 11:53:13 -0700336 check_md(wanted_md, service.received_md)
Tim Emiola62e3cc82015-03-17 21:20:47 -0700337 @srv.stop
338 t.join
339 end
340
Tim Emiola4aba3562015-05-22 17:25:49 -0700341 it 'should receive metadata if a deadline is specified', server: true do
Tim Emiola77e2fb02015-03-19 23:10:10 -0700342 service = SlowService.new
343 @srv.handle(service)
344 t = Thread.new { @srv.run }
345 @srv.wait_till_running
346 req = EchoMsg.new
murgatroid99afe39742015-12-16 13:04:37 -0800347 stub = SlowStub.new(@host, :this_channel_is_insecure, **client_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700348 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 Emiola49b76502015-08-13 14:12:15 -0700353 expect(resp).to be_a(EchoMsg)
Tim Emiola77e2fb02015-03-19 23:10:10 -0700354 wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
Craig Tiller83ac7052015-07-15 11:53:13 -0700355 check_md(wanted_md, service.received_md)
Tim Emiola77e2fb02015-03-19 23:10:10 -0700356 @srv.stop
357 t.join
358 end
359
Tim Emiola72d70fc2015-04-15 08:06:16 -0700360 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
murgatroid99afe39742015-12-16 13:04:37 -0800366 stub = SlowStub.new(@host, :this_channel_is_insecure, **client_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700367 op = stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }, return_op: true)
Tim Emiola1b399162015-04-15 08:09:25 -0700368 Thread.new do # cancel the call
Tim Emiola72d70fc2015-04-15 08:06:16 -0700369 sleep 0.1
370 op.cancel
371 end
Tim Emiola1b399162015-04-15 08:09:25 -0700372 expect { op.execute }.to raise_error GRPC::Cancelled
Tim Emiola72d70fc2015-04-15 08:06:16 -0700373 @srv.stop
374 t.join
375 end
376
Tim Emiola91044c12015-01-29 13:25:08 -0800377 it 'should handle multiple parallel requests', server: true do
nnoble0c475f02014-12-05 15:37:39 -0800378 @srv.handle(EchoService)
Tim Emiola4aba3562015-05-22 17:25:49 -0700379 t = Thread.new { @srv.run }
nnoble0c475f02014-12-05 15:37:39 -0800380 @srv.wait_till_running
381 req, q = EchoMsg.new, Queue.new
382 n = 5 # arbitrary
Tim Emiola4aba3562015-05-22 17:25:49 -0700383 threads = [t]
Tim Emiolae2860c52015-01-16 02:58:41 -0800384 n.times do
nnoble0c475f02014-12-05 15:37:39 -0800385 threads << Thread.new do
murgatroid99afe39742015-12-16 13:04:37 -0800386 stub = EchoStub.new(@host, :this_channel_is_insecure, **client_opts)
nnoble0c475f02014-12-05 15:37:39 -0800387 q << stub.an_rpc(req)
388 end
389 end
390 n.times { expect(q.pop).to be_a(EchoMsg) }
391 @srv.stop
Tim Emiolae2860c52015-01-16 02:58:41 -0800392 threads.each(&:join)
nnoble097ef9b2014-12-01 17:06:10 -0800393 end
394
murgatroid99895c1112016-04-04 11:27:51 -0700395 it 'should return RESOURCE_EXHAUSTED on too many jobs', server: true do
nnoble097ef9b2014-12-01 17:06:10 -0800396 opts = {
murgatroid99ae34a372016-05-19 17:58:33 -0700397 server_args: { a_channel_arg: 'an_arg' },
Alexander Polcyn9c744872016-08-12 14:58:10 -0700398 pool_size: 2,
Tim Emiolae2860c52015-01-16 02:58:41 -0800399 poll_period: 1,
Alexander Polcyn9c744872016-08-12 14:58:10 -0700400 max_waiting_requests: 1
nnoble097ef9b2014-12-01 17:06:10 -0800401 }
nnoble0c475f02014-12-05 15:37:39 -0800402 alt_srv = RpcServer.new(**opts)
403 alt_srv.handle(SlowService)
murgatroid99ae34a372016-05-19 17:58:33 -0700404 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 Emiola4aba3562015-05-22 17:25:49 -0700406 t = Thread.new { alt_srv.run }
nnoble0c475f02014-12-05 15:37:39 -0800407 alt_srv.wait_till_running
408 req = EchoMsg.new
Alexander Polcyn9c744872016-08-12 14:58:10 -0700409 n = 20 # arbitrary, use as many to ensure the server pool is exceeded
nnoble0c475f02014-12-05 15:37:39 -0800410 threads = []
Alexander Polcyn9c744872016-08-12 14:58:10 -0700411 bad_status_code = nil
Tim Emiolae2860c52015-01-16 02:58:41 -0800412 n.times do
nnoble0c475f02014-12-05 15:37:39 -0800413 threads << Thread.new do
murgatroid99ae34a372016-05-19 17:58:33 -0700414 stub = SlowStub.new(alt_host, :this_channel_is_insecure)
nnoble0c475f02014-12-05 15:37:39 -0800415 begin
416 stub.an_rpc(req)
temiola6919c752014-12-10 13:22:00 -0800417 rescue GRPC::BadStatus => e
Alexander Polcyn9c744872016-08-12 14:58:10 -0700418 bad_status_code = e.code
nnoble097ef9b2014-12-01 17:06:10 -0800419 end
420 end
nnoble097ef9b2014-12-01 17:06:10 -0800421 end
Tim Emiolae2860c52015-01-16 02:58:41 -0800422 threads.each(&:join)
nnoble0c475f02014-12-05 15:37:39 -0800423 alt_srv.stop
Tim Emiola4aba3562015-05-22 17:25:49 -0700424 t.join
Alexander Polcyn9c744872016-08-12 14:58:10 -0700425 expect(bad_status_code).to be(StatusCodes::RESOURCE_EXHAUSTED)
nnoble097ef9b2014-12-01 17:06:10 -0800426 end
nnoble097ef9b2014-12-01 17:06:10 -0800427 end
Tim Emiola3fd2be22015-04-16 17:43:59 -0700428
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 Emiola3fd2be22015-04-16 17:43:59 -0700440 poll_period: 1,
441 connect_md_proc: test_md_proc
442 }
443 @srv = RpcServer.new(**server_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700444 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 Emiola3fd2be22015-04-16 17:43:59 -0700446 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
murgatroid99ae34a372016-05-19 17:58:33 -0700454 stub = EchoStub.new(@alt_host, :this_channel_is_insecure)
455 op = stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }, return_op: true)
Tim Emiola3fd2be22015-04-16 17:43:59 -0700456 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 Tiller83ac7052015-07-15 11:53:13 -0700464 wanted_md.each do |key, value|
465 expect(op.metadata[key]).to eq(value)
466 end
Tim Emiola3fd2be22015-04-16 17:43:59 -0700467 @srv.stop
468 t.join
469 end
470 end
Tim Emiola8661a432015-04-17 13:29:59 -0700471
Tim Emiolaa80aa7d2015-04-17 16:49:30 -0700472 context 'with trailing metadata' do
Tim Emiola8661a432015-04-17 13:29:59 -0700473 before(:each) do
474 server_opts = {
Tim Emiola8661a432015-04-17 13:29:59 -0700475 poll_period: 1
476 }
477 @srv = RpcServer.new(**server_opts)
murgatroid99ae34a372016-05-19 17:58:33 -0700478 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 Emiola8661a432015-04-17 13:29:59 -0700480 end
481
Tim Emiolaa80aa7d2015-04-17 16:49:30 -0700482 it 'should be added to BadStatus when requests fail', server: true do
Tim Emiola8661a432015-04-17 13:29:59 -0700483 service = FailingService.new
484 @srv.handle(service)
485 t = Thread.new { @srv.run }
486 @srv.wait_till_running
487 req = EchoMsg.new
murgatroid99ae34a372016-05-19 17:58:33 -0700488 stub = FailingStub.new(@alt_host, :this_channel_is_insecure)
Tim Emiola8661a432015-04-17 13:29:59 -0700489 blk = proc { stub.an_rpc(req) }
490
491 # confirm it raise the expected error
492 expect(&blk).to raise_error GRPC::BadStatus
493
Tim Emiolaa80aa7d2015-04-17 16:49:30 -0700494 # call again and confirm exception contained the trailing metadata.
Tim Emiola8661a432015-04-17 13:29:59 -0700495 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 Emiola9a0ae032015-04-17 14:46:36 -0700505
Tim Emiolaa80aa7d2015-04-17 16:49:30 -0700506 it 'should be received by the client', server: true do
Tim Emiola9a0ae032015-04-17 14:46:36 -0700507 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
murgatroid99ae34a372016-05-19 17:58:33 -0700513 stub = EchoStub.new(@alt_host, :this_channel_is_insecure)
514 op = stub.an_rpc(req, return_op: true, metadata: { k1: 'v1', k2: 'v2' })
Tim Emiola9a0ae032015-04-17 14:46:36 -0700515 expect(op.metadata).to be nil
516 expect(op.execute).to be_a(EchoMsg)
murgatroid99e69f0882016-07-07 15:52:27 -0700517 expect(op.trailing_metadata).to eq(wanted_trailers)
Tim Emiola9a0ae032015-04-17 14:46:36 -0700518 @srv.stop
519 t.join
520 end
521 end
nnoble097ef9b2014-12-01 17:06:10 -0800522 end
Craig Tiller190d3602015-02-18 09:23:38 -0800523end