grpc 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Rakefile +4 -2
- data/bin/{interop/test/cpp/interop/test.rb → grpc_ruby_interop_client} +4 -14
- data/bin/{interop/test/cpp/interop/empty.rb → grpc_ruby_interop_server} +4 -15
- data/bin/interop/interop_client.rb +9 -335
- data/bin/interop/interop_server.rb +9 -153
- data/bin/math_client.rb +3 -3
- data/bin/math_server.rb +18 -1
- data/bin/noproto_server.rb +2 -1
- data/ext/grpc/rb_call.c +82 -15
- data/ext/grpc/rb_channel.c +141 -11
- data/ext/grpc/rb_channel_args.c +2 -1
- data/ext/grpc/rb_completion_queue.c +8 -7
- data/ext/grpc/rb_credentials.c +7 -6
- data/ext/grpc/rb_grpc.c +23 -8
- data/ext/grpc/rb_server.c +31 -45
- data/ext/grpc/rb_server_credentials.c +91 -34
- data/lib/grpc/generic/active_call.rb +7 -7
- data/lib/grpc/generic/bidi_call.rb +17 -12
- data/lib/grpc/generic/client_stub.rb +88 -22
- data/lib/grpc/generic/rpc_server.rb +19 -18
- data/lib/grpc/generic/service.rb +8 -10
- data/lib/grpc/grpc.so +0 -0
- data/lib/grpc/logconfig.rb +26 -10
- data/lib/grpc/version.rb +1 -1
- data/spec/call_spec.rb +9 -1
- data/spec/channel_spec.rb +2 -2
- data/spec/client_server_spec.rb +28 -11
- data/spec/credentials_spec.rb +7 -7
- data/spec/generic/active_call_spec.rb +43 -18
- data/spec/generic/client_stub_spec.rb +21 -1
- data/spec/generic/rpc_server_spec.rb +20 -9
- data/spec/pb/health/checker_spec.rb +232 -0
- data/spec/server_credentials_spec.rb +32 -7
- data/spec/server_spec.rb +8 -4
- data/spec/spec_helper.rb +13 -1
- metadata +31 -51
- data/.gitignore +0 -15
- data/.rspec +0 -4
- data/.rubocop.yml +0 -10
- data/.rubocop_todo.yml +0 -44
- data/CHANGELOG.md +0 -11
- data/Gemfile +0 -4
- data/README.md +0 -84
- data/bin/interop/README.md +0 -8
- data/bin/interop/test/cpp/interop/messages.rb +0 -89
- data/bin/interop/test/cpp/interop/test_services.rb +0 -60
- data/grpc.gemspec +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b272ebd68681b700d46662fda7888004ed93abda
|
4
|
+
data.tar.gz: 9ed56e0929ed31e957390ce91d8c9c97dd66ca2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d355d654d8cfedbffff3f454f11fb866eaf515ba0ca6dfcd38d0e23f7341902e0d3e824535ed2d77520eeaf97518b7b60055aeef596fd5dfa31b2fa729b763c
|
7
|
+
data.tar.gz: d2eae88c15cb5b1d551bed405657ba0dea498bf858367f6cc4ac3a815626b89bcd39e05c88917551522afd42da68c6ff36a12bf419ede487658a4535c285240d
|
data/Rakefile
CHANGED
@@ -20,7 +20,8 @@ SPEC_SUITES = [
|
|
20
20
|
{ id: :bidi, title: 'bidi tests', dir: %w(spec/generic),
|
21
21
|
tag: 'bidi' },
|
22
22
|
{ id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
|
23
|
-
tag: 'server' }
|
23
|
+
tag: 'server' },
|
24
|
+
{ id: :pb, title: 'protobuf service tests', dir: %w(spec/pb) }
|
24
25
|
]
|
25
26
|
namespace :suite do
|
26
27
|
SPEC_SUITES.each do |suite|
|
@@ -50,7 +51,8 @@ task 'suite:wrapper' => [:compile, :rubocop]
|
|
50
51
|
task 'suite:idiomatic' => 'suite:wrapper'
|
51
52
|
task 'suite:bidi' => 'suite:wrapper'
|
52
53
|
task 'suite:server' => 'suite:wrapper'
|
54
|
+
task 'suite:pb' => 'suite:server'
|
53
55
|
|
54
56
|
desc 'Compiles the gRPC extension then runs all the tests'
|
55
|
-
task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
|
57
|
+
task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server']
|
56
58
|
task default: :all
|
@@ -1,3 +1,5 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
# Copyright 2015, Google Inc.
|
2
4
|
# All rights reserved.
|
3
5
|
#
|
@@ -27,17 +29,5 @@
|
|
27
29
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
30
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
31
|
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
require 'google/protobuf'
|
34
|
-
|
35
|
-
require 'test/cpp/interop/empty'
|
36
|
-
require 'test/cpp/interop/messages'
|
37
|
-
Google::Protobuf::DescriptorPool.generated_pool.build do
|
38
|
-
end
|
39
|
-
|
40
|
-
module Grpc
|
41
|
-
module Testing
|
42
|
-
end
|
43
|
-
end
|
32
|
+
# Provides a gem binary entry point for the interop client.
|
33
|
+
require 'test/client'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
# Copyright 2015, Google Inc.
|
2
4
|
# All rights reserved.
|
3
5
|
#
|
@@ -27,18 +29,5 @@
|
|
27
29
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
30
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
31
|
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
require 'google/protobuf'
|
34
|
-
|
35
|
-
Google::Protobuf::DescriptorPool.generated_pool.build do
|
36
|
-
add_message "grpc.testing.Empty" do
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module Grpc
|
41
|
-
module Testing
|
42
|
-
Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
|
43
|
-
end
|
44
|
-
end
|
32
|
+
# Provides a gem binary entry point for the interop server
|
33
|
+
require 'test/server'
|
@@ -29,6 +29,12 @@
|
|
29
29
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
30
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
31
|
|
32
|
+
# #######################################################################
|
33
|
+
# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb
|
34
|
+
#
|
35
|
+
# This file remains to support existing tools and scripts that use it.
|
36
|
+
# ######################################################################
|
37
|
+
#
|
32
38
|
# interop_client is a testing tool that accesses a gRPC interop testing
|
33
39
|
# server and runs a test on it.
|
34
40
|
#
|
@@ -39,339 +45,7 @@
|
|
39
45
|
# --test_case=<testcase_name>
|
40
46
|
|
41
47
|
this_dir = File.expand_path(File.dirname(__FILE__))
|
42
|
-
|
43
|
-
$LOAD_PATH.unshift(
|
44
|
-
$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
|
45
|
-
|
46
|
-
require 'optparse'
|
47
|
-
require 'minitest'
|
48
|
-
require 'minitest/assertions'
|
49
|
-
|
50
|
-
require 'grpc'
|
51
|
-
require 'googleauth'
|
52
|
-
require 'google/protobuf'
|
53
|
-
|
54
|
-
require 'test/cpp/interop/test_services'
|
55
|
-
require 'test/cpp/interop/messages'
|
56
|
-
require 'test/cpp/interop/empty'
|
57
|
-
|
58
|
-
require 'signet/ssl_config'
|
59
|
-
|
60
|
-
AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
|
61
|
-
|
62
|
-
# loads the certificates used to access the test server securely.
|
63
|
-
def load_test_certs
|
64
|
-
this_dir = File.expand_path(File.dirname(__FILE__))
|
65
|
-
data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
|
66
|
-
files = ['ca.pem', 'server1.key', 'server1.pem']
|
67
|
-
files.map { |f| File.open(File.join(data_dir, f)).read }
|
68
|
-
end
|
69
|
-
|
70
|
-
# loads the certificates used to access the test server securely.
|
71
|
-
def load_prod_cert
|
72
|
-
fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
|
73
|
-
GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
|
74
|
-
File.open(ENV['SSL_CERT_FILE']).read
|
75
|
-
end
|
76
|
-
|
77
|
-
# creates SSL Credentials from the test certificates.
|
78
|
-
def test_creds
|
79
|
-
certs = load_test_certs
|
80
|
-
GRPC::Core::Credentials.new(certs[0])
|
81
|
-
end
|
82
|
-
|
83
|
-
# creates SSL Credentials from the production certificates.
|
84
|
-
def prod_creds
|
85
|
-
cert_text = load_prod_cert
|
86
|
-
GRPC::Core::Credentials.new(cert_text)
|
87
|
-
end
|
88
|
-
|
89
|
-
# creates the SSL Credentials.
|
90
|
-
def ssl_creds(use_test_ca)
|
91
|
-
return test_creds if use_test_ca
|
92
|
-
prod_creds
|
93
|
-
end
|
94
|
-
|
95
|
-
# creates a test stub that accesses host:port securely.
|
96
|
-
def create_stub(opts)
|
97
|
-
address = "#{opts.host}:#{opts.port}"
|
98
|
-
if opts.secure
|
99
|
-
stub_opts = {
|
100
|
-
:creds => ssl_creds(opts.use_test_ca),
|
101
|
-
GRPC::Core::Channel::SSL_TARGET => opts.host_override
|
102
|
-
}
|
103
|
-
|
104
|
-
# Add service account creds if specified
|
105
|
-
wants_creds = %w(all compute_engine_creds service_account_creds)
|
106
|
-
if wants_creds.include?(opts.test_case)
|
107
|
-
unless opts.oauth_scope.nil?
|
108
|
-
auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
|
109
|
-
stub_opts[:update_metadata] = auth_creds.updater_proc
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
if opts.test_case == 'jwt_token_creds' # don't use a scope
|
114
|
-
auth_creds = Google::Auth.get_application_default
|
115
|
-
stub_opts[:update_metadata] = auth_creds.updater_proc
|
116
|
-
end
|
117
|
-
|
118
|
-
GRPC.logger.info("... connecting securely to #{address}")
|
119
|
-
Grpc::Testing::TestService::Stub.new(address, **stub_opts)
|
120
|
-
else
|
121
|
-
GRPC.logger.info("... connecting insecurely to #{address}")
|
122
|
-
Grpc::Testing::TestService::Stub.new(address)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# produces a string of null chars (\0) of length l.
|
127
|
-
def nulls(l)
|
128
|
-
fail 'requires #{l} to be +ve' if l < 0
|
129
|
-
[].pack('x' * l).force_encoding('utf-8')
|
130
|
-
end
|
131
|
-
|
132
|
-
# a PingPongPlayer implements the ping pong bidi test.
|
133
|
-
class PingPongPlayer
|
134
|
-
include Minitest::Assertions
|
135
|
-
include Grpc::Testing
|
136
|
-
include Grpc::Testing::PayloadType
|
137
|
-
attr_accessor :assertions # required by Minitest::Assertions
|
138
|
-
attr_accessor :queue
|
139
|
-
attr_accessor :canceller_op
|
140
|
-
|
141
|
-
# reqs is the enumerator over the requests
|
142
|
-
def initialize(msg_sizes)
|
143
|
-
@queue = Queue.new
|
144
|
-
@msg_sizes = msg_sizes
|
145
|
-
@assertions = 0 # required by Minitest::Assertions
|
146
|
-
@canceller_op = nil # used to cancel after the first response
|
147
|
-
end
|
148
|
-
|
149
|
-
def each_item
|
150
|
-
return enum_for(:each_item) unless block_given?
|
151
|
-
req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short
|
152
|
-
count = 0
|
153
|
-
@msg_sizes.each do |m|
|
154
|
-
req_size, resp_size = m
|
155
|
-
req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
|
156
|
-
response_type: :COMPRESSABLE,
|
157
|
-
response_parameters: [p_cls.new(size: resp_size)])
|
158
|
-
yield req
|
159
|
-
resp = @queue.pop
|
160
|
-
assert_equal(:COMPRESSABLE, resp.payload.type, 'payload type is wrong')
|
161
|
-
assert_equal(resp_size, resp.payload.body.length,
|
162
|
-
"payload body #{count} has the wrong length")
|
163
|
-
p "OK: ping_pong #{count}"
|
164
|
-
count += 1
|
165
|
-
unless @canceller_op.nil?
|
166
|
-
canceller_op.cancel
|
167
|
-
break
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# defines methods corresponding to each interop test case.
|
174
|
-
class NamedTests
|
175
|
-
include Minitest::Assertions
|
176
|
-
include Grpc::Testing
|
177
|
-
include Grpc::Testing::PayloadType
|
178
|
-
attr_accessor :assertions # required by Minitest::Assertions
|
179
|
-
|
180
|
-
def initialize(stub, args)
|
181
|
-
@assertions = 0 # required by Minitest::Assertions
|
182
|
-
@stub = stub
|
183
|
-
@args = args
|
184
|
-
end
|
185
|
-
|
186
|
-
def empty_unary
|
187
|
-
resp = @stub.empty_call(Empty.new)
|
188
|
-
assert resp.is_a?(Empty), 'empty_unary: invalid response'
|
189
|
-
p 'OK: empty_unary'
|
190
|
-
end
|
191
|
-
|
192
|
-
def large_unary
|
193
|
-
perform_large_unary
|
194
|
-
p 'OK: large_unary'
|
195
|
-
end
|
196
|
-
|
197
|
-
def service_account_creds
|
198
|
-
# ignore this test if the oauth options are not set
|
199
|
-
if @args.oauth_scope.nil?
|
200
|
-
p 'NOT RUN: service_account_creds; no service_account settings'
|
201
|
-
return
|
202
|
-
end
|
203
|
-
json_key = File.read(ENV[AUTH_ENV])
|
204
|
-
wanted_email = MultiJson.load(json_key)['client_email']
|
205
|
-
resp = perform_large_unary(fill_username: true,
|
206
|
-
fill_oauth_scope: true)
|
207
|
-
assert_equal(wanted_email, resp.username,
|
208
|
-
'service_account_creds: incorrect username')
|
209
|
-
assert(@args.oauth_scope.include?(resp.oauth_scope),
|
210
|
-
'service_account_creds: incorrect oauth_scope')
|
211
|
-
p 'OK: service_account_creds'
|
212
|
-
end
|
213
|
-
|
214
|
-
def jwt_token_creds
|
215
|
-
json_key = File.read(ENV[AUTH_ENV])
|
216
|
-
wanted_email = MultiJson.load(json_key)['client_email']
|
217
|
-
resp = perform_large_unary(fill_username: true)
|
218
|
-
assert_equal(wanted_email, resp.username,
|
219
|
-
'service_account_creds: incorrect username')
|
220
|
-
p 'OK: jwt_token_creds'
|
221
|
-
end
|
222
|
-
|
223
|
-
def compute_engine_creds
|
224
|
-
resp = perform_large_unary(fill_username: true,
|
225
|
-
fill_oauth_scope: true)
|
226
|
-
assert_equal(@args.default_service_account, resp.username,
|
227
|
-
'compute_engine_creds: incorrect username')
|
228
|
-
p 'OK: compute_engine_creds'
|
229
|
-
end
|
230
|
-
|
231
|
-
def client_streaming
|
232
|
-
msg_sizes = [27_182, 8, 1828, 45_904]
|
233
|
-
wanted_aggregate_size = 74_922
|
234
|
-
reqs = msg_sizes.map do |x|
|
235
|
-
req = Payload.new(body: nulls(x))
|
236
|
-
StreamingInputCallRequest.new(payload: req)
|
237
|
-
end
|
238
|
-
resp = @stub.streaming_input_call(reqs)
|
239
|
-
assert_equal(wanted_aggregate_size, resp.aggregated_payload_size,
|
240
|
-
'client_streaming: aggregate payload size is incorrect')
|
241
|
-
p 'OK: client_streaming'
|
242
|
-
end
|
243
|
-
|
244
|
-
def server_streaming
|
245
|
-
msg_sizes = [31_415, 9, 2653, 58_979]
|
246
|
-
response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
|
247
|
-
req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
|
248
|
-
response_parameters: response_spec)
|
249
|
-
resps = @stub.streaming_output_call(req)
|
250
|
-
resps.each_with_index do |r, i|
|
251
|
-
assert i < msg_sizes.length, 'too many responses'
|
252
|
-
assert_equal(:COMPRESSABLE, r.payload.type,
|
253
|
-
'payload type is wrong')
|
254
|
-
assert_equal(msg_sizes[i], r.payload.body.length,
|
255
|
-
'payload body #{i} has the wrong length')
|
256
|
-
end
|
257
|
-
p 'OK: server_streaming'
|
258
|
-
end
|
259
|
-
|
260
|
-
def ping_pong
|
261
|
-
msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
|
262
|
-
ppp = PingPongPlayer.new(msg_sizes)
|
263
|
-
resps = @stub.full_duplex_call(ppp.each_item)
|
264
|
-
resps.each { |r| ppp.queue.push(r) }
|
265
|
-
p 'OK: ping_pong'
|
266
|
-
end
|
267
|
-
|
268
|
-
def cancel_after_begin
|
269
|
-
msg_sizes = [27_182, 8, 1828, 45_904]
|
270
|
-
reqs = msg_sizes.map do |x|
|
271
|
-
req = Payload.new(body: nulls(x))
|
272
|
-
StreamingInputCallRequest.new(payload: req)
|
273
|
-
end
|
274
|
-
op = @stub.streaming_input_call(reqs, return_op: true)
|
275
|
-
op.cancel
|
276
|
-
assert_raises(GRPC::Cancelled) { op.execute }
|
277
|
-
assert(op.cancelled, 'call operation should be CANCELLED')
|
278
|
-
p 'OK: cancel_after_begin'
|
279
|
-
end
|
280
|
-
|
281
|
-
def cancel_after_first_response
|
282
|
-
msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
|
283
|
-
ppp = PingPongPlayer.new(msg_sizes)
|
284
|
-
op = @stub.full_duplex_call(ppp.each_item, return_op: true)
|
285
|
-
ppp.canceller_op = op # causes ppp to cancel after the 1st message
|
286
|
-
op.execute.each { |r| ppp.queue.push(r) }
|
287
|
-
op.wait
|
288
|
-
assert(op.cancelled, 'call operation was not CANCELLED')
|
289
|
-
p 'OK: cancel_after_first_response'
|
290
|
-
end
|
291
|
-
|
292
|
-
def all
|
293
|
-
all_methods = NamedTests.instance_methods(false).map(&:to_s)
|
294
|
-
all_methods.each do |m|
|
295
|
-
next if m == 'all' || m.start_with?('assert')
|
296
|
-
p "TESTCASE: #{m}"
|
297
|
-
method(m).call
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
private
|
302
|
-
|
303
|
-
def perform_large_unary(fill_username: false, fill_oauth_scope: false)
|
304
|
-
req_size, wanted_response_size = 271_828, 314_159
|
305
|
-
payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
|
306
|
-
req = SimpleRequest.new(response_type: :COMPRESSABLE,
|
307
|
-
response_size: wanted_response_size,
|
308
|
-
payload: payload)
|
309
|
-
req.fill_username = fill_username
|
310
|
-
req.fill_oauth_scope = fill_oauth_scope
|
311
|
-
resp = @stub.unary_call(req)
|
312
|
-
assert_equal(:COMPRESSABLE, resp.payload.type,
|
313
|
-
'large_unary: payload had the wrong type')
|
314
|
-
assert_equal(wanted_response_size, resp.payload.body.length,
|
315
|
-
'large_unary: payload had the wrong length')
|
316
|
-
assert_equal(nulls(wanted_response_size), resp.payload.body,
|
317
|
-
'large_unary: payload content is invalid')
|
318
|
-
resp
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
# Args is used to hold the command line info.
|
323
|
-
Args = Struct.new(:default_service_account, :host, :host_override,
|
324
|
-
:oauth_scope, :port, :secure, :test_case,
|
325
|
-
:use_test_ca)
|
326
|
-
|
327
|
-
# validates the the command line options, returning them as a Hash.
|
328
|
-
def parse_args
|
329
|
-
args = Args.new
|
330
|
-
args.host_override = 'foo.test.google.fr'
|
331
|
-
OptionParser.new do |opts|
|
332
|
-
opts.on('--oauth_scope scope',
|
333
|
-
'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
|
334
|
-
opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
|
335
|
-
args['host'] = v
|
336
|
-
end
|
337
|
-
opts.on('--default_service_account email_address',
|
338
|
-
'email address of the default service account') do |v|
|
339
|
-
args['default_service_account'] = v
|
340
|
-
end
|
341
|
-
opts.on('--server_host_override HOST_OVERRIDE',
|
342
|
-
'override host via a HTTP header') do |v|
|
343
|
-
args['host_override'] = v
|
344
|
-
end
|
345
|
-
opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
|
346
|
-
# instance_methods(false) gives only the methods defined in that class
|
347
|
-
test_cases = NamedTests.instance_methods(false).map(&:to_s)
|
348
|
-
test_case_list = test_cases.join(',')
|
349
|
-
opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
|
350
|
-
" (#{test_case_list})") { |v| args['test_case'] = v }
|
351
|
-
opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
|
352
|
-
args['secure'] = v
|
353
|
-
end
|
354
|
-
opts.on('-t', '--use_test_ca',
|
355
|
-
'if secure, use the test certificate?') do |v|
|
356
|
-
args['use_test_ca'] = v
|
357
|
-
end
|
358
|
-
end.parse!
|
359
|
-
_check_args(args)
|
360
|
-
end
|
361
|
-
|
362
|
-
def _check_args(args)
|
363
|
-
%w(host port test_case).each do |a|
|
364
|
-
if args[a].nil?
|
365
|
-
fail(OptionParser::MissingArgument, "please specify --#{arg}")
|
366
|
-
end
|
367
|
-
end
|
368
|
-
args
|
369
|
-
end
|
370
|
-
|
371
|
-
def main
|
372
|
-
opts = parse_args
|
373
|
-
stub = create_stub(opts)
|
374
|
-
NamedTests.new(stub, opts).method(opts['test_case']).call
|
375
|
-
end
|
48
|
+
pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
|
49
|
+
$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
|
376
50
|
|
377
|
-
|
51
|
+
require 'test/client'
|
@@ -29,6 +29,12 @@
|
|
29
29
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
30
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
31
|
|
32
|
+
# #######################################################################
|
33
|
+
# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb
|
34
|
+
#
|
35
|
+
# This file remains to support existing tools and scripts that use it.
|
36
|
+
# ######################################################################
|
37
|
+
#
|
32
38
|
# interop_server is a Testing app that runs a gRPC interop testing server.
|
33
39
|
#
|
34
40
|
# It helps validate interoperation b/w gRPC in different environments
|
@@ -38,157 +44,7 @@
|
|
38
44
|
# Usage: $ path/to/interop_server.rb --port
|
39
45
|
|
40
46
|
this_dir = File.expand_path(File.dirname(__FILE__))
|
41
|
-
|
42
|
-
$LOAD_PATH.unshift(
|
43
|
-
$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
|
44
|
-
|
45
|
-
require 'forwardable'
|
46
|
-
require 'optparse'
|
47
|
-
|
48
|
-
require 'grpc'
|
49
|
-
|
50
|
-
require 'test/cpp/interop/test_services'
|
51
|
-
require 'test/cpp/interop/messages'
|
52
|
-
require 'test/cpp/interop/empty'
|
53
|
-
|
54
|
-
# loads the certificates by the test server.
|
55
|
-
def load_test_certs
|
56
|
-
this_dir = File.expand_path(File.dirname(__FILE__))
|
57
|
-
data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
|
58
|
-
files = ['ca.pem', 'server1.key', 'server1.pem']
|
59
|
-
files.map { |f| File.open(File.join(data_dir, f)).read }
|
60
|
-
end
|
61
|
-
|
62
|
-
# creates a ServerCredentials from the test certificates.
|
63
|
-
def test_server_creds
|
64
|
-
certs = load_test_certs
|
65
|
-
GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
|
66
|
-
end
|
67
|
-
|
68
|
-
# produces a string of null chars (\0) of length l.
|
69
|
-
def nulls(l)
|
70
|
-
fail 'requires #{l} to be +ve' if l < 0
|
71
|
-
[].pack('x' * l).force_encoding('utf-8')
|
72
|
-
end
|
73
|
-
|
74
|
-
# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
|
75
|
-
class EnumeratorQueue
|
76
|
-
extend Forwardable
|
77
|
-
def_delegators :@q, :push
|
78
|
-
|
79
|
-
def initialize(sentinel)
|
80
|
-
@q = Queue.new
|
81
|
-
@sentinel = sentinel
|
82
|
-
end
|
83
|
-
|
84
|
-
def each_item
|
85
|
-
return enum_for(:each_item) unless block_given?
|
86
|
-
loop do
|
87
|
-
r = @q.pop
|
88
|
-
break if r.equal?(@sentinel)
|
89
|
-
fail r if r.is_a? Exception
|
90
|
-
yield r
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# A runnable implementation of the schema-specified testing service, with each
|
96
|
-
# service method implemented as required by the interop testing spec.
|
97
|
-
class TestTarget < Grpc::Testing::TestService::Service
|
98
|
-
include Grpc::Testing
|
99
|
-
include Grpc::Testing::PayloadType
|
100
|
-
|
101
|
-
def empty_call(_empty, _call)
|
102
|
-
Empty.new
|
103
|
-
end
|
104
|
-
|
105
|
-
def unary_call(simple_req, _call)
|
106
|
-
req_size = simple_req.response_size
|
107
|
-
SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
|
108
|
-
body: nulls(req_size)))
|
109
|
-
end
|
110
|
-
|
111
|
-
def streaming_input_call(call)
|
112
|
-
sizes = call.each_remote_read.map { |x| x.payload.body.length }
|
113
|
-
sum = sizes.inject { |s, x| s + x }
|
114
|
-
StreamingInputCallResponse.new(aggregated_payload_size: sum)
|
115
|
-
end
|
116
|
-
|
117
|
-
def streaming_output_call(req, _call)
|
118
|
-
cls = StreamingOutputCallResponse
|
119
|
-
req.response_parameters.map do |p|
|
120
|
-
cls.new(payload: Payload.new(type: req.response_type,
|
121
|
-
body: nulls(p.size)))
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def full_duplex_call(reqs)
|
126
|
-
# reqs is a lazy Enumerator of the requests sent by the client.
|
127
|
-
q = EnumeratorQueue.new(self)
|
128
|
-
cls = StreamingOutputCallResponse
|
129
|
-
Thread.new do
|
130
|
-
begin
|
131
|
-
GRPC.logger.info('interop-server: started receiving')
|
132
|
-
reqs.each do |req|
|
133
|
-
resp_size = req.response_parameters[0].size
|
134
|
-
GRPC.logger.info("read a req, response size is #{resp_size}")
|
135
|
-
resp = cls.new(payload: Payload.new(type: req.response_type,
|
136
|
-
body: nulls(resp_size)))
|
137
|
-
q.push(resp)
|
138
|
-
end
|
139
|
-
GRPC.logger.info('interop-server: finished receiving')
|
140
|
-
q.push(self)
|
141
|
-
rescue StandardError => e
|
142
|
-
GRPC.logger.info('interop-server: failed')
|
143
|
-
GRPC.logger.warn(e)
|
144
|
-
q.push(e) # share the exception with the enumerator
|
145
|
-
end
|
146
|
-
end
|
147
|
-
q.each_item
|
148
|
-
end
|
149
|
-
|
150
|
-
def half_duplex_call(reqs)
|
151
|
-
# TODO: update with unique behaviour of the half_duplex_call if that's
|
152
|
-
# ever required by any of the tests.
|
153
|
-
full_duplex_call(reqs)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# validates the the command line options, returning them as a Hash.
|
158
|
-
def parse_options
|
159
|
-
options = {
|
160
|
-
'port' => nil,
|
161
|
-
'secure' => false
|
162
|
-
}
|
163
|
-
OptionParser.new do |opts|
|
164
|
-
opts.banner = 'Usage: --port port'
|
165
|
-
opts.on('--port PORT', 'server port') do |v|
|
166
|
-
options['port'] = v
|
167
|
-
end
|
168
|
-
opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
|
169
|
-
options['secure'] = v
|
170
|
-
end
|
171
|
-
end.parse!
|
172
|
-
|
173
|
-
if options['port'].nil?
|
174
|
-
fail(OptionParser::MissingArgument, 'please specify --port')
|
175
|
-
end
|
176
|
-
options
|
177
|
-
end
|
178
|
-
|
179
|
-
def main
|
180
|
-
opts = parse_options
|
181
|
-
host = "0.0.0.0:#{opts['port']}"
|
182
|
-
s = GRPC::RpcServer.new
|
183
|
-
if opts['secure']
|
184
|
-
s.add_http2_port(host, test_server_creds)
|
185
|
-
GRPC.logger.info("... running securely on #{host}")
|
186
|
-
else
|
187
|
-
s.add_http2_port(host)
|
188
|
-
GRPC.logger.info("... running insecurely on #{host}")
|
189
|
-
end
|
190
|
-
s.handle(TestTarget)
|
191
|
-
s.run_till_terminated
|
192
|
-
end
|
47
|
+
pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
|
48
|
+
$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
|
193
49
|
|
194
|
-
|
50
|
+
require 'test/server'
|