grpc_status_test.py
Go to the documentation of this file.
1 # Copyright 2020 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 with gRPC AsyncIO stack."""
15 
16 import logging
17 import traceback
18 import unittest
19 
20 from google.protobuf import any_pb2
21 from google.rpc import code_pb2
22 from google.rpc import error_details_pb2
23 from google.rpc import status_pb2
24 import grpc
25 from grpc.experimental import aio
26 from grpc_status import rpc_status
27 
28 from tests_aio.unit._test_base import AioTestBase
29 
30 _STATUS_OK = '/test/StatusOK'
31 _STATUS_NOT_OK = '/test/StatusNotOk'
32 _ERROR_DETAILS = '/test/ErrorDetails'
33 _INCONSISTENT = '/test/Inconsistent'
34 _INVALID_CODE = '/test/InvalidCode'
35 
36 _REQUEST = b'\x00\x00\x00'
37 _RESPONSE = b'\x01\x01\x01'
38 
39 _GRPC_DETAILS_METADATA_KEY = 'grpc-status-details-bin'
40 
41 _STATUS_DETAILS = 'This is an error detail'
42 _STATUS_DETAILS_ANOTHER = 'This is another error detail'
43 
44 
45 async def _ok_unary_unary(request, servicer_context):
46  return _RESPONSE
47 
48 
49 async def _not_ok_unary_unary(request, servicer_context):
50  await servicer_context.abort(grpc.StatusCode.INTERNAL, _STATUS_DETAILS)
51 
52 
53 async def _error_details_unary_unary(request, servicer_context):
54  details = any_pb2.Any()
55  details.Pack(
56  error_details_pb2.DebugInfo(stack_entries=traceback.format_stack(),
57  detail='Intentionally invoked'))
58  rich_status = status_pb2.Status(
59  code=code_pb2.INTERNAL,
60  message=_STATUS_DETAILS,
61  details=[details],
62  )
63  await servicer_context.abort_with_status(rpc_status.to_status(rich_status))
64 
65 
66 async def _inconsistent_unary_unary(request, servicer_context):
67  rich_status = status_pb2.Status(
68  code=code_pb2.INTERNAL,
69  message=_STATUS_DETAILS,
70  )
71  servicer_context.set_code(grpc.StatusCode.NOT_FOUND)
72  servicer_context.set_details(_STATUS_DETAILS_ANOTHER)
73  # User put inconsistent status information in trailing metadata
74  servicer_context.set_trailing_metadata(
75  ((_GRPC_DETAILS_METADATA_KEY, rich_status.SerializeToString()),))
76 
77 
78 async def _invalid_code_unary_unary(request, servicer_context):
79  rich_status = status_pb2.Status(
80  code=42,
81  message='Invalid code',
82  )
83  await servicer_context.abort_with_status(rpc_status.to_status(rich_status))
84 
85 
87 
88  def service(self, handler_call_details):
89  if handler_call_details.method == _STATUS_OK:
90  return grpc.unary_unary_rpc_method_handler(_ok_unary_unary)
91  elif handler_call_details.method == _STATUS_NOT_OK:
92  return grpc.unary_unary_rpc_method_handler(_not_ok_unary_unary)
93  elif handler_call_details.method == _ERROR_DETAILS:
95  _error_details_unary_unary)
96  elif handler_call_details.method == _INCONSISTENT:
98  _inconsistent_unary_unary)
99  elif handler_call_details.method == _INVALID_CODE:
101  _invalid_code_unary_unary)
102  else:
103  return None
104 
105 
107 
108  async def setUp(self):
109  self._server = aio.server()
110  self._server.add_generic_rpc_handlers((_GenericHandler(),))
111  port = self._server.add_insecure_port('[::]:0')
112  await self._server.start()
113 
114  self._channel = aio.insecure_channel('localhost:%d' % port)
115 
116  async def tearDown(self):
117  await self._server.stop(None)
118  await self._channel.close()
119 
120  async def test_status_ok(self):
121  call = self._channel.unary_unary(_STATUS_OK)(_REQUEST)
122 
123  # Succeed RPC doesn't have status
124  status = await rpc_status.aio.from_call(call)
125  self.assertIs(status, None)
126 
127  async def test_status_not_ok(self):
128  call = self._channel.unary_unary(_STATUS_NOT_OK)(_REQUEST)
129  with self.assertRaises(aio.AioRpcError) as exception_context:
130  await call
131  rpc_error = exception_context.exception
132 
133  self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL)
134  # Failed RPC doesn't automatically generate status
135  status = await rpc_status.aio.from_call(call)
136  self.assertIs(status, None)
137 
138  async def test_error_details(self):
139  call = self._channel.unary_unary(_ERROR_DETAILS)(_REQUEST)
140  with self.assertRaises(aio.AioRpcError) as exception_context:
141  await call
142  rpc_error = exception_context.exception
143 
144  status = await rpc_status.aio.from_call(call)
145  self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL)
146  self.assertEqual(status.code, code_pb2.Code.Value('INTERNAL'))
147 
148  # Check if the underlying proto message is intact
149  self.assertTrue(status.details[0].Is(
150  error_details_pb2.DebugInfo.DESCRIPTOR))
151  info = error_details_pb2.DebugInfo()
152  status.details[0].Unpack(info)
153  self.assertIn('_error_details_unary_unary', info.stack_entries[-1])
154 
156  call = self._channel.unary_unary(_INCONSISTENT)(_REQUEST)
157  with self.assertRaises(aio.AioRpcError) as exception_context:
158  await call
159  rpc_error = exception_context.exception
160  self.assertEqual(rpc_error.code(), grpc.StatusCode.NOT_FOUND)
161 
162  # Code/Message validation failed
163  with self.assertRaises(ValueError):
164  await rpc_status.aio.from_call(call)
165 
166  async def test_invalid_code(self):
167  with self.assertRaises(aio.AioRpcError) as exception_context:
168  await self._channel.unary_unary(_INVALID_CODE)(_REQUEST)
169  rpc_error = exception_context.exception
170  self.assertEqual(rpc_error.code(), grpc.StatusCode.UNKNOWN)
171  # Invalid status code exception raised during coversion
172  self.assertIn('Invalid status code', rpc_error.details())
173 
174 
175 if __name__ == '__main__':
176  logging.basicConfig()
177  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
tests_aio.status.grpc_status_test._ok_unary_unary
def _ok_unary_unary(request, servicer_context)
Definition: grpc_status_test.py:45
tests_aio.status.grpc_status_test._GenericHandler.service
def service(self, handler_call_details)
Definition: grpc_status_test.py:88
tests_aio.status.grpc_status_test._inconsistent_unary_unary
def _inconsistent_unary_unary(request, servicer_context)
Definition: grpc_status_test.py:66
tests_aio.status.grpc_status_test.StatusTest.test_status_not_ok
def test_status_not_ok(self)
Definition: grpc_status_test.py:127
tests_aio.unit._test_base
Definition: _test_base.py:1
tests_aio.status.grpc_status_test.StatusTest
Definition: grpc_status_test.py:106
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
tests_aio.status.grpc_status_test.StatusTest.setUp
def setUp(self)
Definition: grpc_status_test.py:108
start
static uint64_t start
Definition: benchmark-pound.c:74
tests_aio.status.grpc_status_test.StatusTest.tearDown
def tearDown(self)
Definition: grpc_status_test.py:116
grpc::experimental
Definition: include/grpcpp/channel.h:46
grpc.GenericRpcHandler
Definition: src/python/grpcio/grpc/__init__.py:1333
tests_aio.status.grpc_status_test.StatusTest.test_error_details
def test_error_details(self)
Definition: grpc_status_test.py:138
tests_aio.status.grpc_status_test._GenericHandler
Definition: grpc_status_test.py:86
close
#define close
Definition: test-fs.c:48
tests_aio.status.grpc_status_test._error_details_unary_unary
def _error_details_unary_unary(request, servicer_context)
Definition: grpc_status_test.py:53
tests_aio.status.grpc_status_test.StatusTest.test_invalid_code
def test_invalid_code(self)
Definition: grpc_status_test.py:166
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_aio.status.grpc_status_test.StatusTest._channel
_channel
Definition: grpc_status_test.py:114
tests_aio.status.grpc_status_test.StatusTest.test_code_message_validation
def test_code_message_validation(self)
Definition: grpc_status_test.py:155
stop
static const char stop[]
Definition: benchmark-async-pummel.c:35
tests_aio.status.grpc_status_test._invalid_code_unary_unary
def _invalid_code_unary_unary(request, servicer_context)
Definition: grpc_status_test.py:78
tests_aio.status.grpc_status_test.StatusTest.test_status_ok
def test_status_ok(self)
Definition: grpc_status_test.py:120
tests_aio.status.grpc_status_test.StatusTest._server
_server
Definition: grpc_status_test.py:109
tests_aio.status.grpc_status_test._not_ok_unary_unary
def _not_ok_unary_unary(request, servicer_context)
Definition: grpc_status_test.py:49
tests_aio.unit._test_base.AioTestBase
Definition: _test_base.py:49


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:47