_grpc_status_test.py
Go to the documentation of this file.
1 # Copyright 2018 The 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 """Tests of grpc_status.
15 
16 isort:skip_file
17 """
18 
19 # NOTE(lidiz) This module only exists in Bazel BUILD file, for more details
20 # please refer to comments in the "bazel_namespace_package_hack" module.
21 try:
22  from tests import bazel_namespace_package_hack
23  bazel_namespace_package_hack.sys_path_to_site_dir_hack()
24 except ImportError:
25  pass
26 
27 import unittest
28 
29 import logging
30 import traceback
31 import sys
32 
33 import grpc
34 from grpc_status import rpc_status
35 
36 from tests.unit import test_common
37 
38 from google.protobuf import any_pb2
39 from google.rpc import code_pb2, status_pb2, error_details_pb2
40 
41 _STATUS_OK = '/test/StatusOK'
42 _STATUS_NOT_OK = '/test/StatusNotOk'
43 _ERROR_DETAILS = '/test/ErrorDetails'
44 _INCONSISTENT = '/test/Inconsistent'
45 _INVALID_CODE = '/test/InvalidCode'
46 
47 _REQUEST = b'\x00\x00\x00'
48 _RESPONSE = b'\x01\x01\x01'
49 
50 _GRPC_DETAILS_METADATA_KEY = 'grpc-status-details-bin'
51 
52 _STATUS_DETAILS = 'This is an error detail'
53 _STATUS_DETAILS_ANOTHER = 'This is another error detail'
54 
55 
56 def _ok_unary_unary(request, servicer_context):
57  return _RESPONSE
58 
59 
60 def _not_ok_unary_unary(request, servicer_context):
61  servicer_context.abort(grpc.StatusCode.INTERNAL, _STATUS_DETAILS)
62 
63 
64 def _error_details_unary_unary(request, servicer_context):
65  details = any_pb2.Any()
66  details.Pack(
67  error_details_pb2.DebugInfo(stack_entries=traceback.format_stack(),
68  detail='Intentionally invoked'))
69  rich_status = status_pb2.Status(
70  code=code_pb2.INTERNAL,
71  message=_STATUS_DETAILS,
72  details=[details],
73  )
74  servicer_context.abort_with_status(rpc_status.to_status(rich_status))
75 
76 
77 def _inconsistent_unary_unary(request, servicer_context):
78  rich_status = status_pb2.Status(
79  code=code_pb2.INTERNAL,
80  message=_STATUS_DETAILS,
81  )
82  servicer_context.set_code(grpc.StatusCode.NOT_FOUND)
83  servicer_context.set_details(_STATUS_DETAILS_ANOTHER)
84  # User put inconsistent status information in trailing metadata
85  servicer_context.set_trailing_metadata(
86  ((_GRPC_DETAILS_METADATA_KEY, rich_status.SerializeToString()),))
87 
88 
89 def _invalid_code_unary_unary(request, servicer_context):
90  rich_status = status_pb2.Status(
91  code=42,
92  message='Invalid code',
93  )
94  servicer_context.abort_with_status(rpc_status.to_status(rich_status))
95 
96 
98 
99  def service(self, handler_call_details):
100  if handler_call_details.method == _STATUS_OK:
101  return grpc.unary_unary_rpc_method_handler(_ok_unary_unary)
102  elif handler_call_details.method == _STATUS_NOT_OK:
103  return grpc.unary_unary_rpc_method_handler(_not_ok_unary_unary)
104  elif handler_call_details.method == _ERROR_DETAILS:
106  _error_details_unary_unary)
107  elif handler_call_details.method == _INCONSISTENT:
109  _inconsistent_unary_unary)
110  elif handler_call_details.method == _INVALID_CODE:
112  _invalid_code_unary_unary)
113  else:
114  return None
115 
116 
117 @unittest.skipIf(sys.version_info[0] < 3,
118  'ProtoBuf descriptor has moved on from Python2')
119 class StatusTest(unittest.TestCase):
120 
121  def setUp(self):
122  self._server = test_common.test_server()
123  self._server.add_generic_rpc_handlers((_GenericHandler(),))
124  port = self._server.add_insecure_port('[::]:0')
125  self._server.start()
126 
127  self._channel = grpc.insecure_channel('localhost:%d' % port)
128 
129  def tearDown(self):
130  self._server.stop(None)
131  self._channel.close()
132 
133  def test_status_ok(self):
134  _, call = self._channel.unary_unary(_STATUS_OK).with_call(_REQUEST)
135 
136  # Succeed RPC doesn't have status
137  status = rpc_status.from_call(call)
138  self.assertIs(status, None)
139 
141  with self.assertRaises(grpc.RpcError) as exception_context:
142  self._channel.unary_unary(_STATUS_NOT_OK).with_call(_REQUEST)
143  rpc_error = exception_context.exception
144 
145  self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL)
146  # Failed RPC doesn't automatically generate status
147  status = rpc_status.from_call(rpc_error)
148  self.assertIs(status, None)
149 
151  with self.assertRaises(grpc.RpcError) as exception_context:
152  self._channel.unary_unary(_ERROR_DETAILS).with_call(_REQUEST)
153  rpc_error = exception_context.exception
154 
155  status = rpc_status.from_call(rpc_error)
156  self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL)
157  self.assertEqual(status.code, code_pb2.Code.Value('INTERNAL'))
158 
159  # Check if the underlying proto message is intact
160  self.assertEqual(
161  status.details[0].Is(error_details_pb2.DebugInfo.DESCRIPTOR), True)
162  info = error_details_pb2.DebugInfo()
163  status.details[0].Unpack(info)
164  self.assertIn('_error_details_unary_unary', info.stack_entries[-1])
165 
167  with self.assertRaises(grpc.RpcError) as exception_context:
168  self._channel.unary_unary(_INCONSISTENT).with_call(_REQUEST)
169  rpc_error = exception_context.exception
170  self.assertEqual(rpc_error.code(), grpc.StatusCode.NOT_FOUND)
171 
172  # Code/Message validation failed
173  self.assertRaises(ValueError, rpc_status.from_call, rpc_error)
174 
175  def test_invalid_code(self):
176  with self.assertRaises(grpc.RpcError) as exception_context:
177  self._channel.unary_unary(_INVALID_CODE).with_call(_REQUEST)
178  rpc_error = exception_context.exception
179  self.assertEqual(rpc_error.code(), grpc.StatusCode.UNKNOWN)
180  # Invalid status code exception raised during coversion
181  self.assertIn('Invalid status code', rpc_error.details())
182 
183 
184 if __name__ == '__main__':
185  logging.basicConfig()
186  unittest.main(verbosity=2)
grpc.unary_unary_rpc_method_handler
def unary_unary_rpc_method_handler(behavior, request_deserializer=None, response_serializer=None)
Definition: src/python/grpcio/grpc/__init__.py:1510
grpc.insecure_channel
def insecure_channel(target, options=None, compression=None)
Definition: src/python/grpcio/grpc/__init__.py:1962
tests.status._grpc_status_test.StatusTest._channel
_channel
Definition: _grpc_status_test.py:127
tests.status._grpc_status_test.StatusTest.test_error_details
def test_error_details(self)
Definition: _grpc_status_test.py:150
tests.status._grpc_status_test.StatusTest.test_status_not_ok
def test_status_not_ok(self)
Definition: _grpc_status_test.py:140
tests.status._grpc_status_test.StatusTest.tearDown
def tearDown(self)
Definition: _grpc_status_test.py:129
tests.status._grpc_status_test._GenericHandler
Definition: _grpc_status_test.py:97
tests.status._grpc_status_test.StatusTest
Definition: _grpc_status_test.py:119
tests.status._grpc_status_test.StatusTest.test_code_message_validation
def test_code_message_validation(self)
Definition: _grpc_status_test.py:166
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
tests.status._grpc_status_test._inconsistent_unary_unary
def _inconsistent_unary_unary(request, servicer_context)
Definition: _grpc_status_test.py:77
grpc.RpcError
Definition: src/python/grpcio/grpc/__init__.py:302
tests.status._grpc_status_test._GenericHandler.service
def service(self, handler_call_details)
Definition: _grpc_status_test.py:99
tests.status._grpc_status_test._not_ok_unary_unary
def _not_ok_unary_unary(request, servicer_context)
Definition: _grpc_status_test.py:60
start
static uint64_t start
Definition: benchmark-pound.c:74
grpc.GenericRpcHandler
Definition: src/python/grpcio/grpc/__init__.py:1333
close
#define close
Definition: test-fs.c:48
grpc._simple_stubs.unary_unary
ResponseType unary_unary(RequestType request, str target, str method, Optional[Callable[[Any], bytes]] request_serializer=None, Optional[Callable[[bytes], Any]] response_deserializer=None, Sequence[Tuple[AnyStr, AnyStr]] options=(), Optional[grpc.ChannelCredentials] channel_credentials=None, bool insecure=False, Optional[grpc.CallCredentials] call_credentials=None, Optional[grpc.Compression] compression=None, Optional[bool] wait_for_ready=None, Optional[float] timeout=_DEFAULT_TIMEOUT, Optional[Sequence[Tuple[str, Union[str, bytes]]]] metadata=None)
Definition: _simple_stubs.py:169
tests.unit
Definition: src/python/grpcio_tests/tests/unit/__init__.py:1
tests.status._grpc_status_test.StatusTest._server
_server
Definition: _grpc_status_test.py:122
tests.status._grpc_status_test.StatusTest.setUp
def setUp(self)
Definition: _grpc_status_test.py:121
tests.status._grpc_status_test.StatusTest.test_status_ok
def test_status_ok(self)
Definition: _grpc_status_test.py:133
tests.status._grpc_status_test._error_details_unary_unary
def _error_details_unary_unary(request, servicer_context)
Definition: _grpc_status_test.py:64
tests.status._grpc_status_test._invalid_code_unary_unary
def _invalid_code_unary_unary(request, servicer_context)
Definition: _grpc_status_test.py:89
tests.status._grpc_status_test._ok_unary_unary
def _ok_unary_unary(request, servicer_context)
Definition: _grpc_status_test.py:56
stop
static const char stop[]
Definition: benchmark-async-pummel.c:35
tests.status._grpc_status_test.StatusTest.test_invalid_code
def test_invalid_code(self)
Definition: _grpc_status_test.py:175


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:27