grpc 1.27.0.pre1-x64-mingw32 → 1.30.0.pre1-x64-mingw32
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/grpc_c.32.ruby +0 -0
- data/grpc_c.64.ruby +0 -0
- data/src/ruby/ext/grpc/rb_call.c +9 -1
- data/src/ruby/lib/grpc/2.3/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.4/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.5/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.6/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/errors.rb +103 -42
- data/src/ruby/lib/grpc/generic/active_call.rb +2 -3
- data/src/ruby/lib/grpc/generic/interceptors.rb +4 -4
- data/src/ruby/lib/grpc/generic/rpc_server.rb +9 -10
- data/src/ruby/lib/grpc/generic/service.rb +5 -4
- data/src/ruby/lib/grpc/structs.rb +1 -1
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/pb/generate_proto_ruby.sh +5 -3
- data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +11 -0
- data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +16 -0
- data/src/ruby/pb/test/xds_client.rb +213 -0
- data/src/ruby/spec/debug_message_spec.rb +134 -0
- data/src/ruby/spec/generic/service_spec.rb +2 -0
- data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +5 -0
- data/src/ruby/spec/pb/codegen/package_option_spec.rb +2 -0
- data/src/ruby/spec/testdata/ca.pem +18 -13
- data/src/ruby/spec/testdata/client.key +26 -14
- data/src/ruby/spec/testdata/client.pem +18 -12
- data/src/ruby/spec/testdata/server1.key +26 -14
- data/src/ruby/spec/testdata/server1.pem +20 -14
- metadata +41 -37
@@ -14,11 +14,13 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
16
|
# Regenerates gRPC service stubs from proto files.
|
17
|
-
set
|
17
|
+
set -e
|
18
18
|
cd $(dirname $0)/../../..
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
# protoc and grpc_*_plugin binaries can be obtained by running
|
21
|
+
# $ bazel build @com_google_protobuf//:protoc //src/compiler:all
|
22
|
+
PROTOC=bazel-bin/external/com_google_protobuf/protoc
|
23
|
+
PLUGIN=protoc-gen-grpc=bazel-bin/src/compiler/grpc_ruby_plugin
|
22
24
|
|
23
25
|
$PROTOC -I src/proto src/proto/grpc/health/v1/health.proto \
|
24
26
|
--grpc_out=src/ruby/pb \
|
@@ -34,6 +34,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
34
34
|
optional :oauth_scope, :string, 3
|
35
35
|
optional :server_id, :string, 4
|
36
36
|
optional :grpclb_route_type, :enum, 5, "grpc.testing.GrpclbRouteType"
|
37
|
+
optional :hostname, :string, 6
|
37
38
|
end
|
38
39
|
add_message "grpc.testing.StreamingInputCallRequest" do
|
39
40
|
optional :payload, :message, 1, "grpc.testing.Payload"
|
@@ -63,6 +64,14 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
63
64
|
optional :passed, :bool, 1
|
64
65
|
repeated :backoff_ms, :int32, 2
|
65
66
|
end
|
67
|
+
add_message "grpc.testing.LoadBalancerStatsRequest" do
|
68
|
+
optional :num_rpcs, :int32, 1
|
69
|
+
optional :timeout_sec, :int32, 2
|
70
|
+
end
|
71
|
+
add_message "grpc.testing.LoadBalancerStatsResponse" do
|
72
|
+
map :rpcs_by_peer, :string, :int32, 1
|
73
|
+
optional :num_failures, :int32, 2
|
74
|
+
end
|
66
75
|
add_enum "grpc.testing.PayloadType" do
|
67
76
|
value :COMPRESSABLE, 0
|
68
77
|
end
|
@@ -88,6 +97,8 @@ module Grpc
|
|
88
97
|
StreamingOutputCallResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
|
89
98
|
ReconnectParams = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectParams").msgclass
|
90
99
|
ReconnectInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
|
100
|
+
LoadBalancerStatsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsRequest").msgclass
|
101
|
+
LoadBalancerStatsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsResponse").msgclass
|
91
102
|
PayloadType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
|
92
103
|
GrpclbRouteType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GrpclbRouteType").enummodule
|
93
104
|
end
|
@@ -96,6 +96,22 @@ module Grpc
|
|
96
96
|
rpc :Stop, Empty, ReconnectInfo
|
97
97
|
end
|
98
98
|
|
99
|
+
Stub = Service.rpc_stub_class
|
100
|
+
end
|
101
|
+
module LoadBalancerStatsService
|
102
|
+
# A service used to obtain stats for verifying LB behavior.
|
103
|
+
class Service
|
104
|
+
|
105
|
+
include GRPC::GenericService
|
106
|
+
|
107
|
+
self.marshal_class_method = :encode
|
108
|
+
self.unmarshal_class_method = :decode
|
109
|
+
self.service_name = 'grpc.testing.LoadBalancerStatsService'
|
110
|
+
|
111
|
+
# Gets the backend distribution for RPCs sent by a test client.
|
112
|
+
rpc :GetClientStats, LoadBalancerStatsRequest, LoadBalancerStatsResponse
|
113
|
+
end
|
114
|
+
|
99
115
|
Stub = Service.rpc_stub_class
|
100
116
|
end
|
101
117
|
end
|
@@ -0,0 +1,213 @@
|
|
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
|
+
# Some global variables to be shared by server and client
|
43
|
+
$watchers = Array.new
|
44
|
+
$watchers_mutex = Mutex.new
|
45
|
+
$watchers_cv = ConditionVariable.new
|
46
|
+
$shutdown = false
|
47
|
+
|
48
|
+
# RubyLogger defines a logger for gRPC based on the standard ruby logger.
|
49
|
+
module RubyLogger
|
50
|
+
def logger
|
51
|
+
LOGGER
|
52
|
+
end
|
53
|
+
|
54
|
+
LOGGER = Logger.new(STDOUT)
|
55
|
+
LOGGER.level = Logger::INFO
|
56
|
+
end
|
57
|
+
|
58
|
+
# GRPC is the general RPC module
|
59
|
+
module GRPC
|
60
|
+
# Inject the noop #logger if no module-level logger method has been injected.
|
61
|
+
extend RubyLogger
|
62
|
+
end
|
63
|
+
|
64
|
+
# creates a test stub
|
65
|
+
def create_stub(opts)
|
66
|
+
address = "#{opts.server}"
|
67
|
+
GRPC.logger.info("... connecting insecurely to #{address}")
|
68
|
+
Grpc::Testing::TestService::Stub.new(
|
69
|
+
address,
|
70
|
+
:this_channel_is_insecure,
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
# This implements LoadBalancerStatsService required by the test runner
|
75
|
+
class TestTarget < Grpc::Testing::LoadBalancerStatsService::Service
|
76
|
+
include Grpc::Testing
|
77
|
+
|
78
|
+
def get_client_stats(req, _call)
|
79
|
+
finish_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) +
|
80
|
+
req['timeout_sec']
|
81
|
+
watcher = {}
|
82
|
+
$watchers_mutex.synchronize do
|
83
|
+
watcher = {
|
84
|
+
"rpcs_by_peer" => Hash.new(0),
|
85
|
+
"rpcs_needed" => req['num_rpcs'],
|
86
|
+
"no_remote_peer" => 0
|
87
|
+
}
|
88
|
+
$watchers << watcher
|
89
|
+
seconds_remaining = finish_time -
|
90
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
91
|
+
while watcher['rpcs_needed'] > 0 && seconds_remaining > 0
|
92
|
+
$watchers_cv.wait($watchers_mutex, seconds_remaining)
|
93
|
+
seconds_remaining = finish_time -
|
94
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
95
|
+
end
|
96
|
+
$watchers.delete_at($watchers.index(watcher))
|
97
|
+
end
|
98
|
+
LoadBalancerStatsResponse.new(
|
99
|
+
rpcs_by_peer: watcher['rpcs_by_peer'],
|
100
|
+
num_failures: watcher['no_remote_peer'] + watcher['rpcs_needed']
|
101
|
+
);
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# send 1 rpc every 1/qps second
|
106
|
+
def run_test_loop(stub, target_seconds_between_rpcs, fail_on_failed_rpcs)
|
107
|
+
include Grpc::Testing
|
108
|
+
req = SimpleRequest.new()
|
109
|
+
target_next_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
110
|
+
while !$shutdown
|
111
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
112
|
+
sleep_seconds = target_next_start - now
|
113
|
+
if sleep_seconds < 0
|
114
|
+
target_next_start = now + target_seconds_between_rpcs
|
115
|
+
GRPC.logger.info(
|
116
|
+
"ruby xds: warning, rpc takes too long to finish. " \
|
117
|
+
"Deficit = %.1fms. " \
|
118
|
+
"If you consistently see this, the qps is too high." \
|
119
|
+
% [(sleep_seconds * 1000).abs().round(1)])
|
120
|
+
else
|
121
|
+
target_next_start += target_seconds_between_rpcs
|
122
|
+
sleep(sleep_seconds)
|
123
|
+
end
|
124
|
+
begin
|
125
|
+
deadline = GRPC::Core::TimeConsts::from_relative_time(30) # 30 seconds
|
126
|
+
resp = stub.unary_call(req, deadline: deadline)
|
127
|
+
remote_peer = resp.hostname
|
128
|
+
rescue GRPC::BadStatus => e
|
129
|
+
remote_peer = ""
|
130
|
+
GRPC.logger.info("ruby xds: rpc failed:|#{e.message}|, " \
|
131
|
+
"this may or may not be expected")
|
132
|
+
if fail_on_failed_rpcs
|
133
|
+
raise e
|
134
|
+
end
|
135
|
+
end
|
136
|
+
$watchers_mutex.synchronize do
|
137
|
+
$watchers.each do |watcher|
|
138
|
+
watcher['rpcs_needed'] -= 1
|
139
|
+
if remote_peer.strip.empty?
|
140
|
+
watcher['no_remote_peer'] += 1
|
141
|
+
else
|
142
|
+
watcher['rpcs_by_peer'][remote_peer] += 1
|
143
|
+
end
|
144
|
+
end
|
145
|
+
$watchers_cv.broadcast
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Args is used to hold the command line info.
|
151
|
+
Args = Struct.new(:fail_on_failed_rpcs, :num_channels,
|
152
|
+
:server, :stats_port, :qps)
|
153
|
+
|
154
|
+
# validates the command line options, returning them as a Hash.
|
155
|
+
def parse_args
|
156
|
+
args = Args.new
|
157
|
+
args['fail_on_failed_rpcs'] = false
|
158
|
+
args['num_channels'] = 1
|
159
|
+
OptionParser.new do |opts|
|
160
|
+
opts.on('--fail_on_failed_rpcs BOOL', ['false', 'true']) do |v|
|
161
|
+
args['fail_on_failed_rpcs'] = v == 'true'
|
162
|
+
end
|
163
|
+
opts.on('--num_channels CHANNELS', 'number of channels') do |v|
|
164
|
+
args['num_channels'] = v.to_i
|
165
|
+
end
|
166
|
+
opts.on('--server SERVER_HOST', 'server hostname') do |v|
|
167
|
+
GRPC.logger.info("ruby xds: server address is #{v}")
|
168
|
+
args['server'] = v
|
169
|
+
end
|
170
|
+
opts.on('--stats_port STATS_PORT', 'stats port') do |v|
|
171
|
+
GRPC.logger.info("ruby xds: stats port is #{v}")
|
172
|
+
args['stats_port'] = v
|
173
|
+
end
|
174
|
+
opts.on('--qps QPS', 'qps') do |v|
|
175
|
+
GRPC.logger.info("ruby xds: qps is #{v}")
|
176
|
+
args['qps'] = v
|
177
|
+
end
|
178
|
+
end.parse!
|
179
|
+
args
|
180
|
+
end
|
181
|
+
|
182
|
+
def main
|
183
|
+
opts = parse_args
|
184
|
+
|
185
|
+
# This server hosts the LoadBalancerStatsService
|
186
|
+
host = "0.0.0.0:#{opts['stats_port']}"
|
187
|
+
s = GRPC::RpcServer.new
|
188
|
+
s.add_http2_port(host, :this_port_is_insecure)
|
189
|
+
s.handle(TestTarget)
|
190
|
+
server_thread = Thread.new {
|
191
|
+
# run the server until the main test runner terminates this process
|
192
|
+
s.run_till_terminated_or_interrupted(['TERM'])
|
193
|
+
}
|
194
|
+
|
195
|
+
# The client just sends unary rpcs continuously in a regular interval
|
196
|
+
stub = create_stub(opts)
|
197
|
+
target_seconds_between_rpcs = (1.0 / opts['qps'].to_f)
|
198
|
+
client_threads = Array.new
|
199
|
+
opts['num_channels'].times {
|
200
|
+
client_threads << Thread.new {
|
201
|
+
run_test_loop(stub, target_seconds_between_rpcs,
|
202
|
+
opts['fail_on_failed_rpcs'])
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
server_thread.join
|
207
|
+
$shutdown = true
|
208
|
+
client_threads.each { |thd| thd.join }
|
209
|
+
end
|
210
|
+
|
211
|
+
if __FILE__ == $0
|
212
|
+
main
|
213
|
+
end
|
@@ -0,0 +1,134 @@
|
|
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
|
+
TEST_DEBUG_MESSAGE = 'raised by test server'.freeze
|
18
|
+
|
19
|
+
# a test service that checks the cert of its peer
|
20
|
+
class DebugMessageTestService
|
21
|
+
include GRPC::GenericService
|
22
|
+
rpc :an_rpc_raises_abort, EchoMsg, EchoMsg
|
23
|
+
rpc :an_rpc_raises_standarderror, EchoMsg, EchoMsg
|
24
|
+
|
25
|
+
def an_rpc_raises_abort(_req, _call)
|
26
|
+
fail GRPC::Aborted.new(
|
27
|
+
'aborted',
|
28
|
+
{},
|
29
|
+
TEST_DEBUG_MESSAGE)
|
30
|
+
end
|
31
|
+
|
32
|
+
def an_rpc_raises_standarderror(_req, _call)
|
33
|
+
fail(StandardError, TEST_DEBUG_MESSAGE)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
DebugMessageTestServiceStub = DebugMessageTestService.rpc_stub_class
|
38
|
+
|
39
|
+
describe 'surfacing and transmitting of debug messages' do
|
40
|
+
RpcServer = GRPC::RpcServer
|
41
|
+
|
42
|
+
before(:all) do
|
43
|
+
server_opts = {
|
44
|
+
poll_period: 1
|
45
|
+
}
|
46
|
+
@srv = new_rpc_server_for_testing(**server_opts)
|
47
|
+
@port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
|
48
|
+
@srv.handle(DebugMessageTestService)
|
49
|
+
@srv_thd = Thread.new { @srv.run }
|
50
|
+
@srv.wait_till_running
|
51
|
+
end
|
52
|
+
|
53
|
+
after(:all) do
|
54
|
+
expect(@srv.stopped?).to be(false)
|
55
|
+
@srv.stop
|
56
|
+
@srv_thd.join
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'debug error message is not present BadStatus exceptions that dont set it' do
|
60
|
+
exception_message = ''
|
61
|
+
begin
|
62
|
+
fail GRPC::Unavailable('unavailable', {})
|
63
|
+
rescue StandardError => e
|
64
|
+
p "Got exception: #{e.message}"
|
65
|
+
exception_message = e.message
|
66
|
+
end
|
67
|
+
expect(exception_message.empty?).to be(false)
|
68
|
+
expect(exception_message.include?('debug_error_string')).to be(false)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'debug error message is present in locally generated errors' do
|
72
|
+
# Create a secure channel. This is just one way to force a
|
73
|
+
# connection handshake error, which shoud result in C-core
|
74
|
+
# generating a status and error message and surfacing them up.
|
75
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
76
|
+
files = ['ca.pem', 'client.key', 'client.pem']
|
77
|
+
creds = files.map { |f| File.open(File.join(test_root, f)).read }
|
78
|
+
creds = GRPC::Core::ChannelCredentials.new(creds[0], creds[1], creds[2])
|
79
|
+
stub = DebugMessageTestServiceStub.new(
|
80
|
+
"localhost:#{@port}", creds)
|
81
|
+
begin
|
82
|
+
stub.an_rpc_raises_abort(EchoMsg.new)
|
83
|
+
rescue StandardError => e
|
84
|
+
p "Got exception: #{e.message}"
|
85
|
+
exception_message = e.message
|
86
|
+
# check that the RPC did actually result in a BadStatus exception
|
87
|
+
expect(e.is_a?(GRPC::BadStatus)).to be(true)
|
88
|
+
end
|
89
|
+
# just check that the debug_error_string is non-empty (we know that
|
90
|
+
# it's a JSON object, so the first character is '{').
|
91
|
+
expect(exception_message.include?('. debug_error_string:{')).to be(true)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'debug message is not transmitted from server to client' do
|
95
|
+
# in order to not accidentally leak internal details about a
|
96
|
+
# server to untrusted clients, avoid including the debug_error_string
|
97
|
+
# field of a BadStatusException raised at a server in the
|
98
|
+
# RPC status that it sends to clients.
|
99
|
+
stub = DebugMessageTestServiceStub.new(
|
100
|
+
"localhost:#{@port}", :this_channel_is_insecure)
|
101
|
+
exception_message = ''
|
102
|
+
begin
|
103
|
+
stub.an_rpc_raises_abort(EchoMsg.new)
|
104
|
+
rescue StandardError => e
|
105
|
+
p "Got exception: #{e.message}"
|
106
|
+
exception_message = e.message
|
107
|
+
# check that the status was aborted is an indirect way to
|
108
|
+
# tell that the RPC did actually get handled by the server
|
109
|
+
expect(e.is_a?(GRPC::Aborted)).to be(true)
|
110
|
+
end
|
111
|
+
# just assert that the contents of the server-side BadStatus
|
112
|
+
# debug_error_string field were *not* propagated to the client.
|
113
|
+
expect(exception_message.include?('. debug_error_string:{')).to be(true)
|
114
|
+
expect(exception_message.include?(TEST_DEBUG_MESSAGE)).to be(false)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'standard_error messages are transmitted from server to client' do
|
118
|
+
# this test exists mostly in order to understand the test case
|
119
|
+
# above, by comparison.
|
120
|
+
stub = DebugMessageTestServiceStub.new(
|
121
|
+
"localhost:#{@port}", :this_channel_is_insecure)
|
122
|
+
exception_message = ''
|
123
|
+
begin
|
124
|
+
stub.an_rpc_raises_standarderror(EchoMsg.new)
|
125
|
+
rescue StandardError => e
|
126
|
+
p "Got exception: #{e.message}"
|
127
|
+
exception_message = e.message
|
128
|
+
expect(e.is_a?(GRPC::BadStatus)).to be(true)
|
129
|
+
end
|
130
|
+
# assert that the contents of the StandardError exception message
|
131
|
+
# are propagated to the client.
|
132
|
+
expect(exception_message.include?(TEST_DEBUG_MESSAGE)).to be(true)
|
133
|
+
end
|
134
|
+
end
|
@@ -55,6 +55,8 @@ describe GenericService do
|
|
55
55
|
expect(GenericService.underscore('AMethod')).to eq('a_method')
|
56
56
|
expect(GenericService.underscore('PrintHTML')).to eq('print_html')
|
57
57
|
expect(GenericService.underscore('SeeHTMLBooks')).to eq('see_html_books')
|
58
|
+
|
59
|
+
expect(GenericService.underscore('SeeHTMLBooks'.freeze)).to eq('see_html_books')
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
@@ -27,8 +27,13 @@ message AnotherTestResponse { }
|
|
27
27
|
|
28
28
|
message Foo { }
|
29
29
|
|
30
|
+
message Bar {
|
31
|
+
message Baz { }
|
32
|
+
}
|
33
|
+
|
30
34
|
service AnotherTestService {
|
31
35
|
rpc GetTest(AnotherTestRequest) returns (AnotherTestResponse) { }
|
32
36
|
rpc OtherTest(Thing) returns (Thing) { }
|
33
37
|
rpc FooTest(Foo) returns (Foo) { }
|
38
|
+
rpc NestedMessageTest(Foo) returns (Bar.Baz) { }
|
34
39
|
}
|