grpc 1.42.0.pre1-x86_64-darwin

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 (128) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32.ruby +0 -0
  4. data/grpc_c.64.ruby +0 -0
  5. data/src/ruby/bin/math_client.rb +140 -0
  6. data/src/ruby/bin/math_pb.rb +34 -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.clang +1 -0
  12. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  13. data/src/ruby/ext/grpc/extconf.rb +123 -0
  14. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  15. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  16. data/src/ruby/ext/grpc/rb_call.c +1051 -0
  17. data/src/ruby/ext/grpc/rb_call.h +57 -0
  18. data/src/ruby/ext/grpc/rb_call_credentials.c +341 -0
  19. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  20. data/src/ruby/ext/grpc/rb_channel.c +846 -0
  21. data/src/ruby/ext/grpc/rb_channel.h +34 -0
  22. data/src/ruby/ext/grpc/rb_channel_args.c +155 -0
  23. data/src/ruby/ext/grpc/rb_channel_args.h +38 -0
  24. data/src/ruby/ext/grpc/rb_channel_credentials.c +286 -0
  25. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  26. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  27. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  28. data/src/ruby/ext/grpc/rb_compression_options.c +471 -0
  29. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  30. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  31. data/src/ruby/ext/grpc/rb_event_thread.c +145 -0
  32. data/src/ruby/ext/grpc/rb_event_thread.h +21 -0
  33. data/src/ruby/ext/grpc/rb_grpc.c +333 -0
  34. data/src/ruby/ext/grpc/rb_grpc.h +77 -0
  35. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +605 -0
  36. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +913 -0
  37. data/src/ruby/ext/grpc/rb_loader.c +57 -0
  38. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  39. data/src/ruby/ext/grpc/rb_server.c +385 -0
  40. data/src/ruby/ext/grpc/rb_server.h +32 -0
  41. data/src/ruby/ext/grpc/rb_server_credentials.c +259 -0
  42. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  43. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +218 -0
  44. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  45. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +170 -0
  46. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  47. data/src/ruby/lib/grpc/2.4/grpc_c.bundle +0 -0
  48. data/src/ruby/lib/grpc/2.5/grpc_c.bundle +0 -0
  49. data/src/ruby/lib/grpc/2.6/grpc_c.bundle +0 -0
  50. data/src/ruby/lib/grpc/2.7/grpc_c.bundle +0 -0
  51. data/src/ruby/lib/grpc/3.0/grpc_c.bundle +0 -0
  52. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  53. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  54. data/src/ruby/lib/grpc/errors.rb +277 -0
  55. data/src/ruby/lib/grpc/generic/active_call.rb +669 -0
  56. data/src/ruby/lib/grpc/generic/bidi_call.rb +233 -0
  57. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  58. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  59. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  60. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  61. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  62. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  63. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  64. data/src/ruby/lib/grpc/grpc.rb +24 -0
  65. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  66. data/src/ruby/lib/grpc/notifier.rb +45 -0
  67. data/src/ruby/lib/grpc/structs.rb +15 -0
  68. data/src/ruby/lib/grpc/version.rb +18 -0
  69. data/src/ruby/lib/grpc.rb +37 -0
  70. data/src/ruby/pb/README.md +42 -0
  71. data/src/ruby/pb/generate_proto_ruby.sh +51 -0
  72. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  73. data/src/ruby/pb/grpc/health/v1/health_pb.rb +31 -0
  74. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  75. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  76. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  77. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  78. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +17 -0
  79. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +145 -0
  80. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +16 -0
  81. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +152 -0
  82. data/src/ruby/pb/test/client.rb +769 -0
  83. data/src/ruby/pb/test/server.rb +252 -0
  84. data/src/ruby/pb/test/xds_client.rb +415 -0
  85. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  86. data/src/ruby/spec/call_spec.rb +180 -0
  87. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  88. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  89. data/src/ruby/spec/channel_spec.rb +245 -0
  90. data/src/ruby/spec/client_auth_spec.rb +152 -0
  91. data/src/ruby/spec/client_server_spec.rb +664 -0
  92. data/src/ruby/spec/compression_options_spec.rb +149 -0
  93. data/src/ruby/spec/debug_message_spec.rb +134 -0
  94. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  95. data/src/ruby/spec/errors_spec.rb +142 -0
  96. data/src/ruby/spec/generic/active_call_spec.rb +683 -0
  97. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  98. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -0
  99. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  100. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  101. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  102. data/src/ruby/spec/generic/rpc_server_spec.rb +748 -0
  103. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  104. data/src/ruby/spec/generic/service_spec.rb +263 -0
  105. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  106. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  107. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  108. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  109. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  110. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  112. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  113. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  114. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  115. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  116. data/src/ruby/spec/server_spec.rb +231 -0
  117. data/src/ruby/spec/spec_helper.rb +61 -0
  118. data/src/ruby/spec/support/helpers.rb +107 -0
  119. data/src/ruby/spec/support/services.rb +160 -0
  120. data/src/ruby/spec/testdata/README +1 -0
  121. data/src/ruby/spec/testdata/ca.pem +20 -0
  122. data/src/ruby/spec/testdata/client.key +28 -0
  123. data/src/ruby/spec/testdata/client.pem +20 -0
  124. data/src/ruby/spec/testdata/server1.key +28 -0
  125. data/src/ruby/spec/testdata/server1.pem +22 -0
  126. data/src/ruby/spec/time_consts_spec.rb +74 -0
  127. data/src/ruby/spec/user_agent_spec.rb +74 -0
  128. metadata +404 -0
