grpc 1.28.0-universal-darwin → 1.31.0.pre1-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/src/ruby/ext/grpc/extconf.rb +5 -2
  3. data/src/ruby/ext/grpc/rb_call.c +12 -3
  4. data/src/ruby/ext/grpc/rb_call.h +4 -0
  5. data/src/ruby/ext/grpc/rb_call_credentials.c +57 -12
  6. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +4 -0
  7. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +6 -0
  8. data/src/ruby/lib/grpc/2.3/grpc_c.bundle +0 -0
  9. data/src/ruby/lib/grpc/2.4/grpc_c.bundle +0 -0
  10. data/src/ruby/lib/grpc/2.5/grpc_c.bundle +0 -0
  11. data/src/ruby/lib/grpc/2.6/grpc_c.bundle +0 -0
  12. data/src/ruby/lib/grpc/2.7/grpc_c.bundle +0 -0
  13. data/src/ruby/lib/grpc/errors.rb +103 -42
  14. data/src/ruby/lib/grpc/generic/active_call.rb +2 -3
  15. data/src/ruby/lib/grpc/generic/interceptors.rb +5 -5
  16. data/src/ruby/lib/grpc/generic/rpc_server.rb +9 -10
  17. data/src/ruby/lib/grpc/generic/service.rb +5 -4
  18. data/src/ruby/lib/grpc/structs.rb +1 -1
  19. data/src/ruby/lib/grpc/version.rb +1 -1
  20. data/src/ruby/pb/generate_proto_ruby.sh +5 -3
  21. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +11 -0
  22. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +16 -0
  23. data/src/ruby/pb/test/xds_client.rb +213 -0
  24. data/src/ruby/spec/debug_message_spec.rb +134 -0
  25. data/src/ruby/spec/generic/service_spec.rb +2 -0
  26. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  27. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +7 -0
  28. data/src/ruby/spec/pb/codegen/package_option_spec.rb +7 -1
  29. data/src/ruby/spec/support/services.rb +10 -4
  30. data/src/ruby/spec/testdata/ca.pem +18 -13
  31. data/src/ruby/spec/testdata/client.key +26 -14
  32. data/src/ruby/spec/testdata/client.pem +18 -12
  33. data/src/ruby/spec/testdata/server1.key +26 -14
  34. data/src/ruby/spec/testdata/server1.pem +20 -14
  35. metadata +45 -40
@@ -23,13 +23,12 @@ class Struct
23
23
  # is non-nil and not OK.
24
24
  def check_status
25
25
  return nil if status.nil?
26
- fail GRPC::Cancelled if status.code == GRPC::Core::StatusCodes::CANCELLED
27
26
  if status.code != GRPC::Core::StatusCodes::OK
28
27
  GRPC.logger.debug("Failing with status #{status}")
29
28
  # raise BadStatus, propagating the metadata if present.
30
- md = status.metadata
31
29
  fail GRPC::BadStatus.new_status_exception(
32
- status.code, status.details, md)
30
+ status.code, status.details, status.metadata,
31
+ status.debug_error_string)
33
32
  end
34
33
  status
35
34
  end
@@ -38,7 +38,7 @@ module GRPC
38
38
  #
39
39
  # @param [Object] request
40
40
  # @param [GRPC::ActiveCall] call
41
- # @param [Method] method
41
+ # @param [String] method
42
42
  # @param [Hash] metadata
43
43
  #
44
44
  def request_response(request: nil, call: nil, method: nil, metadata: nil)
@@ -52,7 +52,7 @@ module GRPC
52
52
  #
53
53
  # @param [Enumerable] requests
54
54
  # @param [GRPC::ActiveCall] call
55
- # @param [Method] method
55
+ # @param [String] method
56
56
  # @param [Hash] metadata
57
57
  #
58
58
  def client_streamer(requests: nil, call: nil, method: nil, metadata: nil)
@@ -66,7 +66,7 @@ module GRPC
66
66
  #
67
67
  # @param [Object] request
68
68
  # @param [GRPC::ActiveCall] call
69
- # @param [Method] method
69
+ # @param [String] method
70
70
  # @param [Hash] metadata
71
71
  #
72
72
  def server_streamer(request: nil, call: nil, method: nil, metadata: nil)
@@ -80,7 +80,7 @@ module GRPC
80
80
  #
81
81
  # @param [Enumerable] requests
82
82
  # @param [GRPC::ActiveCall] call
