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,252 @@
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
+ # interop_server is a Testing app that runs a gRPC interop testing server.
18
+ #
19
+ # It helps validate interoperation b/w gRPC in different environments
20
+ #
21
+ # Helps validate interoperation b/w different gRPC implementations.
22
+ #
23
+ # Usage: $ path/to/interop_server.rb --port
24
+
25
+ this_dir = File.expand_path(File.dirname(__FILE__))
26
+ lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
27
+ pb_dir = File.dirname(this_dir)
28
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
29
+ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
30
+ $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
31
+
32
+ require 'forwardable'
33
+ require 'logger'
34
+ require 'optparse'
35
+
36
+ require 'grpc'
37
+
38
+ require_relative '../src/proto/grpc/testing/empty_pb'
39
+ require_relative '../src/proto/grpc/testing/messages_pb'
40
+ require_relative '../src/proto/grpc/testing/test_services_pb'
41
+
42
+ # DebugIsTruncated extends the default Logger to truncate debug messages
43
+ class DebugIsTruncated < Logger
44
+ def debug(s)
45
+ super(truncate(s, 1024))
46
+ end
47
+
48
+ # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
49
+ #
50
+ # 'Once upon a time in a world far far away'.truncate(27)
51
+ # # => "Once upon a time in a wo..."
52
+ #
53
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
54
+ #
55
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
56
+ # # => "Once upon a time in a..."
57
+ #
58
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
59
+ # # => "Once upon a time in a..."
60
+ #
61
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
62
+ # for a total length not exceeding <tt>length</tt>:
63
+ #
64
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
65
+ # # => "And they f... (continued)"
66
+ def truncate(s, truncate_at, options = {})
67
+ return s unless s.length > truncate_at
68
+ omission = options[:omission] || '...'
69
+ with_extra_room = truncate_at - omission.length
70
+ stop = \
71
+ if options[:separator]
72
+ rindex(options[:separator], with_extra_room) || with_extra_room
73
+ else
74
+ with_extra_room
75
+ end
76
+ "#{s[0, stop]}#{omission}"
77
+ end
78
+ end
79
+
80
+ # RubyLogger defines a logger for gRPC based on the standard ruby logger.
81
+ module RubyLogger
82
+ def logger
83
+ LOGGER
84
+ end
85
+
86
+ LOGGER = DebugIsTruncated.new(STDOUT)
87
+ LOGGER.level = Logger::WARN
88
+ end
89
+
90
+ # GRPC is the general RPC module
91
+ module GRPC
92
+ # Inject the noop #logger if no module-level logger method has been injected.
93
+ extend RubyLogger
94
+ end
95
+
96
+ # loads the certificates by the test server.
97
+ def load_test_certs
98
+ this_dir = File.expand_path(File.dirname(__FILE__))
99
+ data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
100
+ files = ['ca.pem', 'server1.key', 'server1.pem']
101
+ files.map { |f| File.open(File.join(data_dir, f)).read }
102
+ end
103
+
104
+ # creates a ServerCredentials from the test certificates.
105
+ def test_server_creds
106
+ certs = load_test_certs
107
+ GRPC::Core::ServerCredentials.new(
108
+ nil, [{private_key: certs[1], cert_chain: certs[2]}], false)
109
+ end
110
+
111
+ # produces a string of null chars (\0) of length l.
112
+ def nulls(l)
113
+ fail 'requires #{l} to be +ve' if l < 0
114
+ [].pack('x' * l).force_encoding('ascii-8bit')
115
+ end
116
+
117
+ def maybe_echo_metadata(_call)
118
+
119
+ # these are consistent for all interop tests
120
+ initial_metadata_key = "x-grpc-test-echo-initial"
121
+ trailing_metadata_key = "x-grpc-test-echo-trailing-bin"
122
+
123
+ if _call.metadata.has_key?(initial_metadata_key)
124
+ _call.metadata_to_send[initial_metadata_key] = _call.metadata[initial_metadata_key]
125
+ end
126
+ if _call.metadata.has_key?(trailing_metadata_key)
127
+ _call.output_metadata[trailing_metadata_key] = _call.metadata[trailing_metadata_key]
128
+ end
129
+ end
130
+
131
+ def maybe_echo_status_and_message(req)
132
+ unless req.response_status.nil?
133
+ fail GRPC::BadStatus.new_status_exception(
134
+ req.response_status.code, req.response_status.message)
135
+ end
136
+ end
137
+
138
+ # A FullDuplexEnumerator passes requests to a block and yields generated responses
139
+ class FullDuplexEnumerator
140
+ include Grpc::Testing
141
+ include Grpc::Testing::PayloadType
142
+
143
+ def initialize(requests)
144
+ @requests = requests
145
+ end
146
+ def each_item
147
+ return enum_for(:each_item) unless block_given?
148
+ GRPC.logger.info('interop-server: started receiving')
149
+ begin
150
+ cls = StreamingOutputCallResponse
151
+ @requests.each do |req|
152
+ maybe_echo_status_and_message(req)
153
+ req.response_parameters.each do |params|
154
+ resp_size = params.size
155
+ GRPC.logger.info("read a req, response size is #{resp_size}")
156
+ yield cls.new(payload: Payload.new(type: req.response_type,
157
+ body: nulls(resp_size)))
158
+ end
159
+ end
160
+ GRPC.logger.info('interop-server: finished receiving')
161
+ rescue StandardError => e
162
+ GRPC.logger.info('interop-server: failed')
163
+ GRPC.logger.warn(e)
164
+ fail e
165
+ end
166
+ end
167
+ end
168
+
169
+ # A runnable implementation of the schema-specified testing service, with each
170
+ # service method implemented as required by the interop testing spec.
171
+ class TestTarget < Grpc::Testing::TestService::Service
172
+ include Grpc::Testing
173
+ include Grpc::Testing::PayloadType
174
+
175
+ def empty_call(_empty, _call)
176
+ Empty.new
177
+ end
178
+
179
+ def unary_call(simple_req, _call)
180
+ maybe_echo_metadata(_call)
181
+ maybe_echo_status_and_message(simple_req)
182
+ req_size = simple_req.response_size
183
+ SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
184
+ body: nulls(req_size)))
185
+ end
186
+
187
+ def streaming_input_call(call)
188
+ sizes = call.each_remote_read.map { |x| x.payload.body.length }
189
+ sum = sizes.inject(0) { |s, x| s + x }
190
+ StreamingInputCallResponse.new(aggregated_payload_size: sum)
191
+ end
192
+
193
+ def streaming_output_call(req, _call)
194
+ cls = StreamingOutputCallResponse
195
+ req.response_parameters.map do |p|
196
+ cls.new(payload: Payload.new(type: req.response_type,
197
+ body: nulls(p.size)))
198
+ end
199
+ end
200
+
201
+ def full_duplex_call(reqs, _call)
202
+ maybe_echo_metadata(_call)
203
+ # reqs is a lazy Enumerator of the requests sent by the client.
204
+ FullDuplexEnumerator.new(reqs).each_item
205
+ end
206
+
207
+ def half_duplex_call(reqs)
208
+ # TODO: update with unique behaviour of the half_duplex_call if that's
209
+ # ever required by any of the tests.
210
+ full_duplex_call(reqs)
211
+ end
212
+ end
213
+
214
+ # validates the command line options, returning them as a Hash.
215
+ def parse_options
216
+ options = {
217
+ 'port' => nil,
218
+ 'secure' => false
219
+ }
220
+ OptionParser.new do |opts|
221
+ opts.banner = 'Usage: --port port'
222
+ opts.on('--port PORT', 'server port') do |v|
223
+ options['port'] = v
224
+ end
225
+ opts.on('--use_tls USE_TLS', ['false', 'true'],
226
+ 'require a secure connection?') do |v|
227
+ options['secure'] = v == 'true'
228
+ end
229
+ end.parse!
230
+
231
+ if options['port'].nil?
232
+ fail(OptionParser::MissingArgument, 'please specify --port')
233
+ end
234
+ options
235
+ end
236
+
237
+ def main
238
+ opts = parse_options
239
+ host = "0.0.0.0:#{opts['port']}"
240
+ s = GRPC::RpcServer.new
241
+ if opts['secure']
242
+ s.add_http2_port(host, test_server_creds)
243
+ GRPC.logger.info("... running securely on #{host}")
244
+ else
245
+ s.add_http2_port(host, :this_port_is_insecure)
246
+ GRPC.logger.info("... running insecurely on #{host}")
247
+ end
248
+ s.handle(TestTarget)
249
+ s.run_till_terminated
250
+ end
251
+
252
+ main
@@ -0,0 +1,415 @@
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
+ # This is the xDS interop test Ruby client. This is meant to be run by
18
+ # the run_xds_tests.py test runner.
19
+ #
20
+ # Usage: $ tools/run_tests/run_xds_tests.py --test_case=... ...
21
+ # --client_cmd="path/to/xds_client.rb --server=<hostname> \
22
+ # --stats_port=<port> \
23
+ # --qps=<qps>"
24
+
25
+ # These lines are required for the generated files to load grpc
26
+ this_dir = File.expand_path(File.dirname(__FILE__))
27
+ lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
28
+ pb_dir = File.dirname(this_dir)
29
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
30
+ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
31
+
32
+ require 'optparse'
33
+ require 'logger'
34
+
35
+ require_relative '../../lib/grpc'
36
+ require 'google/protobuf'
37
+
38
+ require_relative '../src/proto/grpc/testing/empty_pb'
39
+ require_relative '../src/proto/grpc/testing/messages_pb'
40
+ require_relative '../src/proto/grpc/testing/test_services_pb'
41
+
42
+ class RpcConfig
43
+ attr_reader :rpcs_to_send, :metadata_to_send, :timeout_sec
44
+ def init(rpcs_to_send, metadata_to_send, timeout_sec = 0)
45
+ @rpcs_to_send = rpcs_to_send
46
+ @metadata_to_send = metadata_to_send
47
+ @timeout_sec = timeout_sec
48
+ end
49
+ end
50
+
51
+ # Some global constant mappings
52
+ $RPC_MAP = {
53
+ 'UnaryCall' => :UNARY_CALL,
54
+ 'EmptyCall' => :EMPTY_CALL,
55
+ }
56
+
57
+ # Some global variables to be shared by server and client
58
+ $watchers = Array.new
59
+ $watchers_mutex = Mutex.new
60
+ $watchers_cv = ConditionVariable.new
61
+ $shutdown = false
62
+ # These can be configured by the test runner dynamically
63
+ $rpc_config = RpcConfig.new
64
+ $rpc_config.init([:UNARY_CALL], {})
65
+ # These stats are shared across threads
66
+ $thread_results = Array.new
67
+ $thread_results_mu = Mutex.new
68
+ $accumulated_stats_mu = Mutex.new
69
+ $num_rpcs_started_by_method = {}
70
+ $num_rpcs_succeeded_by_method = {}
71
+ $num_rpcs_failed_by_method = {}
72
+ $accumulated_method_stats = {}
73
+
74
+ # RubyLogger defines a logger for gRPC based on the standard ruby logger.
75
+ module RubyLogger
76
+ def logger
77
+ LOGGER
78
+ end
79
+
80
+ LOGGER = Logger.new(STDOUT)
81
+ LOGGER.level = Logger::INFO
82
+ end
83
+
84
+ # GRPC is the general RPC module
85
+ module GRPC
86
+ # Inject the noop #logger if no module-level logger method has been injected.
87
+ extend RubyLogger
88
+ end
89
+
90
+ # creates a test stub
91
+ def create_stub(opts)
92
+ address = "#{opts.server}"
93
+ GRPC.logger.info("... connecting insecurely to #{address}")
94
+ Grpc::Testing::TestService::Stub.new(
95
+ address,
96
+ :this_channel_is_insecure,
97
+ )
98
+ end
99
+
100
+ class StatsPerMethod
101
+ attr_reader :rpcs_started, :result
102
+ def initialize()
103
+ @rpcs_started = 0
104
+ @result = Hash.new(0)
105
+ end
106
+ def increment_rpcs_started()
107
+ @rpcs_started += 1
108
+ end
109
+ def add_result(status_code)
110
+ @result[status_code] += 1
111
+ end
112
+ end
113
+
114
+ class ConfigureTarget < Grpc::Testing::XdsUpdateClientConfigureService::Service
115
+ include Grpc::Testing
116
+
117
+ def configure(req, _call)
118
+ metadata_to_send = {}
119
+ req.metadata.each do |m|
120
+ rpc = m.type
121
+ if !metadata_to_send.key?(rpc)
122
+ metadata_to_send[rpc] = {}
123
+ end
124
+ metadata_key = m.key
125
+ metadata_value = m.value
126
+ metadata_to_send[rpc][metadata_key] = metadata_value
127
+ end
128
+ new_rpc_config = RpcConfig.new
129
+ new_rpc_config.init(req['types'], metadata_to_send, req['timeout_sec'])
130
+ $rpc_config = new_rpc_config
131
+ ClientConfigureResponse.new()
132
+ end
133
+ end
134
+
135
+ # This implements LoadBalancerStatsService required by the test runner
136
+ class TestTarget < Grpc::Testing::LoadBalancerStatsService::Service
137
+ include Grpc::Testing
138
+
139
+ def get_client_stats(req, _call)
140
+ finish_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) +
141
+ req['timeout_sec']
142
+ watcher = {}
143
+ $watchers_mutex.synchronize do
144
+ watcher = {
145
+ "rpcs_by_method" => Hash.new(),
146
+ "rpcs_by_peer" => Hash.new(0),
147
+ "rpcs_needed" => req['num_rpcs'],
148
+ "no_remote_peer" => 0
149
+ }
150
+ $watchers << watcher
151
+ seconds_remaining = finish_time -
152
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
153
+ while watcher['rpcs_needed'] > 0 && seconds_remaining > 0
154
+ $watchers_cv.wait($watchers_mutex, seconds_remaining)
155
+ seconds_remaining = finish_time -
156
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
157
+ end
158
+ $watchers.delete_at($watchers.index(watcher))
159
+ end
160
+ # convert results into proper proto object
161
+ rpcs_by_method = {}
162
+ watcher['rpcs_by_method'].each do |rpc_name, rpcs_by_peer|
163
+ rpcs_by_method[rpc_name] = LoadBalancerStatsResponse::RpcsByPeer.new(
164
+ rpcs_by_peer: rpcs_by_peer
165
+ )
166
+ end
167
+ LoadBalancerStatsResponse.new(
168
+ rpcs_by_method: rpcs_by_method,
169
+ rpcs_by_peer: watcher['rpcs_by_peer'],
170
+ num_failures: watcher['no_remote_peer'] + watcher['rpcs_needed']
171
+ )
172
+ end
173
+
174
+ def get_client_accumulated_stats(req, _call)
175
+ $accumulated_stats_mu.synchronize do
176
+ all_stats_per_method = $accumulated_method_stats.map { |rpc, stats_per_method|
177
+ [rpc,
178
+ LoadBalancerAccumulatedStatsResponse::MethodStats.new(
179
+ rpcs_started: stats_per_method.rpcs_started,
180
+ result: stats_per_method.result
181
+ )]
182
+ }.to_h
183
+ LoadBalancerAccumulatedStatsResponse.new(
184
+ num_rpcs_started_by_method: $num_rpcs_started_by_method,
185
+ num_rpcs_succeeded_by_method: $num_rpcs_succeeded_by_method,
186
+ num_rpcs_failed_by_method: $num_rpcs_failed_by_method,
187
+ stats_per_method: all_stats_per_method,
188
+ )
189
+ end
190
+ end
191
+ end
192
+
193
+ def execute_rpc_in_thread(op, rpc)
194
+ Thread.new {
195
+ rpc_stats_key = rpc.to_s
196
+ remote_peer = ""
197
+ begin
198
+ op.execute
199
+ if op.metadata.key?('hostname')
200
+ remote_peer = op.metadata['hostname']
201
+ end
202
+ $accumulated_stats_mu.synchronize do
203
+ $num_rpcs_succeeded_by_method[rpc_stats_key] += 1
204
+ $accumulated_method_stats[rpc_stats_key].add_result(0)
205
+ end
206
+ rescue GRPC::BadStatus => e
207
+ $accumulated_stats_mu.synchronize do
208
+ $num_rpcs_failed_by_method[rpc_stats_key] += 1
209
+ $accumulated_method_stats[rpc_stats_key].add_result(e.code)
210
+ end
211
+ end
212
+ $thread_results_mu.synchronize do
213
+ $thread_results << [rpc, remote_peer]
214
+ end
215
+ }
216
+ end
217
+
218
+ # send 1 rpc every 1/qps second
219
+ def run_test_loop(stub, target_seconds_between_rpcs, fail_on_failed_rpcs)
220
+ include Grpc::Testing
221
+ simple_req = SimpleRequest.new()
222
+ empty_req = Empty.new()
223
+ target_next_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
224
+ # Some RPCs are meant to be "kept open". Since Ruby does not have an
225
+ # async API, we are executing those RPCs in a thread so that they don't
226
+ # block.
227
+ keep_open_threads = Array.new
228
+ while !$shutdown
229
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
230
+ sleep_seconds = target_next_start - now
231
+ if sleep_seconds < 0
232
+ target_next_start = now + target_seconds_between_rpcs
233
+ else
234
+ target_next_start += target_seconds_between_rpcs
235
+ sleep(sleep_seconds)
236
+ end
237
+ deadline_sec = $rpc_config.timeout_sec > 0 ? $rpc_config.timeout_sec : 30
238
+ deadline = GRPC::Core::TimeConsts::from_relative_time(deadline_sec)
239
+ results = {}
240
+ $rpc_config.rpcs_to_send.each do |rpc|
241
+ # rpc is in the form of :UNARY_CALL or :EMPTY_CALL here
242
+ metadata = $rpc_config.metadata_to_send.key?(rpc) ?
243
+ $rpc_config.metadata_to_send[rpc] : {}
244
+ $accumulated_stats_mu.synchronize do
245
+ $num_rpcs_started_by_method[rpc.to_s] += 1
246
+ $accumulated_method_stats[rpc.to_s].increment_rpcs_started()
247
+ end
248
+ if rpc == :UNARY_CALL
249
+ op = stub.unary_call(simple_req,
250
+ metadata: metadata,
251
+ deadline: deadline,
252
+ return_op: true)
253
+ elsif rpc == :EMPTY_CALL
254
+ op = stub.empty_call(empty_req,
255
+ metadata: metadata,
256
+ deadline: deadline,
257
+ return_op: true)
258
+ else
259
+ raise "Unsupported rpc #{rpc}"
260
+ end
261
+ keep_open_threads << execute_rpc_in_thread(op, rpc)
262
+ end
263
+ # collect results from threads
264
+ $thread_results_mu.synchronize do
265
+ $thread_results.each do |r|
266
+ rpc_name, remote_peer = r
267
+ results[rpc_name] = remote_peer
268
+ end
269
+ $thread_results = Array.new
270
+ end
271
+ $watchers_mutex.synchronize do
272
+ $watchers.each do |watcher|
273
+ # this is counted once when each group of all rpcs_to_send were done
274
+ watcher['rpcs_needed'] -= 1
275
+ results.each do |rpc_name, remote_peer|
276
+ # These stats expect rpc_name to be in the form of
277
+ # UnaryCall or EmptyCall, not the underscore-case all-caps form
278
+ rpc_name = $RPC_MAP.invert()[rpc_name]
279
+ if remote_peer.strip.empty?
280
+ # error is counted per individual RPC
281
+ watcher['no_remote_peer'] += 1
282
+ else
283
+ if not watcher['rpcs_by_method'].key?(rpc_name)
284
+ watcher['rpcs_by_method'][rpc_name] = Hash.new(0)
285
+ end
286
+ # increment the remote hostname distribution histogram
287
+ # both by overall, and broken down per RPC
288
+ watcher['rpcs_by_method'][rpc_name][remote_peer] += 1
289
+ watcher['rpcs_by_peer'][remote_peer] += 1
290
+ end
291
+ end
292
+ end
293
+ $watchers_cv.broadcast
294
+ end
295
+ end
296
+ keep_open_threads.each { |thd| thd.join }
297
+ end
298
+
299
+ # Args is used to hold the command line info.
300
+ Args = Struct.new(:fail_on_failed_rpcs, :num_channels,
301
+ :rpc, :metadata,
302
+ :server, :stats_port, :qps)
303
+
304
+ # validates the command line options, returning them as a Hash.
305
+ def parse_args
306
+ args = Args.new
307
+ args['fail_on_failed_rpcs'] = false
308
+ args['num_channels'] = 1
309
+ args['rpc'] = 'UnaryCall'
310
+ args['metadata'] = ''
311
+ OptionParser.new do |opts|
312
+ opts.on('--fail_on_failed_rpcs BOOL', ['false', 'true']) do |v|
313
+ args['fail_on_failed_rpcs'] = v == 'true'
314
+ end
315
+ opts.on('--num_channels CHANNELS', 'number of channels') do |v|
316
+ args['num_channels'] = v.to_i
317
+ end
318
+ opts.on('--rpc RPCS_TO_SEND', 'list of RPCs to send') do |v|
319
+ args['rpc'] = v
320
+ end
321
+ opts.on('--metadata METADATA_TO_SEND', 'metadata to send per RPC') do |v|
322
+ args['metadata'] = v
323
+ end
324
+ opts.on('--server SERVER_HOST', 'server hostname') do |v|
325
+ GRPC.logger.info("ruby xds: server address is #{v}")
326
+ args['server'] = v
327
+ end
328
+ opts.on('--stats_port STATS_PORT', 'stats port') do |v|
329
+ GRPC.logger.info("ruby xds: stats port is #{v}")
330
+ args['stats_port'] = v
331
+ end
332
+ opts.on('--qps QPS', 'qps') do |v|
333
+ GRPC.logger.info("ruby xds: qps is #{v}")
334
+ args['qps'] = v
335
+ end
336
+ end.parse!
337
+ args
338
+ end
339
+
340
+ def main
341
+ opts = parse_args
342
+
343
+ # This server hosts the LoadBalancerStatsService
344
+ host = "0.0.0.0:#{opts['stats_port']}"
345
+ s = GRPC::RpcServer.new
346
+ s.add_http2_port(host, :this_port_is_insecure)
347
+ s.handle(TestTarget)
348
+ s.handle(ConfigureTarget)
349
+ server_thread = Thread.new {
350
+ # run the server until the main test runner terminates this process
351
+ s.run_till_terminated_or_interrupted(['TERM'])
352
+ }
353
+
354
+ # Initialize stats
355
+ $RPC_MAP.values.each do |rpc|
356
+ $num_rpcs_started_by_method[rpc.to_s] = 0
357
+ $num_rpcs_succeeded_by_method[rpc.to_s] = 0
358
+ $num_rpcs_failed_by_method[rpc.to_s] = 0
359
+ $accumulated_method_stats[rpc.to_s] = StatsPerMethod.new
360
+ end
361
+
362
+ # The client just sends rpcs continuously in a regular interval
363
+ stub = create_stub(opts)
364
+ target_seconds_between_rpcs = (1.0 / opts['qps'].to_f)
365
+ # Convert 'metadata' input in the form of
366
+ # rpc1:k1:v1,rpc2:k2:v2,rpc1:k3:v3
367
+ # into
368
+ # {
369
+ # 'rpc1' => {
370
+ # 'k1' => 'v1',
371
+ # 'k3' => 'v3',
372
+ # },
373
+ # 'rpc2' => {
374
+ # 'k2' => 'v2'
375
+ # },
376
+ # }
377
+ rpcs_to_send = []
378
+ metadata_to_send = {}
379
+ if opts['metadata']
380
+ metadata_entries = opts['metadata'].split(',')
381
+ metadata_entries.each do |e|
382
+ (rpc_name, metadata_key, metadata_value) = e.split(':')
383
+ rpc_name = $RPC_MAP[rpc_name]
384
+ # initialize if we haven't seen this rpc_name yet
385
+ if !metadata_to_send.key?(rpc_name)
386
+ metadata_to_send[rpc_name] = {}
387
+ end
388
+ metadata_to_send[rpc_name][metadata_key] = metadata_value
389
+ end
390
+ end
391
+ if opts['rpc']
392
+ rpcs_to_send = opts['rpc'].split(',')
393
+ end
394
+ if rpcs_to_send.size > 0
395
+ rpcs_to_send.map! { |rpc| $RPC_MAP[rpc] }
396
+ new_rpc_config = RpcConfig.new
397
+ new_rpc_config.init(rpcs_to_send, metadata_to_send)
398
+ $rpc_config = new_rpc_config
399
+ end
400
+ client_threads = Array.new
401
+ opts['num_channels'].times {
402
+ client_threads << Thread.new {
403
+ run_test_loop(stub, target_seconds_between_rpcs,
404
+ opts['fail_on_failed_rpcs'])
405
+ }
406
+ }
407
+
408
+ server_thread.join
409
+ $shutdown = true
410
+ client_threads.each { |thd| thd.join }
411
+ end
412
+
413
+ if __FILE__ == $0
414
+ main
415
+ end
@@ -0,0 +1,42 @@
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
+ describe GRPC::Core::CallCredentials do
18
+ CallCredentials = GRPC::Core::CallCredentials
19
+
20
+ let(:auth_proc) { proc { { 'plugin_key' => 'plugin_value' } } }
21
+
22
+ describe '#new' do
23
+ it 'can successfully create a CallCredentials from a proc' do
24
+ expect { CallCredentials.new(auth_proc) }.not_to raise_error
25
+ end
26
+ end
27
+
28
+ describe '#compose' do
29
+ it 'can compose with another CallCredentials' do
30
+ creds1 = CallCredentials.new(auth_proc)
31
+ creds2 = CallCredentials.new(auth_proc)
32
+ expect { creds1.compose creds2 }.not_to raise_error
33
+ end
34
+
35
+ it 'can compose with multiple CallCredentials' do
36
+ creds1 = CallCredentials.new(auth_proc)
37
+ creds2 = CallCredentials.new(auth_proc)
38
+ creds3 = CallCredentials.new(auth_proc)
39
+ expect { creds1.compose(creds2, creds3) }.not_to raise_error
40
+ end
41
+ end
42
+ end