grpc 1.74.0.pre2-x86-linux-musl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32-msvcrt.ruby +0 -0
  4. data/grpc_c.64-ucrt.ruby +0 -0
  5. data/src/ruby/bin/math_client.rb +140 -0
  6. data/src/ruby/bin/math_pb.rb +19 -0
  7. data/src/ruby/bin/math_server.rb +191 -0
  8. data/src/ruby/bin/math_services_pb.rb +51 -0
  9. data/src/ruby/bin/noproto_client.rb +93 -0
  10. data/src/ruby/bin/noproto_server.rb +97 -0
  11. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
  13. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
  14. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
  15. data/src/ruby/ext/grpc/ext-export.clang +1 -0
  16. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  17. data/src/ruby/ext/grpc/extconf.rb +269 -0
  18. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  19. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  20. data/src/ruby/ext/grpc/rb_call.c +1075 -0
  21. data/src/ruby/ext/grpc/rb_call.h +57 -0
  22. data/src/ruby/ext/grpc/rb_call_credentials.c +347 -0
  23. data/src/ruby/ext/grpc/rb_call_credentials.h +32 -0
  24. data/src/ruby/ext/grpc/rb_channel.c +391 -0
  25. data/src/ruby/ext/grpc/rb_channel.h +32 -0
  26. data/src/ruby/ext/grpc/rb_channel_args.c +174 -0
  27. data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
  28. data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
  29. data/src/ruby/ext/grpc/rb_channel_credentials.h +36 -0
  30. data/src/ruby/ext/grpc/rb_completion_queue.c +95 -0
  31. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  32. data/src/ruby/ext/grpc/rb_compression_options.c +469 -0
  33. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  34. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  35. data/src/ruby/ext/grpc/rb_event_thread.c +167 -0
  36. data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
  37. data/src/ruby/ext/grpc/rb_grpc.c +500 -0
  38. data/src/ruby/ext/grpc/rb_grpc.h +88 -0
  39. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +597 -0
  40. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +902 -0
  41. data/src/ruby/ext/grpc/rb_loader.c +57 -0
  42. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  43. data/src/ruby/ext/grpc/rb_server.c +406 -0
  44. data/src/ruby/ext/grpc/rb_server.h +32 -0
  45. data/src/ruby/ext/grpc/rb_server_credentials.c +259 -0
  46. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  47. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
  48. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +36 -0
  49. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +170 -0
  50. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  51. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  52. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  53. data/src/ruby/lib/grpc/3.3/grpc_c.so +0 -0
  54. data/src/ruby/lib/grpc/3.4/grpc_c.so +0 -0
  55. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  56. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  57. data/src/ruby/lib/grpc/errors.rb +277 -0
  58. data/src/ruby/lib/grpc/generic/active_call.rb +679 -0
  59. data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
  60. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  61. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  62. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  63. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  64. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  65. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  66. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  67. data/src/ruby/lib/grpc/grpc.rb +24 -0
  68. data/src/ruby/lib/grpc/logconfig.rb +57 -0
  69. data/src/ruby/lib/grpc/notifier.rb +45 -0
  70. data/src/ruby/lib/grpc/structs.rb +15 -0
  71. data/src/ruby/lib/grpc/version.rb +18 -0
  72. data/src/ruby/lib/grpc.rb +37 -0
  73. data/src/ruby/pb/README.md +42 -0
  74. data/src/ruby/pb/generate_proto_ruby.sh +46 -0
  75. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  76. data/src/ruby/pb/grpc/health/v1/health_pb.rb +21 -0
  77. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  78. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  79. data/src/ruby/pb/grpc/testing/metrics_pb.rb +19 -0
  80. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  81. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +17 -0
  82. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +50 -0
  83. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +19 -0
  84. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
  85. data/src/ruby/pb/test/client.rb +785 -0
  86. data/src/ruby/pb/test/server.rb +252 -0
  87. data/src/ruby/pb/test/xds_client.rb +415 -0
  88. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  89. data/src/ruby/spec/call_spec.rb +193 -0
  90. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  91. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  92. data/src/ruby/spec/channel_spec.rb +209 -0
  93. data/src/ruby/spec/client_auth_spec.rb +152 -0
  94. data/src/ruby/spec/client_server_spec.rb +317 -0
  95. data/src/ruby/spec/compression_options_spec.rb +149 -0
  96. data/src/ruby/spec/core_spec.rb +22 -0
  97. data/src/ruby/spec/debug_message_spec.rb +134 -0
  98. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  99. data/src/ruby/spec/errors_spec.rb +142 -0
  100. data/src/ruby/spec/generic/active_call_spec.rb +670 -0
  101. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  102. data/src/ruby/spec/generic/client_stub_spec.rb +1079 -0
  103. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  104. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  105. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  106. data/src/ruby/spec/generic/rpc_server_spec.rb +773 -0
  107. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  108. data/src/ruby/spec/generic/service_spec.rb +263 -0
  109. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  110. data/src/ruby/spec/logconfig_spec.rb +30 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  112. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  113. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  114. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  115. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  116. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  117. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  118. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  119. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  120. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  121. data/src/ruby/spec/server_spec.rb +231 -0
  122. data/src/ruby/spec/spec_helper.rb +61 -0
  123. data/src/ruby/spec/support/helpers.rb +107 -0
  124. data/src/ruby/spec/support/services.rb +163 -0
  125. data/src/ruby/spec/testdata/README +1 -0
  126. data/src/ruby/spec/testdata/ca.pem +20 -0
  127. data/src/ruby/spec/testdata/client.key +28 -0
  128. data/src/ruby/spec/testdata/client.pem +20 -0
  129. data/src/ruby/spec/testdata/server1.key +28 -0
  130. data/src/ruby/spec/testdata/server1.pem +22 -0
  131. data/src/ruby/spec/time_consts_spec.rb +74 -0
  132. data/src/ruby/spec/user_agent_spec.rb +74 -0
  133. metadata +411 -0
