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,181 @@
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.key', 'server1.pem']
35
+ files.map { |f| File.open(File.join(test_root, f)).read }
36
+ end
37
+
38
+ describe GRPC::Core::Channel do
39
+ FAKE_HOST = 'localhost:0'
40
+
41
+ def create_test_cert
42
+ GRPC::Core::Credentials.new(load_test_certs[0])
43
+ end
44
+
45
+ before(:each) do
46
+ @cq = GRPC::Core::CompletionQueue.new
47
+ end
48
+
49
+ shared_examples '#new' do
50
+ it 'take a host name without channel args' do
51
+ expect { GRPC::Core::Channel.new('dummy_host', nil) }.not_to raise_error
52
+ end
53
+
54
+ it 'does not take a hash with bad keys as channel args' do
55
+ blk = construct_with_args(Object.new => 1)
56
+ expect(&blk).to raise_error TypeError
57
+ blk = construct_with_args(1 => 1)
58
+ expect(&blk).to raise_error TypeError
59
+ end
60
+
61
+ it 'does not take a hash with bad values as channel args' do
62
+ blk = construct_with_args(symbol: Object.new)
63
+ expect(&blk).to raise_error TypeError
64
+ blk = construct_with_args('1' => Hash.new)
65
+ expect(&blk).to raise_error TypeError
66
+ end
67
+
68
+ it 'can take a hash with a symbol key as channel args' do
69
+ blk = construct_with_args(a_symbol: 1)
70
+ expect(&blk).to_not raise_error
71
+ end
72
+
73
+ it 'can take a hash with a string key as channel args' do
74
+ blk = construct_with_args('a_symbol' => 1)
75
+ expect(&blk).to_not raise_error
76
+ end
77
+
78
+ it 'can take a hash with a string value as channel args' do
79
+ blk = construct_with_args(a_symbol: '1')
80
+ expect(&blk).to_not raise_error
81
+ end
82
+
83
+ it 'can take a hash with a symbol value as channel args' do
84
+ blk = construct_with_args(a_symbol: :another_symbol)
85
+ expect(&blk).to_not raise_error
86
+ end
87
+
88
+ it 'can take a hash with a numeric value as channel args' do
89
+ blk = construct_with_args(a_symbol: 1)
90
+ expect(&blk).to_not raise_error
91
+ end
92
+
93
+ it 'can take a hash with many args as channel args' do
94
+ args = Hash[127.times.collect { |x| [x.to_s, x] }]
95
+ blk = construct_with_args(args)
96
+ expect(&blk).to_not raise_error
97
+ end
98
+ end
99
+
100
+ describe '#new for secure channels' do
101
+ def construct_with_args(a)
102
+ proc { GRPC::Core::Channel.new('dummy_host', a, create_test_cert) }
103
+ end
104
+
105
+ it_behaves_like '#new'
106
+ end
107
+
108
+ describe '#new for insecure channels' do
109
+ it_behaves_like '#new'
110
+
111
+ def construct_with_args(a)
112
+ proc { GRPC::Core::Channel.new('dummy_host', a) }
113
+ end
114
+ end
115
+
116
+ describe '#create_call' do
117
+ it 'creates a call OK' do
118
+ host = FAKE_HOST
119
+ ch = GRPC::Core::Channel.new(host, nil)
120
+
121
+ deadline = Time.now + 5
122
+
123
+ blk = proc do
124
+ ch.create_call('dummy_method', 'dummy_host', deadline)
125
+ end
126
+ expect(&blk).to_not raise_error
127
+ end
128
+
129
+ it 'raises an error if called on a closed channel' do
130
+ host = FAKE_HOST
131
+ ch = GRPC::Core::Channel.new(host, nil)
132
+ ch.close
133
+
134
+ deadline = Time.now + 5
135
+ blk = proc do
136
+ ch.create_call('dummy_method', 'dummy_host', deadline)
137
+ end
138
+ expect(&blk).to raise_error(RuntimeError)
139
+ end
140
+ end
141
+
142
+ describe '#destroy' do
143
+ it 'destroys a channel ok' do
144
+ host = FAKE_HOST
145
+ ch = GRPC::Core::Channel.new(host, nil)
146
+ blk = proc { ch.destroy }
147
+ expect(&blk).to_not raise_error
148
+ end
149
+
150
+ it 'can be called more than once without error' do
151
+ host = FAKE_HOST
152
+ ch = GRPC::Core::Channel.new(host, nil)
153
+ blk = proc { ch.destroy }
154
+ blk.call
155
+ expect(&blk).to_not raise_error
156
+ end
157
+ end
158
+
159
+ describe '::SSL_TARGET' do
160
+ it 'is a symbol' do
161
+ expect(GRPC::Core::Channel::SSL_TARGET).to be_a(Symbol)
162
+ end
163
+ end
164
+
165
+ describe '#close' do
166
+ it 'closes a channel ok' do
167
+ host = FAKE_HOST
168
+ ch = GRPC::Core::Channel.new(host, nil)
169
+ blk = proc { ch.close }
170
+ expect(&blk).to_not raise_error
171
+ end
172
+
173
+ it 'can be called more than once without error' do
174
+ host = FAKE_HOST
175
+ ch = GRPC::Core::Channel.new(host, nil)
176
+ blk = proc { ch.close }
177
+ blk.call
178
+ expect(&blk).to_not raise_error
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,372 @@
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 'spec_helper'
32
+
33
+ include GRPC::Core::CompletionType
34
+ include GRPC::Core
35
+
36
+ def load_test_certs
37
+ test_root = File.join(File.dirname(__FILE__), 'testdata')
38
+ files = ['ca.pem', 'server1.key', 'server1.pem']
39
+ files.map { |f| File.open(File.join(test_root, f)).read }
40
+ end
41
+
42
+ shared_context 'setup: tags' do
43
+ before(:example) do
44
+ @server_finished_tag = Object.new
45
+ @client_finished_tag = Object.new
46
+ @client_metadata_tag = Object.new
47
+ @server_tag = Object.new
48
+ @tag = Object.new
49
+ end
50
+
51
+ def deadline
52
+ Time.now + 2
53
+ end
54
+
55
+ def expect_next_event_on(queue, type, tag)
56
+ ev = queue.pluck(tag, deadline)
57
+ if type.nil?
58
+ expect(ev).to be_nil
59
+ else
60
+ expect(ev).to_not be_nil
61
+ expect(ev.type).to be(type)
62
+ end
63
+ ev
64
+ end
65
+
66
+ def server_allows_client_to_proceed
67
+ @server.request_call(@server_tag)
68
+ ev = @server_queue.pluck(@server_tag, deadline)
69
+ expect(ev).not_to be_nil
70
+ expect(ev.type).to be(SERVER_RPC_NEW)
71
+ server_call = ev.call
72
+ server_call.server_accept(@server_queue, @server_finished_tag)
73
+ server_call.server_end_initial_metadata
74
+ server_call
75
+ end
76
+
77
+ def server_responds_with(server_call, reply_text)
78
+ reply = ByteBuffer.new(reply_text)
79
+ server_call.start_read(@server_tag)
80
+ ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
81
+ expect(ev.type).to be(READ)
82
+ server_call.start_write(reply, @server_tag)
83
+ ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
84
+ expect(ev).not_to be_nil
85
+ expect(ev.type).to be(WRITE_ACCEPTED)
86
+ end
87
+
88
+ def client_sends(call, sent = 'a message')
89
+ req = ByteBuffer.new(sent)
90
+ call.start_write(req, @tag)
91
+ ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE)
92
+ expect(ev).not_to be_nil
93
+ expect(ev.type).to be(WRITE_ACCEPTED)
94
+ sent
95
+ end
96
+
97
+ def new_client_call
98
+ @ch.create_call('/method', 'localhost', deadline)
99
+ end
100
+ end
101
+
102
+ shared_examples 'basic GRPC message delivery is OK' do
103
+ include_context 'setup: tags'
104
+
105
+ it 'servers receive requests from clients and start responding' do
106
+ reply = ByteBuffer.new('the server payload')
107
+ call = new_client_call
108
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
109
+
110
+ # check the server rpc new was received
111
+ # @server.request_call(@server_tag)
112
+ # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
113
+
114
+ # accept the call
115
+ # server_call = ev.call
116
+ # server_call.server_accept(@server_queue, @server_finished_tag)
117
+ # server_call.server_end_initial_metadata
118
+ server_call = server_allows_client_to_proceed
119
+
120
+ # client sends a message
121
+ msg = client_sends(call)
122
+
123
+ # confirm the server can read the inbound message
124
+ server_call.start_read(@server_tag)
125
+ ev = expect_next_event_on(@server_queue, READ, @server_tag)
126
+ expect(ev.result.to_s).to eq(msg)
127
+
128
+ # the server response
129
+ server_call.start_write(reply, @server_tag)
130
+ expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag)
131
+ end
132
+
133
+ it 'responses written by servers are received by the client' do
134
+ call = new_client_call
135
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
136
+ server_call = server_allows_client_to_proceed
137
+ client_sends(call)
138
+ server_responds_with(server_call, 'server_response')
139
+
140
+ call.start_read(@tag)
141
+ ev = expect_next_event_on(@client_queue, READ, @tag)
142
+ expect(ev.result.to_s).to eq('server_response')
143
+ end
144
+
145
+ it 'servers can ignore a client write and send a status' do
146
+ call = new_client_call
147
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
148
+
149
+ # check the server rpc new was received
150
+ @server.request_call(@server_tag)
151
+ ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
152
+ expect(ev.tag).to be(@server_tag)
153
+
154
+ # accept the call - need to do this to sent status.
155
+ server_call = ev.call
156
+ server_call.server_accept(@server_queue, @server_finished_tag)
157
+ server_call.server_end_initial_metadata
158
+ server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found',
159
+ @server_tag)
160
+
161
+ # Client sends some data
162
+ client_sends(call)
163
+
164
+ # client gets an empty response for the read, preceeded by some metadata.
165
+ call.start_read(@tag)
166
+ expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
167
+ @client_metadata_tag)
168
+ ev = expect_next_event_on(@client_queue, READ, @tag)
169
+ expect(ev.tag).to be(@tag)
170
+ expect(ev.result.to_s).to eq('')
171
+
172
+ # finally, after client sends writes_done, they get the finished.
173
+ call.writes_done(@tag)
174
+ expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
175
+ ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
176
+ expect(ev.result.code).to eq(StatusCodes::NOT_FOUND)
177
+ end
178
+
179
+ it 'completes calls by sending status to client and server' do
180
+ call = new_client_call
181
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
182
+ server_call = server_allows_client_to_proceed
183
+ client_sends(call)
184
+ server_responds_with(server_call, 'server_response')
185
+ server_call.start_write_status(10_101, 'status code is 10101', @server_tag)
186
+
187
+ # first the client says writes are done
188
+ call.start_read(@tag)
189
+ expect_next_event_on(@client_queue, READ, @tag)
190
+ call.writes_done(@tag)
191
+
192
+ # but nothing happens until the server sends a status
193
+ expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag)
194
+ ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag)
195
+ expect(ev.result).to be_a(Struct::Status)
196
+
197
+ # client gets FINISHED
198
+ expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
199
+ ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
200
+ expect(ev.result.details).to eq('status code is 10101')
201
+ expect(ev.result.code).to eq(10_101)
202
+ end
203
+ end
204
+
205
+ shared_examples 'GRPC metadata delivery works OK' do
206
+ include_context 'setup: tags'
207
+
208
+ describe 'from client => server' do
209
+ before(:example) do
210
+ n = 7 # arbitrary number of metadata
211
+ diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
212
+ diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
213
+ null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
214
+ null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
215
+ same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
216
+ same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
217
+ symbol_key = { a_key: 'a val' }
218
+ @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
219
+ @bad_keys = []
220
+ @bad_keys << { Object.new => 'a value' }
221
+ @bad_keys << { 1 => 'a value' }
222
+ end
223
+
224
+ it 'raises an exception if a metadata key is invalid' do
225
+ @bad_keys.each do |md|
226
+ call = new_client_call
227
+ expect { call.add_metadata(md) }.to raise_error
228
+ end
229
+ end
230
+
231
+ it 'sends all the metadata pairs when keys and values are valid' do
232
+ @valid_metadata.each do |md|
233
+ call = new_client_call
234
+ call.add_metadata(md)
235
+
236
+ # Client begins a call OK
237
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
238
+
239
+ # ... server has all metadata available even though the client did not
240
+ # send a write
241
+ @server.request_call(@server_tag)
242
+ ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
243
+ replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
244
+ result = ev.result.metadata
245
+ expect(result.merge(replace_symbols)).to eq(result)
246
+ end
247
+ end
248
+ end
249
+
250
+ describe 'from server => client' do
251
+ before(:example) do
252
+ n = 7 # arbitrary number of metadata
253
+ diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
254
+ diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
255
+ null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
256
+ null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
257
+ same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
258
+ same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
259
+ symbol_key = { a_key: 'a val' }
260
+ @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
261
+ @bad_keys = []
262
+ @bad_keys << { Object.new => 'a value' }
263
+ @bad_keys << { 1 => 'a value' }
264
+ end
265
+
266
+ it 'raises an exception if a metadata key is invalid' do
267
+ @bad_keys.each do |md|
268
+ call = new_client_call
269
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
270
+
271
+ # server gets the invocation
272
+ @server.request_call(@server_tag)
273
+ ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
274
+ expect { ev.call.add_metadata(md) }.to raise_error
275
+ end
276
+ end
277
+
278
+ it 'sends a hash that contains the status when no metadata is added' do
279
+ call = new_client_call
280
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
281
+
282
+ # server gets the invocation
283
+ @server.request_call(@server_tag)
284
+ ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
285
+ server_call = ev.call
286
+
287
+ # ... server accepts the call without adding metadata
288
+ server_call.server_accept(@server_queue, @server_finished_tag)
289
+ server_call.server_end_initial_metadata
290
+
291
+ # there is the HTTP status metadata, though there should not be any
292
+ # TODO: update this with the bug number to be resolved
293
+ ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
294
+ @client_metadata_tag)
295
+ expect(ev.result).to eq({})
296
+ end
297
+
298
+ it 'sends all the pairs when keys and values are valid' do
299
+ @valid_metadata.each do |md|
300
+ call = new_client_call
301
+ call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
302
+
303
+ # server gets the invocation
304
+ @server.request_call(@server_tag)
305
+ ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
306
+ server_call = ev.call
307
+
308
+ # ... server adds metadata and accepts the call
309
+ server_call.add_metadata(md)
310
+ server_call.server_accept(@server_queue, @server_finished_tag)
311
+ server_call.server_end_initial_metadata
312
+
313
+ # Now the client can read the metadata
314
+ ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
315
+ @client_metadata_tag)
316
+ replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
317
+ expect(ev.result).to eq(replace_symbols)
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ describe 'the http client/server' do
324
+ before(:example) do
325
+ server_host = '0.0.0.0:0'
326
+ @client_queue = GRPC::Core::CompletionQueue.new
327
+ @server_queue = GRPC::Core::CompletionQueue.new
328
+ @server = GRPC::Core::Server.new(@server_queue, nil)
329
+ server_port = @server.add_http2_port(server_host)
330
+ @server.start
331
+ @ch = Channel.new("0.0.0.0:#{server_port}", nil)
332
+ end
333
+
334
+ after(:example) do
335
+ @ch.close
336
+ @server.close
337
+ end
338
+
339
+ it_behaves_like 'basic GRPC message delivery is OK' do
340
+ end
341
+
342
+ it_behaves_like 'GRPC metadata delivery works OK' do
343
+ end
344
+ end
345
+
346
+ describe 'the secure http client/server' do
347
+ before(:example) do
348
+ certs = load_test_certs
349
+ server_host = 'localhost:0'
350
+ @client_queue = GRPC::Core::CompletionQueue.new
351
+ @server_queue = GRPC::Core::CompletionQueue.new
352
+ server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
353
+ @server = GRPC::Core::Server.new(@server_queue, nil, server_creds)
354
+ server_port = @server.add_http2_port(server_host, true)
355
+ @server.start
356
+ args = { Channel::SSL_TARGET => 'foo.test.google.fr' }
357
+ @ch = Channel.new("0.0.0.0:#{server_port}", args,
358
+ GRPC::Core::Credentials.new(certs[0], nil, nil))
359
+ end
360
+
361
+ after(:example) do
362
+ @server.close
363
+ end
364
+
365
+ # TODO: uncomment after updating the to the new c api
366
+ # it_behaves_like 'basic GRPC message delivery is OK' do
367
+ # end
368
+
369
+ # TODO: uncomment after updating the to the new c api
370
+ # it_behaves_like 'GRPC metadata delivery works OK' do
371
+ # end
372
+ end