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,74 @@
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
+
32
+ describe GRPC::Core::CompletionQueue do
33
+ before(:example) do
34
+ @cq = GRPC::Core::CompletionQueue.new
35
+ end
36
+
37
+ describe '#new' do
38
+ it 'is constructed successufully' do
39
+ expect { GRPC::Core::CompletionQueue.new }.not_to raise_error
40
+ end
41
+ end
42
+
43
+ describe '#next' do
44
+ it 'can be called without failing' do
45
+ expect { @cq.next(3) }.not_to raise_error
46
+ end
47
+
48
+ it 'can be called with a time constant' do
49
+ # don't use INFINITE_FUTURE, as are no events and this blocks.
50
+ #
51
+ # don't use INFINITE_PAST, as this fails on docker, and does not need to
52
+ # be tested, as its not used anywhere in the ruby implementation
53
+ a_time = GRPC::Core::TimeConsts::ZERO
54
+ expect { @cq.next(a_time) }.not_to raise_error
55
+ end
56
+ end
57
+
58
+ describe '#pluck' do
59
+ it 'can be called without failing' do
60
+ tag = Object.new
61
+ expect { @cq.pluck(tag, 3) }.not_to raise_error
62
+ end
63
+
64
+ it 'can be called with a time constant' do
65
+ # don't use INFINITE_FUTURE, as there no events and this blocks.
66
+ #
67
+ # don't use INFINITE_PAST, as this fails on docker, and does not need to
68
+ # be tested, as its not used anywhere in the ruby implementation
69
+ tag = Object.new
70
+ a_time = GRPC::Core::TimeConsts::ZERO
71
+ expect { @cq.pluck(tag, a_time) }.not_to raise_error
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,71 @@
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
+
32
+ def load_test_certs
33
+ test_root = File.join(File.dirname(__FILE__), 'testdata')
34
+ files = ['ca.pem', 'server1.pem', 'server1.key']
35
+ files.map { |f| File.open(File.join(test_root, f)).read }
36
+ end
37
+
38
+ Credentials = GRPC::Core::Credentials
39
+
40
+ describe Credentials do
41
+ describe '#new' do
42
+ it 'can be constructed with fake inputs' do
43
+ expect { Credentials.new('root_certs', 'key', 'cert') }.not_to raise_error
44
+ end
45
+
46
+ it 'it can be constructed using specific test certificates' do
47
+ certs = load_test_certs
48
+ expect { Credentials.new(*certs) }.not_to raise_error
49
+ end
50
+
51
+ it 'can be constructed with server roots certs only' do
52
+ root_cert, _, _ = load_test_certs
53
+ expect { Credentials.new(root_cert) }.not_to raise_error
54
+ end
55
+
56
+ it 'cannot be constructed with a nil server roots' do
57
+ _, client_key, client_chain = load_test_certs
58
+ blk = proc { Credentials.new(nil, client_key, client_chain) }
59
+ expect(&blk).to raise_error
60
+ end
61
+ end
62
+
63
+ describe '#compose' do
64
+ it 'can be completed OK' do
65
+ certs = load_test_certs
66
+ cred1 = Credentials.new(*certs)
67
+ cred2 = Credentials.new(*certs)
68
+ expect { cred1.compose(cred2) }.to_not raise_error
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,53 @@
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
+
32
+ describe GRPC::Core::CompletionType do
33
+ before(:each) do
34
+ @known_types = {
35
+ QUEUE_SHUTDOWN: 0,
36
+ OP_COMPLETE: 1,
37
+ READ: 2,
38
+ WRITE_ACCEPTED: 3,
39
+ FINISH_ACCEPTED: 4,
40
+ CLIENT_METADATA_READ: 5,
41
+ FINISHED: 6,
42
+ SERVER_RPC_NEW: 7,
43
+ SERVER_SHUTDOWN: 8,
44
+ RESERVED: 9
45
+ }
46
+ end
47
+
48
+ it 'should have all the known types' do
49
+ mod = GRPC::Core::CompletionType
50
+ blk = proc { Hash[mod.constants.collect { |c| [c, mod.const_get(c)] }] }
51
+ expect(blk.call).to eq(@known_types)
52
+ end
53
+ end
@@ -0,0 +1,373 @@
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
+
32
+ include GRPC::Core::StatusCodes
33
+
34
+ describe GRPC::ActiveCall do
35
+ ActiveCall = GRPC::ActiveCall
36
+ Call = GRPC::Core::Call
37
+ CompletionType = GRPC::Core::CompletionType
38
+
39
+ before(:each) do
40
+ @pass_through = proc { |x| x }
41
+ @server_tag = Object.new
42
+ @server_done_tag = Object.new
43
+ @tag = Object.new
44
+
45
+ @client_queue = GRPC::Core::CompletionQueue.new
46
+ @server_queue = GRPC::Core::CompletionQueue.new
47
+ host = '0.0.0.0:0'
48
+ @server = GRPC::Core::Server.new(@server_queue, nil)
49
+ server_port = @server.add_http2_port(host)
50
+ @server.start
51
+ @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil)
52
+ end
53
+
54
+ after(:each) do
55
+ @server.close
56
+ end
57
+
58
+ describe 'restricted view methods' do
59
+ before(:each) do
60
+ call = make_test_call
61
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
62
+ deadline)
63
+ @client_call = ActiveCall.new(call, @client_queue, @pass_through,
64
+ @pass_through, deadline,
65
+ finished_tag: done_tag,
66
+ read_metadata_tag: meta_tag)
67
+ end
68
+
69
+ describe '#multi_req_view' do
70
+ xit 'exposes a fixed subset of the ActiveCall methods' do
71
+ want = %w(cancelled, deadline, each_remote_read, shutdown)
72
+ v = @client_call.multi_req_view
73
+ want.each do |w|
74
+ expect(v.methods.include?(w))
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#single_req_view' do
80
+ xit 'exposes a fixed subset of the ActiveCall methods' do
81
+ want = %w(cancelled, deadline, shutdown)
82
+ v = @client_call.single_req_view
83
+ want.each do |w|
84
+ expect(v.methods.include?(w))
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#remote_send' do
91
+ it 'allows a client to send a payload to the server' do
92
+ call = make_test_call
93
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
94
+ deadline)
95
+ @client_call = ActiveCall.new(call, @client_queue, @pass_through,
96
+ @pass_through, deadline,
97
+ finished_tag: done_tag,
98
+ read_metadata_tag: meta_tag)
99
+ msg = 'message is a string'
100
+ @client_call.remote_send(msg)
101
+
102
+ # check that server rpc new was received
103
+ @server.request_call(@server_tag)
104
+ ev = @server_queue.next(deadline)
105
+ expect(ev.type).to be(CompletionType::SERVER_RPC_NEW)
106
+ expect(ev.call).to be_a(Call)
107
+ expect(ev.tag).to be(@server_tag)
108
+
109
+ # Accept the call, and verify that the server reads the response ok.
110
+ ev.call.server_accept(@client_queue, @server_tag)
111
+ ev.call.server_end_initial_metadata
112
+ server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
113
+ @pass_through, deadline)
114
+ expect(server_call.remote_read).to eq(msg)
115
+ end
116
+
117
+ it 'marshals the payload using the marshal func' do
118
+ call = make_test_call
119
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
120
+ deadline)
121
+ marshal = proc { |x| 'marshalled:' + x }
122
+ client_call = ActiveCall.new(call, @client_queue, marshal,
123
+ @pass_through, deadline,
124
+ finished_tag: done_tag,
125
+ read_metadata_tag: meta_tag)
126
+ msg = 'message is a string'
127
+ client_call.remote_send(msg)
128
+
129
+ # confirm that the message was marshalled
130
+ @server.request_call(@server_tag)
131
+ ev = @server_queue.next(deadline)
132
+ ev.call.server_accept(@client_queue, @server_tag)
133
+ ev.call.server_end_initial_metadata
134
+ server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
135
+ @pass_through, deadline)
136
+ expect(server_call.remote_read).to eq('marshalled:' + msg)
137
+ end
138
+ end
139
+
140
+ describe '#client_invoke' do
141
+ it 'sends keywords as metadata to the server when the are present' do
142
+ call = make_test_call
143
+ ActiveCall.client_invoke(call, @client_queue, deadline,
144
+ k1: 'v1', k2: 'v2')
145
+ @server.request_call(@server_tag)
146
+ ev = @server_queue.next(deadline)
147
+ expect(ev).to_not be_nil
148
+ expect(ev.result.metadata['k1']).to eq('v1')
149
+ expect(ev.result.metadata['k2']).to eq('v2')
150
+ end
151
+ end
152
+
153
+ describe '#remote_read' do
154
+ it 'reads the response sent by a server' do
155
+ call = make_test_call
156
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
157
+ deadline)
158
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
159
+ @pass_through, deadline,
160
+ finished_tag: done_tag,
161
+ read_metadata_tag: meta_tag)
162
+ msg = 'message is a string'
163
+ client_call.remote_send(msg)
164
+ server_call = expect_server_to_receive(msg)
165
+ server_call.remote_send('server_response')
166
+ expect(client_call.remote_read).to eq('server_response')
167
+ end
168
+
169
+ it 'saves no metadata when the server adds no metadata' do
170
+ call = make_test_call
171
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
172
+ deadline)
173
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
174
+ @pass_through, deadline,
175
+ finished_tag: done_tag,
176
+ read_metadata_tag: meta_tag)
177
+ msg = 'message is a string'
178
+ client_call.remote_send(msg)
179
+ server_call = expect_server_to_receive(msg)
180
+ server_call.remote_send('ignore me')
181
+ expect(client_call.metadata).to be_nil
182
+ client_call.remote_read
183
+ expect(client_call.metadata).to eq({})
184
+ end
185
+
186
+ it 'saves metadata add by the server' do
187
+ call = make_test_call
188
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
189
+ deadline)
190
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
191
+ @pass_through, deadline,
192
+ finished_tag: done_tag,
193
+ read_metadata_tag: meta_tag)
194
+ msg = 'message is a string'
195
+ client_call.remote_send(msg)
196
+ server_call = expect_server_to_receive(msg, k1: 'v1', k2: 'v2')
197
+ server_call.remote_send('ignore me')
198
+ expect(client_call.metadata).to be_nil
199
+ client_call.remote_read
200
+ expected = { 'k1' => 'v1', 'k2' => 'v2' }
201
+ expect(client_call.metadata).to eq(expected)
202
+ end
203
+
204
+ it 'get a nil msg before a status when an OK status is sent' do
205
+ call = make_test_call
206
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
207
+ deadline)
208
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
209
+ @pass_through, deadline,
210
+ finished_tag: done_tag,
211
+ read_metadata_tag: meta_tag)
212
+ msg = 'message is a string'
213
+ client_call.remote_send(msg)
214
+ client_call.writes_done(false)
215
+ server_call = expect_server_to_receive(msg)
216
+ server_call.remote_send('server_response')
217
+ server_call.send_status(OK, 'OK')
218
+ expect(client_call.remote_read).to eq('server_response')
219
+ res = client_call.remote_read
220
+ expect(res).to be_nil
221
+ end
222
+
223
+ it 'unmarshals the response using the unmarshal func' do
224
+ call = make_test_call
225
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
226
+ deadline)
227
+ unmarshal = proc { |x| 'unmarshalled:' + x }
228
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
229
+ unmarshal, deadline,
230
+ finished_tag: done_tag,
231
+ read_metadata_tag: meta_tag)
232
+
233
+ # confirm the client receives the unmarshalled message
234
+ msg = 'message is a string'
235
+ client_call.remote_send(msg)
236
+ server_call = expect_server_to_receive(msg)
237
+ server_call.remote_send('server_response')
238
+ expect(client_call.remote_read).to eq('unmarshalled:server_response')
239
+ end
240
+ end
241
+
242
+ describe '#each_remote_read' do
243
+ it 'creates an Enumerator' do
244
+ call = make_test_call
245
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
246
+ @pass_through, deadline)
247
+ expect(client_call.each_remote_read).to be_a(Enumerator)
248
+ end
249
+
250
+ it 'the returns an enumerator that can read n responses' do
251
+ call = make_test_call
252
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
253
+ deadline)
254
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
255
+ @pass_through, deadline,
256
+ finished_tag: done_tag,
257
+ read_metadata_tag: meta_tag)
258
+ msg = 'message is 4a string'
259
+ reply = 'server_response'
260
+ client_call.remote_send(msg)
261
+ server_call = expect_server_to_receive(msg)
262
+ e = client_call.each_remote_read
263
+ n = 3 # arbitrary value > 1
264
+ n.times do
265
+ server_call.remote_send(reply)
266
+ expect(e.next).to eq(reply)
267
+ end
268
+ end
269
+
270
+ it 'the returns an enumerator that stops after an OK Status' do
271
+ call = make_test_call
272
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
273
+ deadline)
274
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
275
+ @pass_through, deadline,
276
+ read_metadata_tag: meta_tag,
277
+ finished_tag: done_tag)
278
+ msg = 'message is a string'
279
+ reply = 'server_response'
280
+ client_call.remote_send(msg)
281
+ client_call.writes_done(false)
282
+ server_call = expect_server_to_receive(msg)
283
+ e = client_call.each_remote_read
284
+ n = 3 # arbitrary value > 1
285
+ n.times do
286
+ server_call.remote_send(reply)
287
+ expect(e.next).to eq(reply)
288
+ end
289
+ server_call.send_status(OK, 'OK')
290
+ expect { e.next }.to raise_error(StopIteration)
291
+ end
292
+ end
293
+
294
+ describe '#writes_done' do
295
+ it 'finishes ok if the server sends a status response' do
296
+ call = make_test_call
297
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
298
+ deadline)
299
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
300
+ @pass_through, deadline,
301
+ finished_tag: done_tag,
302
+ read_metadata_tag: meta_tag)
303
+ msg = 'message is a string'
304
+ client_call.remote_send(msg)
305
+ expect { client_call.writes_done(false) }.to_not raise_error
306
+ server_call = expect_server_to_receive(msg)
307
+ server_call.remote_send('server_response')
308
+ expect(client_call.remote_read).to eq('server_response')
309
+ server_call.send_status(OK, 'status code is OK')
310
+ expect { client_call.finished }.to_not raise_error
311
+ end
312
+
313
+ it 'finishes ok if the server sends an early status response' do
314
+ call = make_test_call
315
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
316
+ deadline)
317
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
318
+ @pass_through, deadline,
319
+ read_metadata_tag: meta_tag,
320
+ finished_tag: done_tag)
321
+ msg = 'message is a string'
322
+ client_call.remote_send(msg)
323
+ server_call = expect_server_to_receive(msg)
324
+ server_call.remote_send('server_response')
325
+ server_call.send_status(OK, 'status code is OK')
326
+ expect(client_call.remote_read).to eq('server_response')
327
+ expect { client_call.writes_done(false) }.to_not raise_error
328
+ expect { client_call.finished }.to_not raise_error
329
+ end
330
+
331
+ it 'finishes ok if writes_done is true' do
332
+ call = make_test_call
333
+ done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
334
+ deadline)
335
+ client_call = ActiveCall.new(call, @client_queue, @pass_through,
336
+ @pass_through, deadline,
337
+ read_metadata_tag: meta_tag,
338
+ finished_tag: done_tag)
339
+ msg = 'message is a string'
340
+ client_call.remote_send(msg)
341
+ server_call = expect_server_to_receive(msg)
342
+ server_call.remote_send('server_response')
343
+ server_call.send_status(OK, 'status code is OK')
344
+ expect(client_call.remote_read).to eq('server_response')
345
+ expect { client_call.writes_done(true) }.to_not raise_error
346
+ end
347
+ end
348
+
349
+ def expect_server_to_receive(sent_text, **kw)
350
+ c = expect_server_to_be_invoked(**kw)
351
+ expect(c.remote_read).to eq(sent_text)
352
+ c
353
+ end
354
+
355
+ def expect_server_to_be_invoked(**kw)
356
+ @server.request_call(@server_tag)
357
+ ev = @server_queue.next(deadline)
358
+ ev.call.add_metadata(kw)
359
+ ev.call.server_accept(@client_queue, @server_done_tag)
360
+ ev.call.server_end_initial_metadata
361
+ ActiveCall.new(ev.call, @client_queue, @pass_through,
362
+ @pass_through, deadline,
363
+ finished_tag: @server_done_tag)
364
+ end
365
+
366
+ def make_test_call
367
+ @ch.create_call('dummy_method', 'dummy_host', deadline)
368
+ end
369
+
370
+ def deadline
371
+ Time.now + 1 # in 1 second; arbitrary
372
+ end
373
+ end