grpc 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +10 -0
  5. data/.rubocop_todo.yml +52 -0
  6. data/Gemfile +4 -0
  7. data/README.md +82 -0
  8. data/Rakefile +54 -0
  9. data/bin/apis/google/protobuf/empty.rb +44 -0
  10. data/bin/apis/pubsub_demo.rb +267 -0
  11. data/bin/apis/tech/pubsub/proto/pubsub.rb +174 -0
  12. data/bin/apis/tech/pubsub/proto/pubsub_services.rb +103 -0
  13. data/bin/interop/README.md +8 -0
  14. data/bin/interop/interop_client.rb +334 -0
  15. data/bin/interop/interop_server.rb +192 -0
  16. data/bin/interop/test/cpp/interop/empty.rb +44 -0
  17. data/bin/interop/test/cpp/interop/messages.rb +89 -0
  18. data/bin/interop/test/cpp/interop/test.rb +43 -0
  19. data/bin/interop/test/cpp/interop/test_services.rb +60 -0
  20. data/bin/math.proto +80 -0
  21. data/bin/math.rb +61 -0
  22. data/bin/math_client.rb +147 -0
  23. data/bin/math_server.rb +190 -0
  24. data/bin/math_services.rb +56 -0
  25. data/bin/noproto_client.rb +108 -0
  26. data/bin/noproto_server.rb +112 -0
  27. data/ext/grpc/extconf.rb +76 -0
  28. data/ext/grpc/rb_byte_buffer.c +241 -0
  29. data/ext/grpc/rb_byte_buffer.h +54 -0
  30. data/ext/grpc/rb_call.c +569 -0
  31. data/ext/grpc/rb_call.h +59 -0
  32. data/ext/grpc/rb_channel.c +264 -0
  33. data/ext/grpc/rb_channel.h +49 -0
  34. data/ext/grpc/rb_channel_args.c +154 -0
  35. data/ext/grpc/rb_channel_args.h +52 -0
  36. data/ext/grpc/rb_completion_queue.c +185 -0
  37. data/ext/grpc/rb_completion_queue.h +50 -0
  38. data/ext/grpc/rb_credentials.c +281 -0
  39. data/ext/grpc/rb_credentials.h +50 -0
  40. data/ext/grpc/rb_event.c +361 -0
  41. data/ext/grpc/rb_event.h +53 -0
  42. data/ext/grpc/rb_grpc.c +274 -0
  43. data/ext/grpc/rb_grpc.h +74 -0
  44. data/ext/grpc/rb_metadata.c +215 -0
  45. data/ext/grpc/rb_metadata.h +53 -0
  46. data/ext/grpc/rb_server.c +278 -0
  47. data/ext/grpc/rb_server.h +50 -0
  48. data/ext/grpc/rb_server_credentials.c +210 -0
  49. data/ext/grpc/rb_server_credentials.h +50 -0
  50. data/grpc.gemspec +41 -0
  51. data/lib/grpc.rb +39 -0
  52. data/lib/grpc/core/event.rb +44 -0
  53. data/lib/grpc/core/time_consts.rb +71 -0
  54. data/lib/grpc/errors.rb +61 -0
  55. data/lib/grpc/generic/active_call.rb +536 -0
  56. data/lib/grpc/generic/bidi_call.rb +221 -0
  57. data/lib/grpc/generic/client_stub.rb +413 -0
  58. data/lib/grpc/generic/rpc_desc.rb +150 -0
  59. data/lib/grpc/generic/rpc_server.rb +404 -0
  60. data/lib/grpc/generic/service.rb +235 -0
  61. data/lib/grpc/logconfig.rb +40 -0
  62. data/lib/grpc/version.rb +33 -0
  63. data/spec/alloc_spec.rb +44 -0
  64. data/spec/byte_buffer_spec.rb +67 -0
  65. data/spec/call_spec.rb +163 -0
  66. data/spec/channel_spec.rb +181 -0
  67. data/spec/client_server_spec.rb +372 -0
  68. data/spec/completion_queue_spec.rb +74 -0
  69. data/spec/credentials_spec.rb +71 -0
  70. data/spec/event_spec.rb +53 -0
  71. data/spec/generic/active_call_spec.rb +373 -0
  72. data/spec/generic/client_stub_spec.rb +519 -0
  73. data/spec/generic/rpc_desc_spec.rb +357 -0
  74. data/spec/generic/rpc_server_pool_spec.rb +139 -0
  75. data/spec/generic/rpc_server_spec.rb +404 -0
  76. data/spec/generic/service_spec.rb +342 -0
  77. data/spec/metadata_spec.rb +64 -0
  78. data/spec/server_credentials_spec.rb +69 -0
  79. data/spec/server_spec.rb +212 -0
  80. data/spec/spec_helper.rb +51 -0
  81. data/spec/testdata/README +1 -0
  82. data/spec/testdata/ca.pem +15 -0
  83. data/spec/testdata/server1.key +16 -0
  84. data/spec/testdata/server1.pem +16 -0
  85. data/spec/time_consts_spec.rb +89 -0
  86. metadata +353 -0
