xref: /aosp_15_r20/external/grpc-grpc/src/ruby/spec/debug_message_spec.rb (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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
15require 'spec_helper'
16
17TEST_DEBUG_MESSAGE = 'raised by test server'.freeze
18
19# a test service that checks the cert of its peer
20class 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
35end
36
37DebugMessageTestServiceStub = DebugMessageTestService.rpc_stub_class
38
39describe '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
134end
135