@@ -0,0 +1,1079 @@
1
+ # Copyright 2015 gRPC authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ Thread.abort_on_exception = true
18
+
19
+ def wakey_thread(&blk)
20
+ n = GRPC::Notifier.new
21
+ t = Thread.new do
22
+ blk.call(n)
23
+ end
24
+ t.abort_on_exception = true
25
+ n.wait
26
+ t
27
+ end
28
+
29
+ def load_test_certs
30
+ test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata')
31
+ files = ['ca.pem', 'server1.key', 'server1.pem']
32
+ files.map { |f| File.open(File.join(test_root, f)).read }
33
+ end
34
+
35
+ include GRPC::Core::StatusCodes
36
+ include GRPC::Core::TimeConsts
37
+ include GRPC::Core::CallOps
38
+
39
+ # check that methods on a finished/closed call t crash
40
+ def check_op_view_of_finished_client_call(op_view,
41
+ expected_metadata,
42
+ expected_trailing_metadata)
43
+ # use read_response_stream to try to iterate through
44
+ # possible response stream
45
+ fail('need something to attempt reads') unless block_given?
46
+ expect do
47
+ resp = op_view.execute
48
+ yield resp
49
+ end.to raise_error(GRPC::Core::CallError)
50
+
51
+ expect { op_view.start_call }.to raise_error(RuntimeError)
52
+
53
+ sanity_check_values_of_accessors(op_view,
54
+ expected_metadata,
55
+ expected_trailing_metadata)
56
+
57
+ expect do
58
+ op_view.wait
59
+ op_view.cancel
60
+ op_view.write_flag = 1
61
+ end.to_not raise_error
62
+ end
63
+
64
+ def sanity_check_values_of_accessors(op_view,
65
+ expected_metadata,
66
+ expected_trailing_metadata)
67
+ expect(op_view.status.code).to eq(0)
68
+ expect(op_view.status.metadata).to eq(expected_trailing_metadata)
69
+ expect(op_view.metadata).to eq(expected_metadata)
70
+ expect(op_view.trailing_metadata).to eq(expected_trailing_metadata)
71
+
72
+ expect(op_view.cancelled?).to be(false)
73
+ expect(op_view.write_flag).to be(nil)
74
+
75
+ # The deadline attribute of a call can be either
76
+ # a GRPC::Core::TimeSpec or a Time, which are mutually exclusive.
77
+ # TODO: fix so that the accessor always returns the same type.
78
+ expect(op_view.deadline.is_a?(GRPC::Core::TimeSpec) ||
79
+ op_view.deadline.is_a?(Time)).to be(true)
80
+ end
81
+
82
+ def close_active_server_call(active_server_call)
83
+ active_server_call.send(:set_input_stream_done)
84
+ active_server_call.send(:set_output_stream_done)
85
+ end
86
+
87
+ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
88
+ let(:noop) { proc { |x| x } }
89
+
90
+ before(:each) do
91
+ Thread.abort_on_exception = true
92
+ @server = nil
93
+ @method = 'an_rpc_method'
94
+ @pass = OK
95
+ @fail = INTERNAL
96
+ @metadata = { k1: 'v1', k2: 'v2' }
97
+ end
98
+
99
+ after(:each) do
100
+ unless @server.nil?
101
+ @server.shutdown_and_notify(from_relative_time(2))
102
+ @server.close
103
+ end
104
+ end
105
+
106
+ describe '#new' do
107
+ let(:fake_host) { 'localhost:0' }
108
+ it 'can be created from a host and args' do
109
+ opts = { channel_args: { a_channel_arg: 'an_arg' } }
110
+ blk = proc do
111
+ GRPC::ClientStub.new(fake_host, :this_channel_is_insecure, **opts)
112
+ end
113
+ expect(&blk).not_to raise_error
114
+ end
115
+
116
+ it 'can be created with an channel override' do
117
+ opts = {
118
+ channel_args: { a_channel_arg: 'an_arg' },
119
+ channel_override: @ch
120
+ }
121
+ blk = proc do
122
+ GRPC::ClientStub.new(fake_host, :this_channel_is_insecure, **opts)
123
+ end
124
+ expect(&blk).not_to raise_error
125
+ end
126
+
127
+ it 'cannot be created with a bad channel override' do
128
+ blk = proc do
129
+ opts = {
130
+ channel_args: { a_channel_arg: 'an_arg' },
131
+ channel_override: Object.new
132
+ }
133
+ GRPC::ClientStub.new(fake_host, :this_channel_is_insecure, **opts)
134
+ end
135
+ expect(&blk).to raise_error
136
+ end
137
+
138
+ it 'cannot be created with bad credentials' do
139
+ blk = proc do
140
+ opts = { channel_args: { a_channel_arg: 'an_arg' } }
141
+ GRPC::ClientStub.new(fake_host, Object.new, **opts)
142
+ end
143
+ expect(&blk).to raise_error
144
+ end
145
+
146
+ it 'can be created with test test credentials' do
147
+ certs = load_test_certs
148
+ blk = proc do
149
+ opts = {
150
+ channel_args: {
151
+ GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr',
152
+ a_channel_arg: 'an_arg'
153
+ }
154
+ }
155
+ creds = GRPC::Core::ChannelCredentials.new(certs[0], nil, nil)
156
+ GRPC::ClientStub.new(fake_host, creds, **opts)
157
+ end
158
+ expect(&blk).to_not raise_error
159
+ end
160
+ end
161
+
162
+ describe '#request_response', request_response: true do
163
+ before(:each) do
164
+ @sent_msg, @resp = 'a_msg', 'a_reply'
165
+ end
166
+
167
+ shared_examples 'request response' do
168
+ it 'should send a request to/receive a reply from a server' do
169
+ server_port = create_test_server
170
+ th = run_request_response(@sent_msg, @resp, @pass)
171
+ stub = GRPC::ClientStub.new("localhost:#{server_port}",
172
+ :this_channel_is_insecure)
173
+ expect(get_response(stub)).to eq(@resp)
174
+ th.join
175
+ end
176
+
177
+ def metadata_test(md)
178
+ server_port = create_test_server
179
+ host = "localhost:#{server_port}"
180
+ th = run_request_response(@sent_msg, @resp, @pass,
181
+ expected_metadata: md)
182
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
183
+ @metadata = md
184
+ expect(get_response(stub)).to eq(@resp)
185
+ th.join
186
+ end
187
+
188
+ it 'should send metadata to the server ok' do
189
+ metadata_test(k1: 'v1', k2: 'v2')
190
+ end
191
+
192
+ # these tests mostly try to exercise when md might be allocated
193
+ # instead of inlined
194
+ it 'should send metadata with multiple large md to the server ok' do
195
+ val_array = %w(
196
+ '00000000000000000000000000000000000000000000000000000000000000',
197
+ '11111111111111111111111111111111111111111111111111111111111111',
198
+ '22222222222222222222222222222222222222222222222222222222222222',
199
+ )
200
+ md = {
201
+ k1: val_array,
202
+ k2: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
203
+ k3: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
204
+ k4: 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
205
+ keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v5',
206
+ 'k66666666666666666666666666666666666666666666666666666' => 'v6',
207
+ 'k77777777777777777777777777777777777777777777777777777' => 'v7',
208
+ 'k88888888888888888888888888888888888888888888888888888' => 'v8'
209
+ }
210
+ metadata_test(md)
211
+ end
212
+
213
+ it 'should send a request when configured using an override channel' do
214
+ server_port = create_test_server
215
+ alt_host = "localhost:#{server_port}"
216
+ th = run_request_response(@sent_msg, @resp, @pass)
217
+ ch = GRPC::Core::Channel.new(alt_host, nil, :this_channel_is_insecure)
218
+ stub = GRPC::ClientStub.new('ignored-host',
219
+ :this_channel_is_insecure,
220
+ channel_override: ch)
221
+ expect(get_response(stub)).to eq(@resp)
222
+ th.join
223
+ end
224
+
225
+ it 'should raise an error if the status is not OK' do
226
+ server_port = create_test_server
227
+ host = "localhost:#{server_port}"
228
+ th = run_request_response(@sent_msg, @resp, @fail)
229
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
230
+ blk = proc { get_response(stub) }
231
+ expect(&blk).to raise_error(GRPC::BadStatus)
232
+ th.join
233
+ end
234
+
235
+ it 'should receive UNAVAILABLE if call credentials plugin fails' do
236
+ server_port = create_secure_test_server
237
+ server_started_notifier = GRPC::Notifier.new
238
+ th = Thread.new do
239
+ @server.start
240
+ server_started_notifier.notify(nil)
241
+ # Poll on the server so that the client connection can proceed.
242
+ # We don't expect the server to actually accept a call though.
243
+ expect { @server.request_call }.to raise_error(GRPC::Core::CallError)
244
+ end
245
+ server_started_notifier.wait
246
+
247
+ certs = load_test_certs
248
+ secure_channel_creds = GRPC::Core::ChannelCredentials.new(
249
+ certs[0], nil, nil)
250
+ secure_stub_opts = {
251
+ channel_args: {
252
+ GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr'
253
+ }
254
+ }
255
+ stub = GRPC::ClientStub.new("localhost:#{server_port}",
256
+ secure_channel_creds, **secure_stub_opts)
257
+
258
+ error_message = 'Failing call credentials callback'
259
+ failing_auth = proc do
260
+ fail error_message
261
+ end
262
+ creds = GRPC::Core::CallCredentials.new(failing_auth)
263
+
264
+ unavailable_error_occurred = false
265
+ begin
266
+ get_response(stub, credentials: creds)
267
+ rescue GRPC::Unavailable => e
268
+ unavailable_error_occurred = true
269
+ expect(e.details.include?(error_message)).to be true
270
+ end
271
+ expect(unavailable_error_occurred).to eq(true)
272
+
273
+ @server.shutdown_and_notify(Time.now + 3)
274
+ th.join
275
+ @server.close
276
+ end
277
+
278
+ it 'should raise ArgumentError if metadata contains invalid values' do
279
+ @metadata.merge!(k3: 3)
280
+ server_port = create_test_server
281
+ host = "localhost:#{server_port}"
282
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
283
+ expect do
284
+ get_response(stub)
285
+ end.to raise_error(ArgumentError,
286
+ /Header values must be of type string or array/)
287
+ end
288
+ end
289
+
290
+ describe 'without a call operation' do
291
+ def get_response(stub, credentials: nil)
292
+ GRPC.logger.info(credentials.inspect)
293
+ stub.request_response(@method, @sent_msg, noop, noop,
294
+ metadata: @metadata,
295
+ credentials: credentials)
296
+ end
297
+
298
+ it_behaves_like 'request response'
299
+ end
300
+
301
+ describe 'via a call operation' do
302
+ after(:each) do
303
+ # make sure op.wait doesn't freeze, even if there's a bad status
304
+ @op.wait
305
+ end
306
+ def get_response(stub, run_start_call_first: false, credentials: nil)
307
+ @op = stub.request_response(@method, @sent_msg, noop, noop,
308
+ return_op: true,
309
+ metadata: @metadata,
310
+ deadline: from_relative_time(2),
311
+ credentials: credentials)
312
+ expect(@op).to be_a(GRPC::ActiveCall::Operation)
313
+ @op.start_call if run_start_call_first
314
+ result = @op.execute
315
+ result
316
+ end
317
+
318
+ it_behaves_like 'request response'
319
+
320
+ def run_op_view_metadata_test(run_start_call_first)
321
+ server_port = create_test_server
322
+ host = "localhost:#{server_port}"
323
+
324
+ @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
325
+ @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
326
+ th = run_request_response(
327
+ @sent_msg, @resp, @pass,
328
+ expected_metadata: @metadata,
329
+ server_initial_md: @server_initial_md,
330
+ server_trailing_md: @server_trailing_md)
331
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
332
+ expect(
333
+ get_response(stub,
334
+ run_start_call_first: run_start_call_first)).to eq(@resp)
335
+ th.join
336
+ end
337
+
338
+ it 'sends metadata to the server ok when running start_call first' do
339
+ run_op_view_metadata_test(true)
340
+ check_op_view_of_finished_client_call(
341
+ @op, @server_initial_md, @server_trailing_md
342
+ ) { |r| GRPC.logger.info(r) }
343
+ end
344
+
345
+ it 'does not crash when used after the call has been finished' do
346
+ run_op_view_metadata_test(false)
347
+ check_op_view_of_finished_client_call(
348
+ @op, @server_initial_md, @server_trailing_md
349
+ ) { |r| GRPC.logger.info(r) }
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#client_streamer', client_streamer: true do
355
+ before(:each) do
356
+ Thread.abort_on_exception = true
357
+ server_port = create_test_server
358
+ host = "localhost:#{server_port}"
359
+ @stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
360
+ @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
361
+ @resp = 'a_reply'
362
+ end
363
+
364
+ shared_examples 'client streaming' do
365
+ it 'should send requests to/receive a reply from a server' do
366
+ th = run_client_streamer(@sent_msgs, @resp, @pass)
367
+ expect(get_response(@stub)).to eq(@resp)
368
+ th.join
369
+ end
370
+
371
+ it 'should send metadata to the server ok' do
372
+ th = run_client_streamer(@sent_msgs, @resp, @pass,
373
+ expected_metadata: @metadata)
374
+ expect(get_response(@stub)).to eq(@resp)
375
+ th.join
376
+ end
377
+
378
+ it 'should raise an error if the status is not ok' do
379
+ th = run_client_streamer(@sent_msgs, @resp, @fail)
380
+ blk = proc { get_response(@stub) }
381
+ expect(&blk).to raise_error(GRPC::BadStatus)
382
+ th.join
383
+ end
384
+
385
+ it 'should raise ArgumentError if metadata contains invalid values' do
386
+ @metadata.merge!(k3: 3)
387
+ expect do
388
+ get_response(@stub)
389
+ end.to raise_error(ArgumentError,
390
+ /Header values must be of type string or array/)
391
+ end
392
+ end
393
+
394
+ describe 'without a call operation' do
395
+ def get_response(stub)
396
+ stub.client_streamer(@method, @sent_msgs, noop, noop,
397
+ metadata: @metadata)
398
+ end
399
+
400
+ it_behaves_like 'client streaming'
401
+ end
402
+
403
+ describe 'via a call operation' do
404
+ after(:each) do
405
+ # make sure op.wait doesn't freeze, even if there's a bad status
406
+ @op.wait
407
+ end
408
+ def get_response(stub, run_start_call_first: false)
409
+ @op = stub.client_streamer(@method, @sent_msgs, noop, noop,
410
+ return_op: true, metadata: @metadata)
411
+ expect(@op).to be_a(GRPC::ActiveCall::Operation)
412
+ @op.start_call if run_start_call_first
413
+ result = @op.execute
414
+ result
415
+ end
416
+
417
+ it_behaves_like 'client streaming'
418
+
419
+ def run_op_view_metadata_test(run_start_call_first)
420
+ @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
421
+ @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
422
+ th = run_client_streamer(
423
+ @sent_msgs, @resp, @pass,
424
+ expected_metadata: @metadata,
425
+ server_initial_md: @server_initial_md,
426
+ server_trailing_md: @server_trailing_md)
427
+ expect(
428
+ get_response(@stub,
429
+ run_start_call_first: run_start_call_first)).to eq(@resp)
430
+ th.join
431
+ end
432
+
433
+ it 'sends metadata to the server ok when running start_call first' do
434
+ run_op_view_metadata_test(true)
435
+ check_op_view_of_finished_client_call(
436
+ @op, @server_initial_md, @server_trailing_md
437
+ ) { |r| GRPC.logger.info(r) }
438
+ end
439
+
440
+ it 'does not crash when used after the call has been finished' do
441
+ run_op_view_metadata_test(false)
442
+ check_op_view_of_finished_client_call(
443
+ @op, @server_initial_md, @server_trailing_md
444
+ ) { |r| GRPC.logger.info(r) }
445
+ end
446
+ end
447
+ end
448
+
449
+ describe '#server_streamer', server_streamer: true do
450
+ before(:each) do
451
+ @sent_msg = 'a_msg'
452
+ @replies = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
453
+ end
454
+
455
+ shared_examples 'server streaming' do
456
+ it 'should send a request to/receive replies from a server' do
457
+ server_port = create_test_server
458
+ host = "localhost:#{server_port}"
459
+ th = run_server_streamer(@sent_msg, @replies, @pass)
460
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
461
+ expect(get_responses(stub).collect { |r| r }).to eq(@replies)
462
+ th.join
463
+ end
464
+
465
+ it 'should raise an error if the status is not ok' do
466
+ server_port = create_test_server
467
+ host = "localhost:#{server_port}"
468
+ th = run_server_streamer(@sent_msg, @replies, @fail)
469
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
470
+ e = get_responses(stub)
471
+ expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
472
+ th.join
473
+ end
474
+
475
+ it 'should send metadata to the server ok' do
476
+ server_port = create_test_server
477
+ host = "localhost:#{server_port}"
478
+ th = run_server_streamer(@sent_msg, @replies, @fail,
479
+ expected_metadata: { k1: 'v1', k2: 'v2' })
480
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
481
+ e = get_responses(stub)
482
+ expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
483
+ th.join
484
+ end
485
+
486
+ it 'should raise ArgumentError if metadata contains invalid values' do
487
+ @metadata.merge!(k3: 3)
488
+ server_port = create_test_server
489
+ host = "localhost:#{server_port}"
490
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
491
+ expect do
492
+ get_responses(stub).collect { |r| r }
493
+ end.to raise_error(ArgumentError,
494
+ /Header values must be of type string or array/)
495
+ end
496
+
497
+ it 'the call terminates when there is an unmarshalling error' do
498
+ server_port = create_test_server
499
+ host = "localhost:#{server_port}"
500
+ th = run_server_streamer_handle_client_cancellation(
501
+ @sent_msg, @replies)
502
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
503
+
504
+ unmarshal = proc { fail(ArgumentError, 'test unmarshalling error') }
505
+ expect do
506
+ get_responses(stub, unmarshal: unmarshal).collect { |r| r }
507
+ end.to raise_error(ArgumentError, 'test unmarshalling error')
508
+ th.join
509
+ end
510
+ end
511
+
512
+ describe 'without a call operation' do
513
+ def get_responses(stub, unmarshal: noop)
514
+ e = stub.server_streamer(@method, @sent_msg, noop, unmarshal,
515
+ metadata: @metadata)
516
+ expect(e).to be_a(Enumerator)
517
+ e
518
+ end
519
+
520
+ it_behaves_like 'server streaming'
521
+ end
522
+
523
+ describe 'via a call operation' do
524
+ after(:each) do
525
+ @op.wait # make sure wait doesn't freeze
526
+ end
527
+ def get_responses(stub, run_start_call_first: false, unmarshal: noop)
528
+ @op = stub.server_streamer(@method, @sent_msg, noop, unmarshal,
529
+ return_op: true,
530
+ metadata: @metadata)
531
+ expect(@op).to be_a(GRPC::ActiveCall::Operation)
532
+ @op.start_call if run_start_call_first
533
+ e = @op.execute
534
+ expect(e).to be_a(Enumerator)
535
+ e
536
+ end
537
+
538
+ it_behaves_like 'server streaming'
539
+
540
+ def run_op_view_metadata_test(run_start_call_first)
541
+ server_port = create_test_server
542
+ host = "localhost:#{server_port}"
543
+ @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
544
+ @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
545
+ th = run_server_streamer(
546
+ @sent_msg, @replies, @pass,
547
+ expected_metadata: @metadata,
548
+ server_initial_md: @server_initial_md,
549
+ server_trailing_md: @server_trailing_md)
550
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
551
+ e = get_responses(stub, run_start_call_first: run_start_call_first)
552
+ expect(e.collect { |r| r }).to eq(@replies)
553
+ th.join
554
+ end
555
+
556
+ it 'should send metadata to the server ok when start_call is run first' do
557
+ run_op_view_metadata_test(true)
558
+ check_op_view_of_finished_client_call(
559
+ @op, @server_initial_md, @server_trailing_md) do |responses|
560
+ responses.each { |r| GRPC.logger.info(r) }
561
+ end
562
+ end
563
+
564
+ it 'does not crash when used after the call has been finished' do
565
+ run_op_view_metadata_test(false)
566
+ check_op_view_of_finished_client_call(
567
+ @op, @server_initial_md, @server_trailing_md) do |responses|
568
+ responses.each { |r| GRPC.logger.info(r) }
569
+ end
570
+ end
571
+
572
+ it 'raises GRPC::Cancelled after the call has been cancelled' do
573
+ server_port = create_test_server
574
+ host = "localhost:#{server_port}"
575
+ th = run_server_streamer_handle_client_cancellation(
576
+ @sent_msg, @replies)
577
+ stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
578
+ resp = get_responses(stub, run_start_call_first: false)
579
+ expect(resp.next).to eq('reply_1')
580
+ @op.cancel
581
+ expect { resp.next }.to raise_error(GRPC::Cancelled)
582
+ th.join
583
+ end
584
+ end
585
+ end
586
+
587
+ describe '#bidi_streamer', bidi: true do
588
+ before(:each) do
589
+ @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
590
+ @replies = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
591
+ server_port = create_test_server
592
+ @host = "localhost:#{server_port}"
593
+ end
594
+
595
+ shared_examples 'bidi streaming' do
596
+ it 'supports sending all the requests first' do
597
+ th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replies,
598
+ @pass)
599
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
600
+ e = get_responses(stub)
601
+ expect(e.collect { |r| r }).to eq(@replies)
602
+ th.join
603
+ end
604
+
605
+ it 'supports client-initiated ping pong' do
606
+ th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true)
607
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
608
+ e = get_responses(stub)
609
+ expect(e.collect { |r| r }).to eq(@sent_msgs)
610
+ th.join
611
+ end
612
+
613
+ it 'supports a server-initiated ping pong' do
614
+ th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
615
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
616
+ e = get_responses(stub)
617
+ expect(e.collect { |r| r }).to eq(@sent_msgs)
618
+ th.join
619
+ end
620
+
621
+ it 'should raise an error if the status is not ok' do
622
+ th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @fail, false)
623
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
624
+ e = get_responses(stub)
625
+ expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
626
+ th.join
627
+ end
628
+
629
+ it 'should raise ArgumentError if metadata contains invalid values' do
630
+ @metadata.merge!(k3: 3)
631
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
632
+ expect do
633
+ get_responses(stub).collect { |r| r }
634
+ end.to raise_error(ArgumentError,
635
+ /Header values must be of type string or array/)
636
+ end
637
+
638
+ it 'terminates if the call fails to start' do
639
+ # don't start the server
640
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
641
+ expect do
642
+ get_responses(stub, deadline: from_relative_time(0)).collect { |r| r }
643
+ end.to raise_error(GRPC::BadStatus)
644
+ end
645
+
646
+ it 'should send metadata to the server ok' do
647
+ th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true,
648
+ expected_metadata: @metadata)
649
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
650
+ e = get_responses(stub)
651
+ expect(e.collect { |r| r }).to eq(@sent_msgs)
652
+ th.join
653
+ end
654
+
655
+ # Prompted by grpc/github #10526
656
+ describe 'surfacing of errors when sending requests' do
657
+ def run_server_bidi_send_one_then_read_indefinitely
658
+ @server.start
659
+ recvd_rpc = @server.request_call
660
+ recvd_call = recvd_rpc.call
661
+ server_call = GRPC::ActiveCall.new(
662
+ recvd_call, noop, noop, INFINITE_FUTURE,
663
+ metadata_received: true, started: false)
664
+ server_call.send_initial_metadata
665
+ server_call.remote_send('server response')
666
+ loop do
667
+ m = server_call.remote_read
668
+ break if m.nil?
669
+ end
670
+ # can't fail since initial metadata already sent
671
+ server_call.send_status(@pass, 'OK', true)
672
+ close_active_server_call(server_call)
673
+ end
674
+
675
+ def verify_error_from_write_thread(stub, requests_to_push,
676
+ request_queue, expected_description)
677
+ # TODO: an improvement might be to raise the original exception from
678
+ # bidi call write loops instead of only cancelling the call
679
+ failing_marshal_proc = proc do |req|
680
+ fail req if req.is_a?(StandardError)
681
+ req
682
+ end
683
+ begin
684
+ e = get_responses(stub, marshal_proc: failing_marshal_proc)
685
+ first_response = e.next
686
+ expect(first_response).to eq('server response')
687
+ requests_to_push.each { |req| request_queue.push(req) }
688
+ e.collect { |r| r }
689
+ rescue GRPC::Unknown => e
690
+ exception = e
691
+ end
692
+ expect(exception.message.include?(expected_description)).to be(true)
693
+ end
694
+
695
+ # Provides an Enumerable view of a Queue
696
+ class BidiErrorTestingEnumerateForeverQueue
697
+ def initialize(queue)
698
+ @queue = queue
699
+ end
700
+
701
+ def each
702
+ loop do
703
+ msg = @queue.pop
704
+ yield msg
705
+ end
706
+ end
707
+ end
708
+
709
+ def run_error_in_client_request_stream_test(requests_to_push,
710
+ expected_error_message)
711
+ # start a server that waits on a read indefinitely - it should
712
+ # see a cancellation and be able to break out
713
+ th = Thread.new { run_server_bidi_send_one_then_read_indefinitely }
714
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
715
+
716
+ request_queue = Queue.new
717
+ @sent_msgs = BidiErrorTestingEnumerateForeverQueue.new(request_queue)
718
+
719
+ verify_error_from_write_thread(stub,
720
+ requests_to_push,
721
+ request_queue,
722
+ expected_error_message)
723
+ # the write loop error should cancel the call and end the
724
+ # server's request stream
725
+ th.join
726
+ end
727
+
728
+ it 'non-GRPC errors from the write loop surface when raised ' \
729
+ 'at the start of a request stream' do
730
+ expected_error_message = 'expect error on first request'
731
+ requests_to_push = [StandardError.new(expected_error_message)]
732
+ run_error_in_client_request_stream_test(requests_to_push,
733
+ expected_error_message)
734
+ end
735
+
736
+ it 'non-GRPC errors from the write loop surface when raised ' \
737
+ 'during the middle of a request stream' do
738
+ expected_error_message = 'expect error on last request'
739
+ requests_to_push = %w( one two )
740
+ requests_to_push << StandardError.new(expected_error_message)
741
+ run_error_in_client_request_stream_test(requests_to_push,
742
+ expected_error_message)
743
+ end
744
+ end
745
+
746
+ # Prompted by grpc/github #14853
747
+ describe 'client-side error handling on bidi streams' do
748
+ class EnumeratorQueue
749
+ def initialize(queue)
750
+ @queue = queue
751
+ end
752
+
753
+ def each
754
+ loop do
755
+ msg = @queue.pop
756
+ break if msg.nil?
757
+ yield msg
758
+ end
759
+ end
760
+ end
761
+
762
+ def run_server_bidi_shutdown_after_one_read
763
+ @server.start
764
+ recvd_rpc = @server.request_call
765
+ recvd_call = recvd_rpc.call
766
+ server_call = GRPC::ActiveCall.new(
767
+ recvd_call, noop, noop, INFINITE_FUTURE,
768
+ metadata_received: true, started: false)
769
+ expect(server_call.remote_read).to eq('first message')
770
+ @server.shutdown_and_notify(from_relative_time(0))
771
+ @server.close
772
+ end
773
+
774
+ it 'receives a grpc status code when writes to a bidi stream fail' do
775
+ # This test tries to trigger the case when a 'SEND_MESSAGE' op
776
+ # and subsequent 'SEND_CLOSE_FROM_CLIENT' op of a bidi stream fails.
777
+ # In this case, iteration through the response stream should result
778
+ # in a grpc status code, and the writer thread should not raise an
779
+ # exception.
780
+ server_thread = Thread.new do
781
+ run_server_bidi_shutdown_after_one_read
782
+ end
783
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
784
+ request_queue = Queue.new
785
+ @sent_msgs = EnumeratorQueue.new(request_queue)
786
+ responses = get_responses(stub)
787
+ request_queue.push('first message')
788
+ # Now wait for the server to shut down.
789
+ server_thread.join
790
+ # Sanity check. This test is not interesting if
791
+ # Thread.abort_on_exception is not set.
792
+ expect(Thread.abort_on_exception).to be(true)
793
+ # An attempt to send a second message should fail now that the
794
+ # server is down.
795
+ request_queue.push('second message')
796
+ request_queue.push(nil)
797
+ expect { responses.next }.to raise_error(GRPC::BadStatus)
798
+ end
799
+
800
+ def run_server_bidi_shutdown_after_one_write
801
+ @server.start
802
+ recvd_rpc = @server.request_call
803
+ recvd_call = recvd_rpc.call
804
+ server_call = GRPC::ActiveCall.new(
805
+ recvd_call, noop, noop, INFINITE_FUTURE,
806
+ metadata_received: true, started: false)
807
+ server_call.send_initial_metadata
808
+ server_call.remote_send('message')
809
+ @server.shutdown_and_notify(from_relative_time(0))
810
+ @server.close
811
+ end
812
+
813
+ it 'receives a grpc status code when reading from a failed bidi call' do
814
+ server_thread = Thread.new do
815
+ run_server_bidi_shutdown_after_one_write
816
+ end
817
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
818
+ request_queue = Queue.new
819
+ @sent_msgs = EnumeratorQueue.new(request_queue)
820
+ responses = get_responses(stub)
821
+ expect(responses.next).to eq('message')
822
+ # Wait for the server to shut down
823
+ server_thread.join
824
+ expect { responses.next }.to raise_error(GRPC::BadStatus)
825
+ # Push a sentinel to allow the writer thread to finish
826
+ request_queue.push(nil)
827
+ end
828
+ end
829
+ end
830
+
831
+ describe 'without a call operation' do
832
+ def get_responses(stub, deadline: nil, marshal_proc: noop)
833
+ e = stub.bidi_streamer(@method, @sent_msgs, marshal_proc, noop,
834
+ metadata: @metadata, deadline: deadline)
835
+ expect(e).to be_a(Enumerator)
836
+ e
837
+ end
838
+
839
+ it_behaves_like 'bidi streaming'
840
+ end
841
+
842
+ describe 'via a call operation' do
843
+ after(:each) do
844
+ @op.wait # make sure wait doesn't freeze
845
+ end
846
+ def get_responses(stub, run_start_call_first: false, deadline: nil,
847
+ marshal_proc: noop)
848
+ @op = stub.bidi_streamer(@method, @sent_msgs, marshal_proc, noop,
849
+ return_op: true,
850
+ metadata: @metadata, deadline: deadline)
851
+ expect(@op).to be_a(GRPC::ActiveCall::Operation)
852
+ @op.start_call if run_start_call_first
853
+ e = @op.execute
854
+ expect(e).to be_a(Enumerator)
855
+ e
856
+ end
857
+
858
+ it_behaves_like 'bidi streaming'
859
+
860
+ def run_op_view_metadata_test(run_start_call_first)
861
+ @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
862
+ @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
863
+ th = run_bidi_streamer_echo_ping_pong(
864
+ @sent_msgs, @pass, true,
865
+ expected_metadata: @metadata,
866
+ server_initial_md: @server_initial_md,
867
+ server_trailing_md: @server_trailing_md)
868
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
869
+ e = get_responses(stub, run_start_call_first: run_start_call_first)
870
+ expect(e.collect { |r| r }).to eq(@sent_msgs)
871
+ th.join
872
+ end
873
+
874
+ it 'can run start_call before executing the call' do
875
+ run_op_view_metadata_test(true)
876
+ check_op_view_of_finished_client_call(
877
+ @op, @server_initial_md, @server_trailing_md) do |responses|
878
+ responses.each { |r| GRPC.logger.info(r) }
879
+ end
880
+ end
881
+
882
+ it 'doesnt crash when op_view used after call has finished' do
883
+ run_op_view_metadata_test(false)
884
+ check_op_view_of_finished_client_call(
885
+ @op, @server_initial_md, @server_trailing_md) do |responses|
886
+ responses.each { |r| GRPC.logger.info(r) }
887
+ end
888
+ end
889
+
890
+ def run_server_bidi_expect_client_to_cancel(wait_for_shutdown_ok_callback)
891
+ @server.start
892
+ recvd_rpc = @server.request_call
893
+ recvd_call = recvd_rpc.call
894
+ server_call = GRPC::ActiveCall.new(
895
+ recvd_call, noop, noop, INFINITE_FUTURE,
896
+ metadata_received: true, started: false)
897
+ server_call.send_initial_metadata
898
+ server_call.remote_send('server call received')
899
+ wait_for_shutdown_ok_callback.call
900
+ # since the client is cancelling the call,
901
+ # we should be able to shut down cleanly
902
+ @server.shutdown_and_notify(nil)
903
+ @server.close
904
+ end
905
+
906
+ it 'receives a grpc status code when reading from a cancelled bidi call' do
907
+ # This test tries to trigger a 'RECV_INITIAL_METADATA' and/or
908
+ # 'RECV_MESSAGE' op failure.
909
+ # An attempt to read a message might fail; in that case, iteration
910
+ # through the response stream should still result in a grpc status.
911
+ server_can_shutdown = false
912
+ server_can_shutdown_mu = Mutex.new
913
+ server_can_shutdown_cv = ConditionVariable.new
914
+ wait_for_shutdown_ok_callback = proc do
915
+ server_can_shutdown_mu.synchronize do
916
+ server_can_shutdown_cv.wait(server_can_shutdown_mu) until server_can_shutdown
917
+ end
918
+ end
919
+ server_thread = Thread.new do
920
+ run_server_bidi_expect_client_to_cancel(wait_for_shutdown_ok_callback)
921
+ end
922
+ stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
923
+ request_queue = Queue.new
924
+ @sent_msgs = EnumeratorQueue.new(request_queue)
925
+ responses = get_responses(stub)
926
+ expect(responses.next).to eq('server call received')
927
+ @op.cancel
928
+ expect { responses.next }.to raise_error(GRPC::Cancelled)
929
+ # Now let the server proceed to shut down.
930
+ server_can_shutdown_mu.synchronize do
931
+ server_can_shutdown = true
932
+ server_can_shutdown_cv.broadcast
933
+ end
934
+ server_thread.join
935
+ # Push a sentinel to allow the writer thread to finish
936
+ request_queue.push(nil)
937
+ end
938
+ end
939
+ end
940
+
941
+ def run_server_streamer(expected_input, replies, status,
942
+ expected_metadata: {},
943
+ server_initial_md: {},
944
+ server_trailing_md: {})
945
+ wanted_metadata = expected_metadata.clone
946
+ wakey_thread do |notifier|
947
+ c = expect_server_to_be_invoked(
948
+ notifier, metadata_to_send: server_initial_md)
949
+ wanted_metadata.each do |k, v|
950
+ expect(c.metadata[k.to_s]).to eq(v)
951
+ end
952
+ expect(c.remote_read).to eq(expected_input)
953
+ replies.each { |r| c.remote_send(r) }
954
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
955
+ metadata: server_trailing_md)
956
+ close_active_server_call(c)
957
+ end
958
+ end
959
+
960
+ def run_bidi_streamer_handle_inputs_first(expected_inputs, replies,
961
+ status)
962
+ wakey_thread do |notifier|
963
+ c = expect_server_to_be_invoked(notifier)
964
+ expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
965
+ replies.each { |r| c.remote_send(r) }
966
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
967
+ close_active_server_call(c)
968
+ end
969
+ end
970
+
971
+ def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts,
972
+ expected_metadata: {},
973
+ server_initial_md: {},
974
+ server_trailing_md: {})
975
+ wanted_metadata = expected_metadata.clone
976
+ wakey_thread do |notifier|
977
+ c = expect_server_to_be_invoked(
978
+ notifier, metadata_to_send: server_initial_md)
979
+ wanted_metadata.each do |k, v|
980
+ expect(c.metadata[k.to_s]).to eq(v)
981
+ end
982
+ expected_inputs.each do |i|
983
+ if client_starts
984
+ expect(c.remote_read).to eq(i)
985
+ c.remote_send(i)
986
+ else
987
+ c.remote_send(i)
988
+ expect(c.remote_read).to eq(i)
989
+ end
990
+ end
991
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
992
+ metadata: server_trailing_md)
993
+ close_active_server_call(c)
994
+ end
995
+ end
996
+
997
+ def run_client_streamer(expected_inputs, resp, status,
998
+ expected_metadata: {},
999
+ server_initial_md: {},
1000
+ server_trailing_md: {})
1001
+ wanted_metadata = expected_metadata.clone
1002
+ wakey_thread do |notifier|
1003
+ c = expect_server_to_be_invoked(
1004
+ notifier, metadata_to_send: server_initial_md)
1005
+ expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
1006
+ wanted_metadata.each do |k, v|
1007
+ expect(c.metadata[k.to_s]).to eq(v)
1008
+ end
1009
+ c.remote_send(resp)
1010
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
1011
+ metadata: server_trailing_md)
1012
+ close_active_server_call(c)
1013
+ end
1014
+ end
1015
+
1016
+ def run_server_streamer_handle_client_cancellation(
1017
+ expected_input, replies)
1018
+ wakey_thread do |notifier|
1019
+ c = expect_server_to_be_invoked(notifier)
1020
+ expect(c.remote_read).to eq(expected_input)
1021
+ begin
1022
+ replies.each { |r| c.remote_send(r) }
1023
+ rescue GRPC::Core::CallError
1024
+ # An attempt to write to the client might fail. This is ok
1025
+ # because the client call is expected to cancel the call,
1026
+ # and there is a race as for when the server-side call will
1027
+ # start to fail.
1028
+ p 'remote_send failed (allowed because call expected to cancel)'
1029
+ ensure
1030
+ c.send_status(OK, 'OK', true)
1031
+ close_active_server_call(c)
1032
+ end
1033
+ end
1034
+ end
1035
+
1036
+ def run_request_response(expected_input, resp, status,
1037
+ expected_metadata: {},
1038
+ server_initial_md: {},
1039
+ server_trailing_md: {})
1040
+ wanted_metadata = expected_metadata.clone
1041
+ wakey_thread do |notifier|
1042
+ c = expect_server_to_be_invoked(
1043
+ notifier, metadata_to_send: server_initial_md)
1044
+ expect(c.remote_read).to eq(expected_input)
1045
+ wanted_metadata.each do |k, v|
1046
+ expect(c.metadata[k.to_s]).to eq(v)
1047
+ end
1048
+ c.remote_send(resp)
1049
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
1050
+ metadata: server_trailing_md)
1051
+ close_active_server_call(c)
1052
+ end
1053
+ end
1054
+
1055
+ def create_secure_test_server
1056
+ certs = load_test_certs
1057
+ secure_credentials = GRPC::Core::ServerCredentials.new(
1058
+ nil, [{ private_key: certs[1], cert_chain: certs[2] }], false)
1059
+
1060
+ @server = new_core_server_for_testing(nil)
1061
+ @server.add_http2_port('0.0.0.0:0', secure_credentials)
1062
+ end
1063
+
1064
+ def create_test_server
1065
+ @server = new_core_server_for_testing(nil)
1066
+ @server.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
1067
+ end
1068
+
1069
+ def expect_server_to_be_invoked(notifier, metadata_to_send: nil)
1070
+ @server.start
1071
+ notifier.notify(nil)
1072
+ recvd_rpc = @server.request_call
1073
+ recvd_call = recvd_rpc.call
1074
+ recvd_call.metadata = recvd_rpc.metadata
1075
+ recvd_call.run_batch(SEND_INITIAL_METADATA => metadata_to_send)
1076
+ GRPC::ActiveCall.new(recvd_call, noop, noop, INFINITE_FUTURE,
1077
+ metadata_received: true)
1078
+ end
1079
+ end