grpc 1.60.0.pre1-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) 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-msvcrt.ruby +0 -0
  5. data/grpc_c.64-ucrt.ruby +0 -0
  6. data/src/ruby/bin/math_client.rb +140 -0
  7. data/src/ruby/bin/math_pb.rb +40 -0
  8. data/src/ruby/bin/math_server.rb +191 -0
  9. data/src/ruby/bin/math_services_pb.rb +51 -0
  10. data/src/ruby/bin/noproto_client.rb +93 -0
  11. data/src/ruby/bin/noproto_server.rb +97 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
  13. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
  14. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
  15. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
  16. data/src/ruby/ext/grpc/ext-export.clang +1 -0
  17. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  18. data/src/ruby/ext/grpc/extconf.rb +270 -0
  19. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  20. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  21. data/src/ruby/ext/grpc/rb_call.c +1075 -0
  22. data/src/ruby/ext/grpc/rb_call.h +57 -0
  23. data/src/ruby/ext/grpc/rb_call_credentials.c +340 -0
  24. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  25. data/src/ruby/ext/grpc/rb_channel.c +875 -0
  26. data/src/ruby/ext/grpc/rb_channel.h +35 -0
  27. data/src/ruby/ext/grpc/rb_channel_args.c +172 -0
  28. data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
  29. data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
  30. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  31. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  32. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  33. data/src/ruby/ext/grpc/rb_compression_options.c +470 -0
  34. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  35. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  36. data/src/ruby/ext/grpc/rb_event_thread.c +161 -0
  37. data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
  38. data/src/ruby/ext/grpc/rb_grpc.c +496 -0
  39. data/src/ruby/ext/grpc/rb_grpc.h +83 -0
  40. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +603 -0
  41. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +910 -0
  42. data/src/ruby/ext/grpc/rb_loader.c +61 -0
  43. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  44. data/src/ruby/ext/grpc/rb_server.c +405 -0
  45. data/src/ruby/ext/grpc/rb_server.h +32 -0
  46. data/src/ruby/ext/grpc/rb_server_credentials.c +258 -0
  47. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  48. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
  49. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  50. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +169 -0
  51. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  52. data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
  53. data/src/ruby/lib/grpc/3.0/grpc_c.so +0 -0
  54. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  55. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  56. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  57. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  58. data/src/ruby/lib/grpc/errors.rb +277 -0
  59. data/src/ruby/lib/grpc/generic/active_call.rb +670 -0
  60. data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
  61. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  62. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  63. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  64. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  65. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  66. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  67. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  68. data/src/ruby/lib/grpc/grpc.rb +24 -0
  69. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  70. data/src/ruby/lib/grpc/notifier.rb +45 -0
  71. data/src/ruby/lib/grpc/structs.rb +15 -0
  72. data/src/ruby/lib/grpc/version.rb +18 -0
  73. data/src/ruby/lib/grpc.rb +37 -0
  74. data/src/ruby/pb/README.md +42 -0
  75. data/src/ruby/pb/generate_proto_ruby.sh +46 -0
  76. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  77. data/src/ruby/pb/grpc/health/v1/health_pb.rb +42 -0
  78. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  79. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  80. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  81. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  82. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +38 -0
  83. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +71 -0
  84. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +40 -0
  85. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
  86. data/src/ruby/pb/test/client.rb +785 -0
  87. data/src/ruby/pb/test/server.rb +252 -0
  88. data/src/ruby/pb/test/xds_client.rb +415 -0
  89. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  90. data/src/ruby/spec/call_spec.rb +180 -0
  91. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  92. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  93. data/src/ruby/spec/channel_spec.rb +207 -0
  94. data/src/ruby/spec/client_auth_spec.rb +152 -0
  95. data/src/ruby/spec/client_server_spec.rb +676 -0
  96. data/src/ruby/spec/compression_options_spec.rb +149 -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 +692 -0
  101. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  102. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -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 +748 -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/pb/codegen/grpc/testing/package_options.proto +28 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  112. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  113. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  114. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  115. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  116. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  117. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  118. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  119. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  120. data/src/ruby/spec/server_spec.rb +231 -0
  121. data/src/ruby/spec/spec_helper.rb +61 -0
  122. data/src/ruby/spec/support/helpers.rb +107 -0
  123. data/src/ruby/spec/support/services.rb +160 -0
  124. data/src/ruby/spec/testdata/README +1 -0
  125. data/src/ruby/spec/testdata/ca.pem +20 -0
  126. data/src/ruby/spec/testdata/client.key +28 -0
  127. data/src/ruby/spec/testdata/client.pem +20 -0
  128. data/src/ruby/spec/testdata/server1.key +28 -0
  129. data/src/ruby/spec/testdata/server1.pem +22 -0
  130. data/src/ruby/spec/time_consts_spec.rb +74 -0
  131. data/src/ruby/spec/user_agent_spec.rb +74 -0
  132. metadata +405 -0