@@ -0,0 +1,404 @@
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 'xray/thread_dump_signal_handler'
32
+
33
+ def load_test_certs
34
+ test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata')
35
+ files = ['ca.pem', 'server1.key', 'server1.pem']
36
+ files.map { |f| File.open(File.join(test_root, f)).read }
37
+ end
38
+
39
+ # A test message
40
+ class EchoMsg
41
+ def self.marshal(_o)
42
+ ''
43
+ end
44
+
45
+ def self.unmarshal(_o)
46
+ EchoMsg.new
47
+ end
48
+ end
49
+
50
+ # A test service with no methods.
51
+ class EmptyService
52
+ include GRPC::GenericService
53
+ end
54
+
55
+ # A test service without an implementation.
56
+ class NoRpcImplementation
57
+ include GRPC::GenericService
58
+ rpc :an_rpc, EchoMsg, EchoMsg
59
+ end
60
+
61
+ # A test service with an implementation.
62
+ class EchoService
63
+ include GRPC::GenericService
64
+ rpc :an_rpc, EchoMsg, EchoMsg
65
+
66
+ def initialize(_default_var = 'ignored')
67
+ end
68
+
69
+ def an_rpc(req, _call)
70
+ logger.info('echo service received a request')
71
+ req
72
+ end
73
+ end
74
+
75
+ EchoStub = EchoService.rpc_stub_class
76
+
77
+ # A slow test service.
78
+ class SlowService
79
+ include GRPC::GenericService
80
+ rpc :an_rpc, EchoMsg, EchoMsg
81
+
82
+ def initialize(_default_var = 'ignored')
83
+ end
84
+
85
+ def an_rpc(req, _call)
86
+ delay = 0.25
87
+ logger.info("starting a slow #{delay} rpc")
88
+ sleep delay
89
+ req # send back the req as the response
90
+ end
91
+ end
92
+
93
+ SlowStub = SlowService.rpc_stub_class
94
+
95
+ describe GRPC::RpcServer do
96
+ RpcServer = GRPC::RpcServer
97
+ StatusCodes = GRPC::Core::StatusCodes
98
+
99
+ before(:each) do
100
+ @method = 'an_rpc_method'
101
+ @pass = 0
102
+ @fail = 1
103
+ @noop = proc { |x| x }
104
+
105
+ @server_queue = GRPC::Core::CompletionQueue.new
106
+ server_host = '0.0.0.0:0'
107
+ @server = GRPC::Core::Server.new(@server_queue, nil)
108
+ server_port = @server.add_http2_port(server_host)
109
+ @host = "localhost:#{server_port}"
110
+ @ch = GRPC::Core::Channel.new(@host, nil)
111
+ end
112
+
113
+ after(:each) do
114
+ @server.close
115
+ end
116
+
117
+ describe '#new' do
118
+ it 'can be created with just some args' do
119
+ opts = { a_channel_arg: 'an_arg' }
120
+ blk = proc do
121
+ RpcServer.new(**opts)
122
+ end
123
+ expect(&blk).not_to raise_error
124
+ end
125
+
126
+ it 'can be created with a default deadline' do
127
+ opts = { a_channel_arg: 'an_arg', deadline: 5 }
128
+ blk = proc do
129
+ RpcServer.new(**opts)
130
+ end
131
+ expect(&blk).not_to raise_error
132
+ end
133
+
134
+ it 'can be created with a completion queue override' do
135
+ opts = {
136
+ a_channel_arg: 'an_arg',
137
+ completion_queue_override: @server_queue
138
+ }
139
+ blk = proc do
140
+ RpcServer.new(**opts)
141
+ end
142
+ expect(&blk).not_to raise_error
143
+ end
144
+
145
+ it 'cannot be created with a bad completion queue override' do
146
+ blk = proc do
147
+ opts = {
148
+ a_channel_arg: 'an_arg',
149
+ completion_queue_override: Object.new
150
+ }
151
+ RpcServer.new(**opts)
152
+ end
153
+ expect(&blk).to raise_error
154
+ end
155
+
156
+ it 'cannot be created with invalid ServerCredentials' do
157
+ blk = proc do
158
+ opts = {
159
+ a_channel_arg: 'an_arg',
160
+ creds: Object.new
161
+ }
162
+ RpcServer.new(**opts)
163
+ end
164
+ expect(&blk).to raise_error
165
+ end
166
+
167
+ it 'can be created with the creds as valid ServerCedentials' do
168
+ certs = load_test_certs
169
+ server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
170
+ blk = proc do
171
+ opts = {
172
+ a_channel_arg: 'an_arg',
173
+ creds: server_creds
174
+ }
175
+ RpcServer.new(**opts)
176
+ end
177
+ expect(&blk).to_not raise_error
178
+ end
179
+
180
+ it 'can be created with a server override' do
181
+ opts = { a_channel_arg: 'an_arg', server_override: @server }
182
+ blk = proc do
183
+ RpcServer.new(**opts)
184
+ end
185
+ expect(&blk).not_to raise_error
186
+ end
187
+
188
+ it 'cannot be created with a bad server override' do
189
+ blk = proc do
190
+ opts = {
191
+ a_channel_arg: 'an_arg',
192
+ server_override: Object.new
193
+ }
194
+ RpcServer.new(**opts)
195
+ end
196
+ expect(&blk).to raise_error
197
+ end
198
+ end
199
+
200
+ describe '#stopped?' do
201
+ before(:each) do
202
+ opts = { a_channel_arg: 'an_arg', poll_period: 1 }
203
+ @srv = RpcServer.new(**opts)
204
+ end
205
+
206
+ it 'starts out false' do
207
+ expect(@srv.stopped?).to be(false)
208
+ end
209
+
210
+ it 'stays false after a #stop is called before #run' do
211
+ @srv.stop
212
+ expect(@srv.stopped?).to be(false)
213
+ end
214
+
215
+ it 'stays false after the server starts running' do
216
+ @srv.handle(EchoService)
217
+ t = Thread.new { @srv.run }
218
+ @srv.wait_till_running
219
+ expect(@srv.stopped?).to be(false)
220
+ @srv.stop
221
+ t.join
222
+ end
223
+
224
+ it 'is true after a running server is stopped' do
225
+ @srv.handle(EchoService)
226
+ t = Thread.new { @srv.run }
227
+ @srv.wait_till_running
228
+ @srv.stop
229
+ expect(@srv.stopped?).to be(true)
230
+ t.join
231
+ end
232
+ end
233
+
234
+ describe '#running?' do
235
+ it 'starts out false' do
236
+ opts = { a_channel_arg: 'an_arg', server_override: @server }
237
+ r = RpcServer.new(**opts)
238
+ expect(r.running?).to be(false)
239
+ end
240
+
241
+ it 'is false after run is called with no services registered' do
242
+ opts = {
243
+ a_channel_arg: 'an_arg',
244
+ poll_period: 1,
245
+ server_override: @server
246
+ }
247
+ r = RpcServer.new(**opts)
248
+ r.run
249
+ expect(r.running?).to be(false)
250
+ end
251
+
252
+ it 'is true after run is called with a registered service' do
253
+ opts = {
254
+ a_channel_arg: 'an_arg',
255
+ poll_period: 1,
256
+ server_override: @server
257
+ }
258
+ r = RpcServer.new(**opts)
259
+ r.handle(EchoService)
260
+ t = Thread.new { r.run }
261
+ r.wait_till_running
262
+ expect(r.running?).to be(true)
263
+ r.stop
264
+ t.join
265
+ end
266
+ end
267
+
268
+ describe '#handle' do
269
+ before(:each) do
270
+ @opts = { a_channel_arg: 'an_arg', poll_period: 1 }
271
+ @srv = RpcServer.new(**@opts)
272
+ end
273
+
274
+ it 'raises if #run has already been called' do
275
+ @srv.handle(EchoService)
276
+ t = Thread.new { @srv.run }
277
+ @srv.wait_till_running
278
+ expect { @srv.handle(EchoService) }.to raise_error
279
+ @srv.stop
280
+ t.join
281
+ end
282
+
283
+ it 'raises if the server has been run and stopped' do
284
+ @srv.handle(EchoService)
285
+ t = Thread.new { @srv.run }
286
+ @srv.wait_till_running
287
+ @srv.stop
288
+ t.join
289
+ expect { @srv.handle(EchoService) }.to raise_error
290
+ end
291
+
292
+ it 'raises if the service does not include GenericService ' do
293
+ expect { @srv.handle(Object) }.to raise_error
294
+ end
295
+
296
+ it 'raises if the service does not declare any rpc methods' do
297
+ expect { @srv.handle(EmptyService) }.to raise_error
298
+ end
299
+
300
+ it 'raises if the service does not define its rpc methods' do
301
+ expect { @srv.handle(NoRpcImplementation) }.to raise_error
302
+ end
303
+
304
+ it 'raises if a handler method is already registered' do
305
+ @srv.handle(EchoService)
306
+ expect { r.handle(EchoService) }.to raise_error
307
+ end
308
+ end
309
+
310
+ describe '#run' do
311
+ before(:each) do
312
+ @client_opts = {
313
+ channel_override: @ch
314
+ }
315
+ @marshal = EchoService.rpc_descs[:an_rpc].marshal_proc
316
+ @unmarshal = EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output)
317
+ server_opts = {
318
+ server_override: @server,
319
+ completion_queue_override: @server_queue,
320
+ poll_period: 1
321
+ }
322
+ @srv = RpcServer.new(**server_opts)
323
+ end
324
+
325
+ describe 'when running' do
326
+ it 'should return NOT_FOUND status on unknown methods', server: true do
327
+ @srv.handle(EchoService)
328
+ t = Thread.new { @srv.run }
329
+ @srv.wait_till_running
330
+ req = EchoMsg.new
331
+ blk = proc do
332
+ cq = GRPC::Core::CompletionQueue.new
333
+ stub = GRPC::ClientStub.new(@host, cq, **@client_opts)
334
+ stub.request_response('/unknown', req, @marshal, @unmarshal)
335
+ end
336
+ expect(&blk).to raise_error GRPC::BadStatus
337
+ @srv.stop
338
+ t.join
339
+ end
340
+
341
+ it 'should handle multiple sequential requests', server: true do
342
+ @srv.handle(EchoService)
343
+ t = Thread.new { @srv.run }
344
+ @srv.wait_till_running
345
+ req = EchoMsg.new
346
+ n = 5 # arbitrary
347
+ stub = EchoStub.new(@host, **@client_opts)
348
+ n.times { expect(stub.an_rpc(req)).to be_a(EchoMsg) }
349
+ @srv.stop
350
+ t.join
351
+ end
352
+
353
+ it 'should handle multiple parallel requests', server: true do
354
+ @srv.handle(EchoService)
355
+ Thread.new { @srv.run }
356
+ @srv.wait_till_running
357
+ req, q = EchoMsg.new, Queue.new
358
+ n = 5 # arbitrary
359
+ threads = []
360
+ n.times do
361
+ threads << Thread.new do
362
+ stub = EchoStub.new(@host, **@client_opts)
363
+ q << stub.an_rpc(req)
364
+ end
365
+ end
366
+ n.times { expect(q.pop).to be_a(EchoMsg) }
367
+ @srv.stop
368
+ threads.each(&:join)
369
+ end
370
+
371
+ it 'should return UNAVAILABLE on too many jobs', server: true do
372
+ opts = {
373
+ a_channel_arg: 'an_arg',
374
+ server_override: @server,
375
+ completion_queue_override: @server_queue,
376
+ pool_size: 1,
377
+ poll_period: 1,
378
+ max_waiting_requests: 0
379
+ }
380
+ alt_srv = RpcServer.new(**opts)
381
+ alt_srv.handle(SlowService)
382
+ Thread.new { alt_srv.run }
383
+ alt_srv.wait_till_running
384
+ req = EchoMsg.new
385
+ n = 5 # arbitrary, use as many to ensure the server pool is exceeded
386
+ threads = []
387
+ one_failed_as_unavailable = false
388
+ n.times do
389
+ threads << Thread.new do
390
+ stub = SlowStub.new(@host, **@client_opts)
391
+ begin
392
+ stub.an_rpc(req)
393
+ rescue GRPC::BadStatus => e
394
+ one_failed_as_unavailable = e.code == StatusCodes::UNAVAILABLE
395
+ end
396
+ end
397
+ end
398
+ threads.each(&:join)
399
+ alt_srv.stop
400
+ expect(one_failed_as_unavailable).to be(true)
401
+ end
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,342 @@
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
+ require 'grpc/generic/service'
33
+
34
+ # A test message that encodes/decodes using marshal/marshal.
35
+ class GoodMsg
36
+ def self.marshal(_o)
37
+ ''
38
+ end
39
+
40
+ def self.unmarshal(_o)
41
+ GoodMsg.new
42
+ end
43
+ end
44
+
45
+ # A test message that encodes/decodes using encode/decode.
46
+ class EncodeDecodeMsg
47
+ def self.encode(_o)
48
+ ''
49
+ end
50
+
51
+ def self.decode(_o)
52
+ GoodMsg.new
53
+ end
54
+ end
55
+
56
+ GenericService = GRPC::GenericService
57
+ Dsl = GenericService::Dsl
58
+
59
+ describe 'String#underscore' do
60
+ it 'should convert CamelCase to underscore separated' do
61
+ expect('AnRPC'.underscore).to eq('an_rpc')
62
+ expect('AMethod'.underscore).to eq('a_method')
63
+ expect('PrintHTML'.underscore).to eq('print_html')
64
+ expect('PrintHTMLBooks'.underscore).to eq('print_html_books')
65
+ end
66
+ end
67
+
68
+ describe Dsl do
69
+ it 'can be included in new classes' do
70
+ blk = proc { Class.new { include Dsl } }
71
+ expect(&blk).to_not raise_error
72
+ end
73
+ end
74
+
75
+ describe GenericService do
76
+ describe 'including it' do
77
+ it 'adds a class method, rpc' do
78
+ c = Class.new do
79
+ include GenericService
80
+ end
81
+ expect(c.methods).to include(:rpc)
82
+ end
83
+
84
+ it 'adds rpc descs using the added class method, #rpc' do
85
+ c = Class.new do
86
+ include GenericService
87
+ rpc :AnRpc, GoodMsg, GoodMsg
88
+ end
89
+
90
+ expect(c.rpc_descs).to include(:AnRpc)
91
+ expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc)
92
+ end
93
+
94
+ it 'give subclasses access to #rpc_descs' do
95
+ base = Class.new do
96
+ include GenericService
97
+ rpc :AnRpc, GoodMsg, GoodMsg
98
+ end
99
+ c = Class.new(base) do
100
+ end
101
+ expect(c.rpc_descs).to include(:AnRpc)
102
+ expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc)
103
+ end
104
+
105
+ it 'adds a default service name' do
106
+ c = Class.new do
107
+ include GenericService
108
+ end
109
+ expect(c.service_name).to eq('GenericService')
110
+ end
111
+
112
+ it 'adds a default service name to subclasses' do
113
+ base = Class.new do
114
+ include GenericService
115
+ end
116
+ c = Class.new(base) do
117
+ end
118
+ expect(c.service_name).to eq('GenericService')
119
+ end
120
+
121
+ it 'adds the specified service name' do
122
+ c = Class.new do
123
+ include GenericService
124
+ self.service_name = 'test.service.TestService'
125
+ end
126
+ expect(c.service_name).to eq('test.service.TestService')
127
+ end
128
+
129
+ it 'adds the specified service name to subclasses' do
130
+ base = Class.new do
131
+ include GenericService
132
+ self.service_name = 'test.service.TestService'
133
+ end
134
+ c = Class.new(base) do
135
+ end
136
+ expect(c.service_name).to eq('test.service.TestService')
137
+ end
138
+ end
139
+
140
+ describe '#include' do
141
+ it 'raises if #rpc is missing an arg' do
142
+ blk = proc do
143
+ Class.new do
144
+ include GenericService
145
+ rpc :AnRpc, GoodMsg
146
+ end
147
+ end
148
+ expect(&blk).to raise_error ArgumentError
149
+
150
+ blk = proc do
151
+ Class.new do
152
+ include GenericService
153
+ rpc :AnRpc
154
+ end
155
+ end
156
+ expect(&blk).to raise_error ArgumentError
157
+ end
158
+
159
+ describe 'when #rpc args are incorrect' do
160
+ it 'raises if an arg does not have the marshal or unmarshal methods' do
161
+ blk = proc do
162
+ Class.new do
163
+ include GenericService
164
+ rpc :AnRpc, GoodMsg, Object
165
+ end
166
+ end
167
+ expect(&blk).to raise_error ArgumentError
168
+ end
169
+
170
+ it 'raises if a type arg only has the marshal method' do
171
+ # a bad message type with only a marshal method
172
+ class OnlyMarshal
173
+ def marshal(o)
174
+ o
175
+ end
176
+ end
177
+
178
+ blk = proc do
179
+ Class.new do
180
+ include GenericService
181
+ rpc :AnRpc, OnlyMarshal, GoodMsg
182
+ end
183
+ end
184
+ expect(&blk).to raise_error ArgumentError
185
+ end
186
+
187
+ it 'raises if a type arg only has the unmarshal method' do
188
+ # a bad message type with only an unmarshal method
189
+ class OnlyUnmarshal
190
+ def self.ummarshal(o)
191
+ o
192
+ end
193
+ end
194
+ blk = proc do
195
+ Class.new do
196
+ include GenericService
197
+ rpc :AnRpc, GoodMsg, OnlyUnmarshal
198
+ end
199
+ end
200
+ expect(&blk).to raise_error ArgumentError
201
+ end
202
+ end
203
+
204
+ it 'is ok for services that expect the default {un,}marshal methods' do
205
+ blk = proc do
206
+ Class.new do
207
+ include GenericService
208
+ rpc :AnRpc, GoodMsg, GoodMsg
209
+ end
210
+ end
211
+ expect(&blk).not_to raise_error
212
+ end
213
+
214
+ it 'is ok for services that override the default {un,}marshal methods' do
215
+ blk = proc do
216
+ Class.new do
217
+ include GenericService
218
+ self.marshal_class_method = :encode
219
+ self.unmarshal_class_method = :decode
220
+ rpc :AnRpc, EncodeDecodeMsg, EncodeDecodeMsg
221
+ end
222
+ end
223
+ expect(&blk).not_to raise_error
224
+ end
225
+ end
226
+
227
+ describe '#rpc_stub_class' do
228
+ it 'generates a client class that defines any of the rpc methods' do
229
+ s = Class.new do
230
+ include GenericService
231
+ rpc :AnRpc, GoodMsg, GoodMsg
232
+ rpc :AServerStreamer, GoodMsg, stream(GoodMsg)
233
+ rpc :AClientStreamer, stream(GoodMsg), GoodMsg
234
+ rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg)
235
+ end
236
+ client_class = s.rpc_stub_class
237
+ expect(client_class.instance_methods).to include(:an_rpc)
238
+ expect(client_class.instance_methods).to include(:a_server_streamer)
239
+ expect(client_class.instance_methods).to include(:a_client_streamer)
240
+ expect(client_class.instance_methods).to include(:a_bidi_streamer)
241
+ end
242
+
243
+ describe 'the generated instances' do
244
+ it 'can be instanciated with just a hostname' do
245
+ s = Class.new do
246
+ include GenericService
247
+ rpc :AnRpc, GoodMsg, GoodMsg
248
+ rpc :AServerStreamer, GoodMsg, stream(GoodMsg)
249
+ rpc :AClientStreamer, stream(GoodMsg), GoodMsg
250
+ rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg)
251
+ end
252
+ client_class = s.rpc_stub_class
253
+ expect { client_class.new('fakehostname') }.not_to raise_error
254
+ end
255
+
256
+ it 'has the methods defined in the service' do
257
+ s = Class.new do
258
+ include GenericService
259
+ rpc :AnRpc, GoodMsg, GoodMsg
260
+ rpc :AServerStreamer, GoodMsg, stream(GoodMsg)
261
+ rpc :AClientStreamer, stream(GoodMsg), GoodMsg
262
+ rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg)
263
+ end
264
+ client_class = s.rpc_stub_class
265
+ o = client_class.new('fakehostname')
266
+ expect(o.methods).to include(:an_rpc)
267
+ expect(o.methods).to include(:a_bidi_streamer)
268
+ expect(o.methods).to include(:a_client_streamer)
269
+ expect(o.methods).to include(:a_bidi_streamer)
270
+ end
271
+ end
272
+ end
273
+
274
+ describe '#assert_rpc_descs_have_methods' do
275
+ it 'fails if there is no instance method for an rpc descriptor' do
276
+ c1 = Class.new do
277
+ include GenericService
278
+ rpc :AnRpc, GoodMsg, GoodMsg
279
+ end
280
+ expect { c1.assert_rpc_descs_have_methods }.to raise_error
281
+
282
+ c2 = Class.new do
283
+ include GenericService
284
+ rpc :AnRpc, GoodMsg, GoodMsg
285
+ rpc :AnotherRpc, GoodMsg, GoodMsg
286
+
287
+ def an_rpc
288
+ end
289
+ end
290
+ expect { c2.assert_rpc_descs_have_methods }.to raise_error
291
+ end
292
+
293
+ it 'passes if there are corresponding methods for each descriptor' do
294
+ c = Class.new do
295
+ include GenericService
296
+ rpc :AnRpc, GoodMsg, GoodMsg
297
+ rpc :AServerStreamer, GoodMsg, stream(GoodMsg)
298
+ rpc :AClientStreamer, stream(GoodMsg), GoodMsg
299
+ rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg)
300
+
301
+ def an_rpc(_req, _call)
302
+ end
303
+
304
+ def a_server_streamer(_req, _call)
305
+ end
306
+
307
+ def a_client_streamer(_call)
308
+ end
309
+
310
+ def a_bidi_streamer(_call)
311
+ end
312
+ end
313
+ expect { c.assert_rpc_descs_have_methods }.to_not raise_error
314
+ end
315
+
316
+ it 'passes for subclasses of that include GenericService' do
317
+ base = Class.new do
318
+ include GenericService
319
+ rpc :AnRpc, GoodMsg, GoodMsg
320
+
321
+ def an_rpc(_req, _call)
322
+ end
323
+ end
324
+ c = Class.new(base)
325
+ expect { c.assert_rpc_descs_have_methods }.to_not raise_error
326
+ expect(c.include?(GenericService)).to be(true)
327
+ end
328
+
329
+ it 'passes if subclasses define the rpc methods' do
330
+ base = Class.new do
331
+ include GenericService
332
+ rpc :AnRpc, GoodMsg, GoodMsg
333
+ end
334
+ c = Class.new(base) do
335
+ def an_rpc(_req, _call)
336
+ end
337
+ end
338
+ expect { c.assert_rpc_descs_have_methods }.to_not raise_error
339
+ expect(c.include?(GenericService)).to be(true)
340
+ end
341
+ end
342
+ end