83
- # @param [Method] method
83
+ # @param [String] method
84
84
  # @param [Hash] metadata
85
85
  #
86
86
  def bidi_streamer(requests: nil, call: nil, method: nil, metadata: nil)
@@ -172,7 +172,7 @@ module GRPC
172
172
  i = @interceptors.pop
173
173
  return yield unless i
174
174
 
175
- i.send(type, args) do
175
+ i.send(type, **args) do
176
176
  if @interceptors.any?
177
177
  intercept!(type, args) do
178
178
  yield
@@ -391,22 +391,21 @@ module GRPC
391
391
  # register signal handlers
392
392
  signals.each do |sig|
393
393
  # input validation
394
- if sig.class == String
395
- sig.upcase!
396
- if sig.start_with?('SIG')
397
- # cut out the SIG prefix to see if valid signal
398
- sig = sig[3..-1]
399
- end
400
- end
394
+ target_sig = if sig.class == String
395
+ # cut out the SIG prefix to see if valid signal
396
+ sig.upcase.start_with?('SIG') ? sig.upcase[3..-1] : sig.upcase
397
+ else
398
+ sig
399
+ end
401
400
 
402
401
  # register signal traps for all valid signals
403
- if valid_signals.value?(sig) || valid_signals.key?(sig)
404
- Signal.trap(sig) do
402
+ if valid_signals.value?(target_sig) || valid_signals.key?(target_sig)
403
+ Signal.trap(target_sig) do
405
404
  @stop_server = true
406
405
  @stop_server_cv.broadcast
407
406
  end
408
407
  else
409
- fail "#{sig} not a valid signal"
408
+ fail "#{target_sig} not a valid signal"
410
409
  end
411
410
  end
412
411
 
@@ -31,6 +31,7 @@ module GRPC
31
31
  #
32
32
  # @param s [String] the string to be converted.
33
33
  def self.underscore(s)
34
+ s = +s # Avoid mutating the argument, as it might be frozen.
34
35
  s.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
35
36
  s.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
36
37
  s.tr!('-', '_')
@@ -167,22 +168,22 @@ module GRPC
167
168
  if desc.request_response?
168
169
  define_method(mth_name) do |req, metadata = {}|
169
170
  GRPC.logger.debug("calling #{@host}:#{route}")
170
- request_response(route, req, marshal, unmarshal, metadata)
171
+ request_response(route, req, marshal, unmarshal, **metadata)
171
172
  end
172
173
  elsif desc.client_streamer?
173
174
  define_method(mth_name) do |reqs, metadata = {}|
174
175
  GRPC.logger.debug("calling #{@host}:#{route}")
175
- client_streamer(route, reqs, marshal, unmarshal, metadata)
176
+ client_streamer(route, reqs, marshal, unmarshal, **metadata)
176
177
  end
177
178
  elsif desc.server_streamer?
178
179
  define_method(mth_name) do |req, metadata = {}, &blk|
179
180
  GRPC.logger.debug("calling #{@host}:#{route}")
180
- server_streamer(route, req, marshal, unmarshal, metadata, &blk)
181
+ server_streamer(route, req, marshal, unmarshal, **metadata, &blk)
181
182
  end
182
183
  else # is a bidi_stream
183
184
  define_method(mth_name) do |reqs, metadata = {}, &blk|
184
185
  GRPC.logger.debug("calling #{@host}:#{route}")
185
- bidi_streamer(route, reqs, marshal, unmarshal, metadata, &blk)
186
+ bidi_streamer(route, reqs, marshal, unmarshal, **metadata, &blk)
186
187
  end
187
188
  end
188
189
  end
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- Struct.new('Status', :code, :details, :metadata)
15
+ Struct.new('Status', :code, :details, :metadata, :debug_error_string)
@@ -14,5 +14,5 @@
14
14
 
15
15
  # GRPC contains the General RPC module.
16
16
  module GRPC
17
- VERSION = '1.28.0'
17
+ VERSION = '1.31.0.pre1'
18
18
  end
@@ -14,11 +14,13 @@
14
14
  # limitations under the License.
15
15
 
16
16
  # Regenerates gRPC service stubs from proto files.
17
- set +e
17
+ set -e
18
18
  cd $(dirname $0)/../../..
19
19
 
20
- PROTOC=bins/opt/protobuf/protoc
21
- PLUGIN=protoc-gen-grpc=bins/opt/grpc_ruby_plugin
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