@@ -0,0 +1,785 @@
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 special_status_message
653
+ code = GRPC::Core::StatusCodes::UNKNOWN
654
+ message = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n"
655
+ req = SimpleRequest.new(
656
+ response_status: EchoStatus.new(code: code, message: message))
657
+ begin
658
+ resp = @stub.unary_call(req)
659
+ fail AssertionError, "GRPC::Unknown should have been raised."
660
+ rescue GRPC::Unknown => e
661
+ if e.details.force_encoding("UTF-8") != message
662
+ fail AssertionError,
663
+ "Expected message #{message}. Received: #{e.details}"
664
+ end
665
+ end
666
+ end
667
+
668
+ def all
669
+ all_methods = NamedTests.instance_methods(false).map(&:to_s)
670
+ all_methods.each do |m|
671
+ next if m == 'all' || m.start_with?('assert')
672
+ p "TESTCASE: #{m}"
673
+ method(m).call
674
+ end
675
+ end
676
+
677
+ private
678
+
679
+ def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw)
680
+ req_size, wanted_response_size = 271_828, 314_159
681
+ payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
682
+ req = SimpleRequest.new(response_type: :COMPRESSABLE,
683
+ response_size: wanted_response_size,
684
+ payload: payload)
685
+ req.fill_username = fill_username
686
+ req.fill_oauth_scope = fill_oauth_scope
687
+ resp = @stub.unary_call(req, **kw)
688
+ assert('payload type is wrong') do
689
+ :COMPRESSABLE == resp.payload.type
690
+ end
691
+ assert('payload body has the wrong length') do
692
+ wanted_response_size == resp.payload.body.length
693
+ end
694
+ assert('payload body is invalid') do
695
+ nulls(wanted_response_size) == resp.payload.body
696
+ end
697
+ resp
698
+ end
699
+
700
+ # Send probing message for compressed request on the server, to see
701
+ # if it's implemented.
702
+ def send_probe_for_compressed_request_support(&send_probe)
703
+ bad_status_occurred = false
704
+
705
+ begin
706
+ send_probe.call
707
+ rescue GRPC::BadStatus => e
708
+ if e.code == GRPC::Core::StatusCodes::INVALID_ARGUMENT
709
+ bad_status_occurred = true
710
+ else
711
+ fail AssertionError, "Bad status received but code is #{e.code}"
712
+ end
713
+ rescue Exception => e
714
+ fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
715
+ end
716
+
717
+ assert('CompressedRequest probe failed') do
718
+ bad_status_occurred
719
+ end
720
+ end
721
+
722
+ end
723
+
724
+ # Args is used to hold the command line info.
725
+ Args = Struct.new(:default_service_account, :server_host, :server_host_override,
726
+ :oauth_scope, :server_port, :secure, :test_case,
727
+ :use_test_ca)
728
+
729
+ # validates the command line options, returning them as a Hash.
730
+ def parse_args
731
+ args = Args.new
732
+ args.server_host_override = ''
733
+ OptionParser.new do |opts|
734
+ opts.on('--oauth_scope scope',
735
+ 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
736
+ opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
737
+ args['server_host'] = v
738
+ end
739
+ opts.on('--default_service_account email_address',
740
+ 'email address of the default service account') do |v|
741
+ args['default_service_account'] = v
742
+ end
743
+ opts.on('--server_host_override HOST_OVERRIDE',
744
+ 'override host via a HTTP header') do |v|
745
+ args['server_host_override'] = v
746
+ end
747
+ opts.on('--server_port SERVER_PORT', 'server port') do |v|
748
+ args['server_port'] = v
749
+ end
750
+ # instance_methods(false) gives only the methods defined in that class
751
+ test_cases = NamedTests.instance_methods(false).map(&:to_s)
752
+ test_case_list = test_cases.join(',')
753
+ opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
754
+ " (#{test_case_list})") { |v| args['test_case'] = v }
755
+ opts.on('--use_tls USE_TLS', ['false', 'true'],
756
+ 'require a secure connection?') do |v|
757
+ args['secure'] = v == 'true'
758
+ end
759
+ opts.on('--use_test_ca USE_TEST_CA', ['false', 'true'],
760
+ 'if secure, use the test certificate?') do |v|
761
+ args['use_test_ca'] = v == 'true'
762
+ end
763
+ end.parse!
764
+ _check_args(args)
765
+ end
766
+
767
+ def _check_args(args)
768
+ %w(server_host server_port test_case).each do |a|
769
+ if args[a].nil?
770
+ fail(OptionParser::MissingArgument, "please specify --#{a}")
771
+ end
772
+ end
773
+ args
774
+ end
775
+
776
+ def main
777
+ opts = parse_args
778
+ stub = create_stub(opts)
779
+ NamedTests.new(stub, opts).method(opts['test_case']).call
780
+ p "OK: #{opts['test_case']}"
781
+ end
782
+
783
+ if __FILE__ == $0
784
+ main
785
+ end