@@ -0,0 +1,769 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright 2015 gRPC authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # client is a testing tool that accesses a gRPC interop testing server and runs
18
+ # a test on it.
19
+ #
20
+ # Helps validate interoperation b/w different gRPC implementations.
21
+ #
22
+ # Usage: $ path/to/client.rb --server_host=<hostname> \
23
+ # --server_port=<port> \
24
+ # --test_case=<testcase_name>
25
+
26
+ # These lines are required for the generated files to load grpc
27
+ this_dir = File.expand_path(File.dirname(__FILE__))
28
+ lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
29
+ pb_dir = File.dirname(this_dir)
30
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
31
+ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
32
+
33
+ require 'optparse'
34
+ require 'logger'
35
+
36
+ require_relative '../../lib/grpc'
37
+ require 'googleauth'
38
+ require 'google/protobuf'
39
+
40
+ require_relative '../src/proto/grpc/testing/empty_pb'
41
+ require_relative '../src/proto/grpc/testing/messages_pb'
42
+ require_relative '../src/proto/grpc/testing/test_services_pb'
43
+
44
+ AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
45
+
46
+ # RubyLogger defines a logger for gRPC based on the standard ruby logger.
47
+ module RubyLogger
48
+ def logger
49
+ LOGGER
50
+ end
51
+
52
+ LOGGER = Logger.new(STDOUT)
53
+ LOGGER.level = Logger::INFO
54
+ end
55
+
56
+ # GRPC is the general RPC module
57
+ module GRPC
58
+ # Inject the noop #logger if no module-level logger method has been injected.
59
+ extend RubyLogger
60
+ end
61
+
62
+ # AssertionError is use to indicate interop test failures.
63
+ class AssertionError < RuntimeError; end
64
+
65
+ # Fails with AssertionError if the block does evaluate to true
66
+ def assert(msg = 'unknown cause')
67
+ fail 'No assertion block provided' unless block_given?
68
+ fail AssertionError, msg unless yield
69
+ end
70
+
71
+ # loads the certificates used to access the test server securely.
72
+ def load_test_certs
73
+ this_dir = File.expand_path(File.dirname(__FILE__))
74
+ data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
75
+ files = ['ca.pem', 'server1.key', 'server1.pem']
76
+ files.map { |f| File.open(File.join(data_dir, f)).read }
77
+ end
78
+
79
+ # creates SSL Credentials from the test certificates.
80
+ def test_creds
81
+ certs = load_test_certs
82
+ GRPC::Core::ChannelCredentials.new(certs[0])
83
+ end
84
+
85
+ # creates SSL Credentials from the production certificates.
86
+ def prod_creds
87
+ GRPC::Core::ChannelCredentials.new()
88
+ end
89
+
90
+ # creates the SSL Credentials.
91
+ def ssl_creds(use_test_ca)
92
+ return test_creds if use_test_ca
93
+ prod_creds
94
+ end
95
+
96
+ # creates a test stub that accesses host:port securely.
97
+ def create_stub(opts)
98
+ address = "#{opts.server_host}:#{opts.server_port}"
99
+
100
+ # Provide channel args that request compression by default
101
+ # for compression interop tests
102
+ if ['client_compressed_unary',
103
+ 'client_compressed_streaming'].include?(opts.test_case)
104
+ compression_options =
105
+ GRPC::Core::CompressionOptions.new(default_algorithm: :gzip)
106
+ compression_channel_args = compression_options.to_channel_arg_hash
107
+ else
108
+ compression_channel_args = {}
109
+ end
110
+
111
+ if opts.secure
112
+ creds = ssl_creds(opts.use_test_ca)
113
+ stub_opts = {
114
+ channel_args: {}
115
+ }
116
+ unless opts.server_host_override.empty?
117
+ stub_opts[:channel_args].merge!({
118
+ GRPC::Core::Channel::SSL_TARGET => opts.server_host_override
119
+ })
120
+ end
121
+
122
+ # Add service account creds if specified
123
+ wants_creds = %w(all compute_engine_creds service_account_creds)
124
+ if wants_creds.include?(opts.test_case)
125
+ unless opts.oauth_scope.nil?
126
+ auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
127
+ call_creds = GRPC::Core::CallCredentials.new(auth_creds.updater_proc)
128
+ creds = creds.compose call_creds
129
+ end
130
+ end
131
+
132
+ if opts.test_case == 'oauth2_auth_token'
133
+ auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
134
+ kw = auth_creds.updater_proc.call({}) # gives as an auth token
135
+
136
+ # use a metadata update proc that just adds the auth token.
137
+ call_creds = GRPC::Core::CallCredentials.new(proc { |md| md.merge(kw) })
138
+ creds = creds.compose call_creds
139
+ end
140
+
141
+ if opts.test_case == 'jwt_token_creds' # don't use a scope
142
+ auth_creds = Google::Auth.get_application_default
143
+ call_creds = GRPC::Core::CallCredentials.new(auth_creds.updater_proc)
144
+ creds = creds.compose call_creds
145
+ end
146
+
147
+ GRPC.logger.info("... connecting securely to #{address}")
148
+ stub_opts[:channel_args].merge!(compression_channel_args)
149
+ if opts.test_case == "unimplemented_service"
150
+ Grpc::Testing::UnimplementedService::Stub.new(address, creds, **stub_opts)
151
+ else
152
+ Grpc::Testing::TestService::Stub.new(address, creds, **stub_opts)
153
+ end
154
+ else
155
+ GRPC.logger.info("... connecting insecurely to #{address}")
156
+ if opts.test_case == "unimplemented_service"
157
+ Grpc::Testing::UnimplementedService::Stub.new(
158
+ address,
159
+ :this_channel_is_insecure,
160
+ channel_args: compression_channel_args
161
+ )
162
+ else
163
+ Grpc::Testing::TestService::Stub.new(
164
+ address,
165
+ :this_channel_is_insecure,
166
+ channel_args: compression_channel_args
167
+ )
168
+ end
169
+ end
170
+ end
171
+
172
+ # produces a string of null chars (\0) of length l.
173
+ def nulls(l)
174
+ fail 'requires #{l} to be +ve' if l < 0
175
+ [].pack('x' * l).force_encoding('ascii-8bit')
176
+ end
177
+
178
+ # a PingPongPlayer implements the ping pong bidi test.
179
+ class PingPongPlayer
180
+ include Grpc::Testing
181
+ include Grpc::Testing::PayloadType
182
+ attr_accessor :queue
183
+ attr_accessor :canceller_op
184
+
185
+ # reqs is the enumerator over the requests
186
+ def initialize(msg_sizes)
187
+ @queue = Queue.new
188
+ @msg_sizes = msg_sizes
189
+ @canceller_op = nil # used to cancel after the first response
190
+ end
191
+
192
+ def each_item
193
+ return enum_for(:each_item) unless block_given?
194
+ req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short
195
+ count = 0
196
+ @msg_sizes.each do |m|
197
+ req_size, resp_size = m
198
+ req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
199
+ response_type: :COMPRESSABLE,
200
+ response_parameters: [p_cls.new(size: resp_size)])
201
+ yield req
202
+ resp = @queue.pop
203
+ assert('payload type is wrong') { :COMPRESSABLE == resp.payload.type }
204
+ assert("payload body #{count} has the wrong length") do
205
+ resp_size == resp.payload.body.length
206
+ end
207
+ p "OK: ping_pong #{count}"
208
+ count += 1
209
+ unless @canceller_op.nil?
210
+ canceller_op.cancel
211
+ break
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ class BlockingEnumerator
218
+ include Grpc::Testing
219
+ include Grpc::Testing::PayloadType
220
+
221
+ def initialize(req_size, sleep_time)
222
+ @req_size = req_size
223
+ @sleep_time = sleep_time
224
+ end
225
+
226
+ def each_item
227
+ return enum_for(:each_item) unless block_given?
228
+ req_cls = StreamingOutputCallRequest
229
+ req = req_cls.new(payload: Payload.new(body: nulls(@req_size)))
230
+ yield req
231
+ # Sleep until after the deadline should have passed
232
+ sleep(@sleep_time)
233
+ end
234
+ end
235
+
236
+ # Intended to be used to wrap a call_op, and to adjust
237
+ # the write flag of the call_op in between messages yielded to it.
238
+ class WriteFlagSettingStreamingInputEnumerable
239
+ attr_accessor :call_op
240
+
241
+ def initialize(requests_and_write_flags)
242
+ @requests_and_write_flags = requests_and_write_flags
243
+ end
244
+
245
+ def each
246
+ @requests_and_write_flags.each do |request_and_flag|
247
+ @call_op.write_flag = request_and_flag[:write_flag]
248
+ yield request_and_flag[:request]
249
+ end
250
+ end
251
+ end
252
+
253
+ # defines methods corresponding to each interop test case.
254
+ class NamedTests
255
+ include Grpc::Testing
256
+ include Grpc::Testing::PayloadType
257
+ include GRPC::Core::MetadataKeys
258
+
259
+ def initialize(stub, args)
260
+ @stub = stub
261
+ @args = args
262
+ end
263
+
264
+ def empty_unary
265
+ resp = @stub.empty_call(Empty.new)
266
+ assert('empty_unary: invalid response') { resp.is_a?(Empty) }
267
+ end
268
+
269
+ def large_unary
270
+ perform_large_unary
271
+ end
272
+
273
+ def client_compressed_unary
274
+ # first request used also for the probe
275
+ req_size, wanted_response_size = 271_828, 314_159
276
+ expect_compressed = BoolValue.new(value: true)
277
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
278
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
279
+ response_size: wanted_response_size,
280
+ payload: payload,
281
+ expect_compressed: expect_compressed)
282
+
283
+ # send a probe to see if CompressedResponse is supported on the server
284
+ send_probe_for_compressed_request_support do
285
+ request_uncompressed_args = {
286
+ COMPRESSION_REQUEST_ALGORITHM => 'identity'
287
+ }
288
+ @stub.unary_call(req, metadata: request_uncompressed_args)
289
+ end
290
+
291
+ # make a call with a compressed message
292
+ resp = @stub.unary_call(req)
293
+ assert('Expected second unary call with compression to work') do
294
+ resp.payload.body.length == wanted_response_size
295
+ end
296
+
297
+ # make a call with an uncompressed message
298
+ stub_options = {
299
+ COMPRESSION_REQUEST_ALGORITHM => 'identity'
300
+ }
301
+
302
+ req = SimpleRequest.new(
303
+ response_type: :COMPRESSABLE,
304
+ response_size: wanted_response_size,
305
+ payload: payload,
306
+ expect_compressed: BoolValue.new(value: false)
307
+ )
308
+
309
+ resp = @stub.unary_call(req, metadata: stub_options)
310
+ assert('Expected second unary call with compression to work') do
311
+ resp.payload.body.length == wanted_response_size
312
+ end
313
+ end
314
+
315
+ def service_account_creds
316
+ # ignore this test if the oauth options are not set
317
+ if @args.oauth_scope.nil?
318
+ p 'NOT RUN: service_account_creds; no service_account settings'
319
+ return
320
+ end
321
+ json_key = File.read(ENV[AUTH_ENV])
322
+ wanted_email = MultiJson.load(json_key)['client_email']
323
+ resp = perform_large_unary(fill_username: true,
324
+ fill_oauth_scope: true)
325
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
326
+ assert("#{__callee__}: bad oauth scope") do
327
+ @args.oauth_scope.include?(resp.oauth_scope)
328
+ end
329
+ end
330
+
331
+ def jwt_token_creds
332
+ json_key = File.read(ENV[AUTH_ENV])
333
+ wanted_email = MultiJson.load(json_key)['client_email']
334
+ resp = perform_large_unary(fill_username: true)
335
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
336
+ end
337
+
338
+ def compute_engine_creds
339
+ resp = perform_large_unary(fill_username: true,
340
+ fill_oauth_scope: true)
341
+ assert("#{__callee__}: bad username") do
342
+ @args.default_service_account == resp.username
343
+ end
344
+ end
345
+
346
+ def oauth2_auth_token
347
+ resp = perform_large_unary(fill_username: true,
348
+ fill_oauth_scope: true)
349
+ json_key = File.read(ENV[AUTH_ENV])
350
+ wanted_email = MultiJson.load(json_key)['client_email']
351
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
352
+ assert("#{__callee__}: bad oauth scope") do
353
+ @args.oauth_scope.include?(resp.oauth_scope)
354
+ end
355
+ end
356
+
357
+ def per_rpc_creds
358
+ auth_creds = Google::Auth.get_application_default(@args.oauth_scope)
359
+ update_metadata = proc do |md|
360
+ kw = auth_creds.updater_proc.call({})
361
+ end
362
+
363
+ call_creds = GRPC::Core::CallCredentials.new(update_metadata)
364
+
365
+ resp = perform_large_unary(fill_username: true,
366
+ fill_oauth_scope: true,
367
+ credentials: call_creds)
368
+ json_key = File.read(ENV[AUTH_ENV])
369
+ wanted_email = MultiJson.load(json_key)['client_email']
370
+ assert("#{__callee__}: bad username") { wanted_email == resp.username }
371
+ assert("#{__callee__}: bad oauth scope") do
372
+ @args.oauth_scope.include?(resp.oauth_scope)
373
+ end
374
+ end
375
+
376
+ def client_streaming
377
+ msg_sizes = [27_182, 8, 1828, 45_904]
378
+ wanted_aggregate_size = 74_922
379
+ reqs = msg_sizes.map do |x|
380
+ req = Payload.new(body: nulls(x))
381
+ StreamingInputCallRequest.new(payload: req)
382
+ end
383
+ resp = @stub.streaming_input_call(reqs)
384
+ assert("#{__callee__}: aggregate payload size is incorrect") do
385
+ wanted_aggregate_size == resp.aggregated_payload_size
386
+ end
387
+ end
388
+
389
+ def client_compressed_streaming
390
+ # first request used also by the probe
391
+ first_request = StreamingInputCallRequest.new(
392
+ payload: Payload.new(type: :COMPRESSABLE, body: nulls(27_182)),
393
+ expect_compressed: BoolValue.new(value: true)
394
+ )
395
+
396
+ # send a probe to see if CompressedResponse is supported on the server
397
+ send_probe_for_compressed_request_support do
398
+ request_uncompressed_args = {
399
+ COMPRESSION_REQUEST_ALGORITHM => 'identity'
400
+ }
401
+ @stub.streaming_input_call([first_request],
402
+ metadata: request_uncompressed_args)
403
+ end
404
+
405
+ second_request = StreamingInputCallRequest.new(
406
+ payload: Payload.new(type: :COMPRESSABLE, body: nulls(45_904)),
407
+ expect_compressed: BoolValue.new(value: false)
408
+ )
409
+
410
+ # Create the requests messages and the corresponding write flags
411
+ # for each message
412
+ requests = WriteFlagSettingStreamingInputEnumerable.new([
413
+ { request: first_request,
414
+ write_flag: 0 },
415
+ { request: second_request,
416
+ write_flag: GRPC::Core::WriteFlags::NO_COMPRESS }
417
+ ])
418
+
419
+ # Create the call_op, pass it to the requests enumerable, and
420
+ # run the call
421
+ call_op = @stub.streaming_input_call(requests,
422
+ return_op: true)
423
+ requests.call_op = call_op
424
+ resp = call_op.execute
425
+
426
+ wanted_aggregate_size = 73_086
427
+
428
+ assert("#{__callee__}: aggregate payload size is incorrect") do
429
+ wanted_aggregate_size == resp.aggregated_payload_size
430
+ end
431
+ end
432
+
433
+ def server_streaming
434
+ msg_sizes = [31_415, 9, 2653, 58_979]
435
+ response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
436
+ req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
437
+ response_parameters: response_spec)
438
+ resps = @stub.streaming_output_call(req)
439
+ resps.each_with_index do |r, i|
440
+ assert("#{__callee__}: too many responses") { i < msg_sizes.length }
441
+ assert("#{__callee__}: payload body #{i} has the wrong length") do
442
+ msg_sizes[i] == r.payload.body.length
443
+ end
444
+ assert("#{__callee__}: payload type is wrong") do
445
+ :COMPRESSABLE == r.payload.type
446
+ end
447
+ end
448
+ end
449
+
450
+ def ping_pong
451
+ msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
452
+ ppp = PingPongPlayer.new(msg_sizes)
453
+ resps = @stub.full_duplex_call(ppp.each_item)
454
+ resps.each { |r| ppp.queue.push(r) }
455
+ end
456
+
457
+ def timeout_on_sleeping_server
458
+ enum = BlockingEnumerator.new(27_182, 2)
459
+ deadline = GRPC::Core::TimeConsts::from_relative_time(1)
460
+ resps = @stub.full_duplex_call(enum.each_item, deadline: deadline)
461
+ resps.each { } # wait to receive each request (or timeout)
462
+ fail 'Should have raised GRPC::DeadlineExceeded'
463
+ rescue GRPC::DeadlineExceeded
464
+ end
465
+
466
+ def empty_stream
467
+ ppp = PingPongPlayer.new([])
468
+ resps = @stub.full_duplex_call(ppp.each_item)
469
+ count = 0
470
+ resps.each do |r|
471
+ ppp.queue.push(r)
472
+ count += 1
473
+ end
474
+ assert("#{__callee__}: too many responses expected 0") do
475
+ count == 0
476
+ end
477
+ end
478
+
479
+ def cancel_after_begin
480
+ msg_sizes = [27_182, 8, 1828, 45_904]
481
+ reqs = msg_sizes.map do |x|
482
+ req = Payload.new(body: nulls(x))
483
+ StreamingInputCallRequest.new(payload: req)
484
+ end
485
+ op = @stub.streaming_input_call(reqs, return_op: true)
486
+ op.cancel
487
+ op.execute
488
+ fail 'Should have raised GRPC:Cancelled'
489
+ rescue GRPC::Cancelled
490
+ assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled? }
491
+ end
492
+
493
+ def cancel_after_first_response
494
+ msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
495
+ ppp = PingPongPlayer.new(msg_sizes)
496
+ op = @stub.full_duplex_call(ppp.each_item, return_op: true)
497
+ ppp.canceller_op = op # causes ppp to cancel after the 1st message
498
+ op.execute.each { |r| ppp.queue.push(r) }
499
+ fail 'Should have raised GRPC:Cancelled'
500
+ rescue GRPC::Cancelled
501
+ assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled? }
502
+ op.wait
503
+ end
504
+
505
+ def unimplemented_method
506
+ begin
507
+ resp = @stub.unimplemented_call(Empty.new)
508
+ rescue GRPC::Unimplemented => e
509
+ return
510
+ rescue Exception => e
511
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
512
+ end
513
+ fail AssertionError, "GRPC::Unimplemented should have been raised. Was not."
514
+ end
515
+
516
+ def unimplemented_service
517
+ begin
518
+ resp = @stub.unimplemented_call(Empty.new)
519
+ rescue GRPC::Unimplemented => e
520
+ return
521
+ rescue Exception => e
522
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
523
+ end
524
+ fail AssertionError, "GRPC::Unimplemented should have been raised. Was not."
525
+ end
526
+
527
+ def status_code_and_message
528
+
529
+ # Function wide constants.
530
+ message = "test status method"
531
+ code = GRPC::Core::StatusCodes::UNKNOWN
532
+
533
+ # Testing with UnaryCall.
534
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(1))
535
+ echo_status = EchoStatus.new(code: code, message: message)
536
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
537
+ response_size: 1,
538
+ payload: payload,
539
+ response_status: echo_status)
540
+ seen_correct_exception = false
541
+ begin
542
+ resp = @stub.unary_call(req)
543
+ rescue GRPC::Unknown => e
544
+ if e.details != message
545
+ fail AssertionError,
546
+ "Expected message #{message}. Received: #{e.details}"
547
+ end
548
+ seen_correct_exception = true
549
+ rescue Exception => e
550
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
551
+ end
552
+
553
+ if not seen_correct_exception
554
+ fail AssertionError, "Did not see expected status from UnaryCall"
555
+ end
556
+
557
+ # testing with FullDuplex
558
+ req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters
559
+ duplex_req = req_cls.new(payload: Payload.new(body: nulls(1)),
560
+ response_type: :COMPRESSABLE,
561
+ response_parameters: [p_cls.new(size: 1)],
562
+ response_status: echo_status)
563
+ seen_correct_exception = false
564
+ begin
565
+ resp = @stub.full_duplex_call([duplex_req])
566
+ resp.each { |r| }
567
+ rescue GRPC::Unknown => e
568
+ if e.details != message
569
+ fail AssertionError,
570
+ "Expected message #{message}. Received: #{e.details}"
571
+ end
572
+ seen_correct_exception = true
573
+ rescue Exception => e
574
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
575
+ end
576
+
577
+ if not seen_correct_exception
578
+ fail AssertionError, "Did not see expected status from FullDuplexCall"
579
+ end
580
+
581
+ end
582
+
583
+
584
+ def custom_metadata
585
+
586
+ # Function wide constants
587
+ req_size, wanted_response_size = 271_828, 314_159
588
+ initial_metadata_key = "x-grpc-test-echo-initial"
589
+ initial_metadata_value = "test_initial_metadata_value"
590
+ trailing_metadata_key = "x-grpc-test-echo-trailing-bin"
591
+ trailing_metadata_value = "\x0a\x0b\x0a\x0b\x0a\x0b"
592
+
593
+ metadata = {
594
+ initial_metadata_key => initial_metadata_value,
595
+ trailing_metadata_key => trailing_metadata_value
596
+ }
597
+
598
+ # Testing with UnaryCall
599
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
600
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
601
+ response_size: wanted_response_size,
602
+ payload: payload)
603
+
604
+ op = @stub.unary_call(req, metadata: metadata, return_op: true)
605
+ op.execute
606
+ if not op.metadata.has_key?(initial_metadata_key)
607
+ fail AssertionError, "Expected initial metadata. None received"
608
+ elsif op.metadata[initial_metadata_key] != metadata[initial_metadata_key]
609
+ fail AssertionError,
610
+ "Expected initial metadata: #{metadata[initial_metadata_key]}. "\
611
+ "Received: #{op.metadata[initial_metadata_key]}"
612
+ end
613
+ if not op.trailing_metadata.has_key?(trailing_metadata_key)
614
+ fail AssertionError, "Expected trailing metadata. None received"
615
+ elsif op.trailing_metadata[trailing_metadata_key] !=
616
+ metadata[trailing_metadata_key]
617
+ fail AssertionError,
618
+ "Expected trailing metadata: #{metadata[trailing_metadata_key]}. "\
619
+ "Received: #{op.trailing_metadata[trailing_metadata_key]}"
620
+ end
621
+
622
+ # Testing with FullDuplex
623
+ req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters
624
+ duplex_req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
625
+ response_type: :COMPRESSABLE,
626
+ response_parameters: [p_cls.new(size: wanted_response_size)])
627
+
628
+ duplex_op = @stub.full_duplex_call([duplex_req], metadata: metadata,
629
+ return_op: true)
630
+ resp = duplex_op.execute
631
+ resp.each { |r| } # ensures that the server sends trailing data
632
+ duplex_op.wait
633
+ if not duplex_op.metadata.has_key?(initial_metadata_key)
634
+ fail AssertionError, "Expected initial metadata. None received"
635
+ elsif duplex_op.metadata[initial_metadata_key] !=
636
+ metadata[initial_metadata_key]
637
+ fail AssertionError,
638
+ "Expected initial metadata: #{metadata[initial_metadata_key]}. "\
639
+ "Received: #{duplex_op.metadata[initial_metadata_key]}"
640
+ end
641
+ if not duplex_op.trailing_metadata[trailing_metadata_key]
642
+ fail AssertionError, "Expected trailing metadata. None received"
643
+ elsif duplex_op.trailing_metadata[trailing_metadata_key] !=
644
+ metadata[trailing_metadata_key]
645
+ fail AssertionError,
646
+ "Expected trailing metadata: #{metadata[trailing_metadata_key]}. "\
647
+ "Received: #{duplex_op.trailing_metadata[trailing_metadata_key]}"
648
+ end
649
+
650
+ end
651
+
652
+ def all
653
+ all_methods = NamedTests.instance_methods(false).map(&:to_s)
654
+ all_methods.each do |m|
655
+ next if m == 'all' || m.start_with?('assert')
656
+ p "TESTCASE: #{m}"
657
+ method(m).call
658
+ end
659
+ end
660
+
661
+ private
662
+
663
+ def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw)
664
+ req_size, wanted_response_size = 271_828, 314_159
665
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
666
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
667
+ response_size: wanted_response_size,
668
+ payload: payload)
669
+ req.fill_username = fill_username
670
+ req.fill_oauth_scope = fill_oauth_scope
671
+ resp = @stub.unary_call(req, **kw)
672
+ assert('payload type is wrong') do
673
+ :COMPRESSABLE == resp.payload.type
674
+ end
675
+ assert('payload body has the wrong length') do
676
+ wanted_response_size == resp.payload.body.length
677
+ end
678
+ assert('payload body is invalid') do
679
+ nulls(wanted_response_size) == resp.payload.body
680
+ end
681
+ resp
682
+ end
683
+
684
+ # Send probing message for compressed request on the server, to see
685
+ # if it's implemented.
686
+ def send_probe_for_compressed_request_support(&send_probe)
687
+ bad_status_occurred = false
688
+
689
+ begin
690
+ send_probe.call
691
+ rescue GRPC::BadStatus => e
692
+ if e.code == GRPC::Core::StatusCodes::INVALID_ARGUMENT
693
+ bad_status_occurred = true
694
+ else
695
+ fail AssertionError, "Bad status received but code is #{e.code}"
696
+ end
697
+ rescue Exception => e
698
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
699
+ end
700
+
701
+ assert('CompressedRequest probe failed') do
702
+ bad_status_occurred
703
+ end
704
+ end
705
+
706
+ end
707
+
708
+ # Args is used to hold the command line info.
709
+ Args = Struct.new(:default_service_account, :server_host, :server_host_override,
710
+ :oauth_scope, :server_port, :secure, :test_case,
711
+ :use_test_ca)
712
+
713
+ # validates the command line options, returning them as a Hash.
714
+ def parse_args
715
+ args = Args.new
716
+ args.server_host_override = ''
717
+ OptionParser.new do |opts|
718
+ opts.on('--oauth_scope scope',
719
+ 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
720
+ opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
721
+ args['server_host'] = v
722
+ end
723
+ opts.on('--default_service_account email_address',
724
+ 'email address of the default service account') do |v|
725
+ args['default_service_account'] = v
726
+ end
727
+ opts.on('--server_host_override HOST_OVERRIDE',
728
+ 'override host via a HTTP header') do |v|
729
+ args['server_host_override'] = v
730
+ end
731
+ opts.on('--server_port SERVER_PORT', 'server port') do |v|
732
+ args['server_port'] = v
733
+ end
734
+ # instance_methods(false) gives only the methods defined in that class
735
+ test_cases = NamedTests.instance_methods(false).map(&:to_s)
736
+ test_case_list = test_cases.join(',')
737
+ opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
738
+ " (#{test_case_list})") { |v| args['test_case'] = v }
739
+ opts.on('--use_tls USE_TLS', ['false', 'true'],
740
+ 'require a secure connection?') do |v|
741
+ args['secure'] = v == 'true'
742
+ end
743
+ opts.on('--use_test_ca USE_TEST_CA', ['false', 'true'],
744
+ 'if secure, use the test certificate?') do |v|
745
+ args['use_test_ca'] = v == 'true'
746
+ end
747
+ end.parse!
748
+ _check_args(args)
749
+ end
750
+
751
+ def _check_args(args)
752
+ %w(server_host server_port test_case).each do |a|
753
+ if args[a].nil?
754
+ fail(OptionParser::MissingArgument, "please specify --#{a}")
755
+ end
756
+ end
757
+ args
758
+ end
759
+
760
+ def main
761
+ opts = parse_args
762
+ stub = create_stub(opts)
763
+ NamedTests.new(stub, opts).method(opts['test_case']).call
764
+ p "OK: #{opts['test_case']}"
765
+ end
766
+
767
+ if __FILE__ == $0
768
+ main
769
+ end