1# Copyright 2016 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 application-provided metadata, status code, and details."""
15
16import threading
17import unittest
18
19import grpc
20
21from tests.unit import test_common
22from tests.unit.framework.common import test_constants
23from tests.unit.framework.common import test_control
24
25_SERIALIZED_REQUEST = b'\x46\x47\x48'
26_SERIALIZED_RESPONSE = b'\x49\x50\x51'
27
28_REQUEST_SERIALIZER = lambda unused_request: _SERIALIZED_REQUEST
29_REQUEST_DESERIALIZER = lambda unused_serialized_request: object()
30_RESPONSE_SERIALIZER = lambda unused_response: _SERIALIZED_RESPONSE
31_RESPONSE_DESERIALIZER = lambda unused_serialized_response: object()
32
33_SERVICE = 'test.TestService'
34_UNARY_UNARY = 'UnaryUnary'
35_UNARY_STREAM = 'UnaryStream'
36_STREAM_UNARY = 'StreamUnary'
37_STREAM_STREAM = 'StreamStream'
38
39_CLIENT_METADATA = (('client-md-key', 'client-md-key'), ('client-md-key-bin',
40                                                         b'\x00\x01'))
41
42_SERVER_INITIAL_METADATA = (('server-initial-md-key',
43                             'server-initial-md-value'),
44                            ('server-initial-md-key-bin', b'\x00\x02'))
45
46_SERVER_TRAILING_METADATA = (('server-trailing-md-key',
47                              'server-trailing-md-value'),
48                             ('server-trailing-md-key-bin', b'\x00\x03'))
49
50_NON_OK_CODE = grpc.StatusCode.NOT_FOUND
51_DETAILS = 'Test details!'
52
53# calling abort should always fail an RPC, even for "invalid" codes
54_ABORT_CODES = (_NON_OK_CODE, 3, grpc.StatusCode.OK)
55_EXPECTED_CLIENT_CODES = (_NON_OK_CODE, grpc.StatusCode.UNKNOWN,
56                          grpc.StatusCode.UNKNOWN)
57_EXPECTED_DETAILS = (_DETAILS, _DETAILS, '')
58
59
60class _Servicer(object):
61
62    def __init__(self):
63        self._lock = threading.Lock()
64        self._abort_call = False
65        self._code = None
66        self._details = None
67        self._exception = False
68        self._return_none = False
69        self._received_client_metadata = None
70
71    def unary_unary(self, request, context):
72        with self._lock:
73            self._received_client_metadata = context.invocation_metadata()
74            context.send_initial_metadata(_SERVER_INITIAL_METADATA)
75            context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
76            if self._abort_call:
77                context.abort(self._code, self._details)
78            else:
79                if self._code is not None:
80                    context.set_code(self._code)
81                if self._details is not None:
82                    context.set_details(self._details)
83            if self._exception:
84                raise test_control.Defect()
85            else:
86                return None if self._return_none else object()
87
88    def unary_stream(self, request, context):
89        with self._lock:
90            self._received_client_metadata = context.invocation_metadata()
91            context.send_initial_metadata(_SERVER_INITIAL_METADATA)
92            context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
93            if self._abort_call:
94                context.abort(self._code, self._details)
95            else:
96                if self._code is not None:
97                    context.set_code(self._code)
98                if self._details is not None:
99                    context.set_details(self._details)
100            for _ in range(test_constants.STREAM_LENGTH // 2):
101                yield _SERIALIZED_RESPONSE
102            if self._exception:
103                raise test_control.Defect()
104
105    def stream_unary(self, request_iterator, context):
106        with self._lock:
107            self._received_client_metadata = context.invocation_metadata()
108            context.send_initial_metadata(_SERVER_INITIAL_METADATA)
109            context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
110            # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
111            # request iterator.
112            list(request_iterator)
113            if self._abort_call:
114                context.abort(self._code, self._details)
115            else:
116                if self._code is not None:
117                    context.set_code(self._code)
118                if self._details is not None:
119                    context.set_details(self._details)
120            if self._exception:
121                raise test_control.Defect()
122            else:
123                return None if self._return_none else _SERIALIZED_RESPONSE
124
125    def stream_stream(self, request_iterator, context):
126        with self._lock:
127            self._received_client_metadata = context.invocation_metadata()
128            context.send_initial_metadata(_SERVER_INITIAL_METADATA)
129            context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
130            # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
131            # request iterator.
132            list(request_iterator)
133            if self._abort_call:
134                context.abort(self._code, self._details)
135            else:
136                if self._code is not None:
137                    context.set_code(self._code)
138                if self._details is not None:
139                    context.set_details(self._details)
140            for _ in range(test_constants.STREAM_LENGTH // 3):
141                yield object()
142            if self._exception:
143                raise test_control.Defect()
144
145    def set_abort_call(self):
146        with self._lock:
147            self._abort_call = True
148
149    def set_code(self, code):
150        with self._lock:
151            self._code = code
152
153    def set_details(self, details):
154        with self._lock:
155            self._details = details
156
157    def set_exception(self):
158        with self._lock:
159            self._exception = True
160
161    def set_return_none(self):
162        with self._lock:
163            self._return_none = True
164
165    def received_client_metadata(self):
166        with self._lock:
167            return self._received_client_metadata
168
169
170def _generic_handler(servicer):
171    method_handlers = {
172        _UNARY_UNARY:
173        grpc.unary_unary_rpc_method_handler(
174            servicer.unary_unary,
175            request_deserializer=_REQUEST_DESERIALIZER,
176            response_serializer=_RESPONSE_SERIALIZER),
177        _UNARY_STREAM:
178        grpc.unary_stream_rpc_method_handler(servicer.unary_stream),
179        _STREAM_UNARY:
180        grpc.stream_unary_rpc_method_handler(servicer.stream_unary),
181        _STREAM_STREAM:
182        grpc.stream_stream_rpc_method_handler(
183            servicer.stream_stream,
184            request_deserializer=_REQUEST_DESERIALIZER,
185            response_serializer=_RESPONSE_SERIALIZER),
186    }
187    return grpc.method_handlers_generic_handler(_SERVICE, method_handlers)
188
189
190class MetadataCodeDetailsTest(unittest.TestCase):
191
192    def setUp(self):
193        self._servicer = _Servicer()
194        self._server = test_common.test_server()
195        self._server.add_generic_rpc_handlers(
196            (_generic_handler(self._servicer),))
197        port = self._server.add_insecure_port('[::]:0')
198        self._server.start()
199
200        channel = grpc.insecure_channel('localhost:{}'.format(port))
201        self._unary_unary = channel.unary_unary(
202            '/'.join((
203                '',
204                _SERVICE,
205                _UNARY_UNARY,
206            )),
207            request_serializer=_REQUEST_SERIALIZER,
208            response_deserializer=_RESPONSE_DESERIALIZER,
209        )
210        self._unary_stream = channel.unary_stream('/'.join((
211            '',
212            _SERVICE,
213            _UNARY_STREAM,
214        )),)
215        self._stream_unary = channel.stream_unary('/'.join((
216            '',
217            _SERVICE,
218            _STREAM_UNARY,
219        )),)
220        self._stream_stream = channel.stream_stream(
221            '/'.join((
222                '',
223                _SERVICE,
224                _STREAM_STREAM,
225            )),
226            request_serializer=_REQUEST_SERIALIZER,
227            response_deserializer=_RESPONSE_DESERIALIZER,
228        )
229
230    def testSuccessfulUnaryUnary(self):
231        self._servicer.set_details(_DETAILS)
232
233        unused_response, call = self._unary_unary.with_call(
234            object(), metadata=_CLIENT_METADATA)
235
236        self.assertTrue(
237            test_common.metadata_transmitted(
238                _CLIENT_METADATA, self._servicer.received_client_metadata()))
239        self.assertTrue(
240            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
241                                             call.initial_metadata()))
242        self.assertTrue(
243            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
244                                             call.trailing_metadata()))
245        self.assertIs(grpc.StatusCode.OK, call.code())
246        self.assertEqual(_DETAILS, call.details())
247
248    def testSuccessfulUnaryStream(self):
249        self._servicer.set_details(_DETAILS)
250
251        response_iterator_call = self._unary_stream(
252            _SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
253        received_initial_metadata = response_iterator_call.initial_metadata()
254        list(response_iterator_call)
255
256        self.assertTrue(
257            test_common.metadata_transmitted(
258                _CLIENT_METADATA, self._servicer.received_client_metadata()))
259        self.assertTrue(
260            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
261                                             received_initial_metadata))
262        self.assertTrue(
263            test_common.metadata_transmitted(
264                _SERVER_TRAILING_METADATA,
265                response_iterator_call.trailing_metadata()))
266        self.assertIs(grpc.StatusCode.OK, response_iterator_call.code())
267        self.assertEqual(_DETAILS, response_iterator_call.details())
268
269    def testSuccessfulStreamUnary(self):
270        self._servicer.set_details(_DETAILS)
271
272        unused_response, call = self._stream_unary.with_call(
273            iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
274            metadata=_CLIENT_METADATA)
275
276        self.assertTrue(
277            test_common.metadata_transmitted(
278                _CLIENT_METADATA, self._servicer.received_client_metadata()))
279        self.assertTrue(
280            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
281                                             call.initial_metadata()))
282        self.assertTrue(
283            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
284                                             call.trailing_metadata()))
285        self.assertIs(grpc.StatusCode.OK, call.code())
286        self.assertEqual(_DETAILS, call.details())
287
288    def testSuccessfulStreamStream(self):
289        self._servicer.set_details(_DETAILS)
290
291        response_iterator_call = self._stream_stream(
292            iter([object()] * test_constants.STREAM_LENGTH),
293            metadata=_CLIENT_METADATA)
294        received_initial_metadata = response_iterator_call.initial_metadata()
295        list(response_iterator_call)
296
297        self.assertTrue(
298            test_common.metadata_transmitted(
299                _CLIENT_METADATA, self._servicer.received_client_metadata()))
300        self.assertTrue(
301            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
302                                             received_initial_metadata))
303        self.assertTrue(
304            test_common.metadata_transmitted(
305                _SERVER_TRAILING_METADATA,
306                response_iterator_call.trailing_metadata()))
307        self.assertIs(grpc.StatusCode.OK, response_iterator_call.code())
308        self.assertEqual(_DETAILS, response_iterator_call.details())
309
310    def testAbortedUnaryUnary(self):
311        test_cases = zip(_ABORT_CODES, _EXPECTED_CLIENT_CODES,
312                         _EXPECTED_DETAILS)
313        for abort_code, expected_code, expected_details in test_cases:
314            self._servicer.set_code(abort_code)
315            self._servicer.set_details(_DETAILS)
316            self._servicer.set_abort_call()
317
318            with self.assertRaises(grpc.RpcError) as exception_context:
319                self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
320
321            self.assertTrue(
322                test_common.metadata_transmitted(
323                    _CLIENT_METADATA,
324                    self._servicer.received_client_metadata()))
325            self.assertTrue(
326                test_common.metadata_transmitted(
327                    _SERVER_INITIAL_METADATA,
328                    exception_context.exception.initial_metadata()))
329            self.assertTrue(
330                test_common.metadata_transmitted(
331                    _SERVER_TRAILING_METADATA,
332                    exception_context.exception.trailing_metadata()))
333            self.assertIs(expected_code, exception_context.exception.code())
334            self.assertEqual(expected_details,
335                             exception_context.exception.details())
336
337    def testAbortedUnaryStream(self):
338        test_cases = zip(_ABORT_CODES, _EXPECTED_CLIENT_CODES,
339                         _EXPECTED_DETAILS)
340        for abort_code, expected_code, expected_details in test_cases:
341            self._servicer.set_code(abort_code)
342            self._servicer.set_details(_DETAILS)
343            self._servicer.set_abort_call()
344
345            response_iterator_call = self._unary_stream(
346                _SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
347            received_initial_metadata = \
348                response_iterator_call.initial_metadata()
349            with self.assertRaises(grpc.RpcError):
350                self.assertEqual(len(list(response_iterator_call)), 0)
351
352            self.assertTrue(
353                test_common.metadata_transmitted(
354                    _CLIENT_METADATA,
355                    self._servicer.received_client_metadata()))
356            self.assertTrue(
357                test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
358                                                 received_initial_metadata))
359            self.assertTrue(
360                test_common.metadata_transmitted(
361                    _SERVER_TRAILING_METADATA,
362                    response_iterator_call.trailing_metadata()))
363            self.assertIs(expected_code, response_iterator_call.code())
364            self.assertEqual(expected_details, response_iterator_call.details())
365
366    def testAbortedStreamUnary(self):
367        test_cases = zip(_ABORT_CODES, _EXPECTED_CLIENT_CODES,
368                         _EXPECTED_DETAILS)
369        for abort_code, expected_code, expected_details in test_cases:
370            self._servicer.set_code(abort_code)
371            self._servicer.set_details(_DETAILS)
372            self._servicer.set_abort_call()
373
374            with self.assertRaises(grpc.RpcError) as exception_context:
375                self._stream_unary.with_call(
376                    iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
377                    metadata=_CLIENT_METADATA)
378
379            self.assertTrue(
380                test_common.metadata_transmitted(
381                    _CLIENT_METADATA,
382                    self._servicer.received_client_metadata()))
383            self.assertTrue(
384                test_common.metadata_transmitted(
385                    _SERVER_INITIAL_METADATA,
386                    exception_context.exception.initial_metadata()))
387            self.assertTrue(
388                test_common.metadata_transmitted(
389                    _SERVER_TRAILING_METADATA,
390                    exception_context.exception.trailing_metadata()))
391            self.assertIs(expected_code, exception_context.exception.code())
392            self.assertEqual(expected_details,
393                             exception_context.exception.details())
394
395    def testAbortedStreamStream(self):
396        test_cases = zip(_ABORT_CODES, _EXPECTED_CLIENT_CODES,
397                         _EXPECTED_DETAILS)
398        for abort_code, expected_code, expected_details in test_cases:
399            self._servicer.set_code(abort_code)
400            self._servicer.set_details(_DETAILS)
401            self._servicer.set_abort_call()
402
403            response_iterator_call = self._stream_stream(
404                iter([object()] * test_constants.STREAM_LENGTH),
405                metadata=_CLIENT_METADATA)
406            received_initial_metadata = \
407                response_iterator_call.initial_metadata()
408            with self.assertRaises(grpc.RpcError):
409                self.assertEqual(len(list(response_iterator_call)), 0)
410
411            self.assertTrue(
412                test_common.metadata_transmitted(
413                    _CLIENT_METADATA,
414                    self._servicer.received_client_metadata()))
415            self.assertTrue(
416                test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
417                                                 received_initial_metadata))
418            self.assertTrue(
419                test_common.metadata_transmitted(
420                    _SERVER_TRAILING_METADATA,
421                    response_iterator_call.trailing_metadata()))
422            self.assertIs(expected_code, response_iterator_call.code())
423            self.assertEqual(expected_details, response_iterator_call.details())
424
425    def testCustomCodeUnaryUnary(self):
426        self._servicer.set_code(_NON_OK_CODE)
427        self._servicer.set_details(_DETAILS)
428
429        with self.assertRaises(grpc.RpcError) as exception_context:
430            self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
431
432        self.assertTrue(
433            test_common.metadata_transmitted(
434                _CLIENT_METADATA, self._servicer.received_client_metadata()))
435        self.assertTrue(
436            test_common.metadata_transmitted(
437                _SERVER_INITIAL_METADATA,
438                exception_context.exception.initial_metadata()))
439        self.assertTrue(
440            test_common.metadata_transmitted(
441                _SERVER_TRAILING_METADATA,
442                exception_context.exception.trailing_metadata()))
443        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
444        self.assertEqual(_DETAILS, exception_context.exception.details())
445
446    def testCustomCodeUnaryStream(self):
447        self._servicer.set_code(_NON_OK_CODE)
448        self._servicer.set_details(_DETAILS)
449
450        response_iterator_call = self._unary_stream(
451            _SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
452        received_initial_metadata = response_iterator_call.initial_metadata()
453        with self.assertRaises(grpc.RpcError):
454            list(response_iterator_call)
455
456        self.assertTrue(
457            test_common.metadata_transmitted(
458                _CLIENT_METADATA, self._servicer.received_client_metadata()))
459        self.assertTrue(
460            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
461                                             received_initial_metadata))
462        self.assertTrue(
463            test_common.metadata_transmitted(
464                _SERVER_TRAILING_METADATA,
465                response_iterator_call.trailing_metadata()))
466        self.assertIs(_NON_OK_CODE, response_iterator_call.code())
467        self.assertEqual(_DETAILS, response_iterator_call.details())
468
469    def testCustomCodeStreamUnary(self):
470        self._servicer.set_code(_NON_OK_CODE)
471        self._servicer.set_details(_DETAILS)
472
473        with self.assertRaises(grpc.RpcError) as exception_context:
474            self._stream_unary.with_call(
475                iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
476                metadata=_CLIENT_METADATA)
477
478        self.assertTrue(
479            test_common.metadata_transmitted(
480                _CLIENT_METADATA, self._servicer.received_client_metadata()))
481        self.assertTrue(
482            test_common.metadata_transmitted(
483                _SERVER_INITIAL_METADATA,
484                exception_context.exception.initial_metadata()))
485        self.assertTrue(
486            test_common.metadata_transmitted(
487                _SERVER_TRAILING_METADATA,
488                exception_context.exception.trailing_metadata()))
489        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
490        self.assertEqual(_DETAILS, exception_context.exception.details())
491
492    def testCustomCodeStreamStream(self):
493        self._servicer.set_code(_NON_OK_CODE)
494        self._servicer.set_details(_DETAILS)
495
496        response_iterator_call = self._stream_stream(
497            iter([object()] * test_constants.STREAM_LENGTH),
498            metadata=_CLIENT_METADATA)
499        received_initial_metadata = response_iterator_call.initial_metadata()
500        with self.assertRaises(grpc.RpcError) as exception_context:
501            list(response_iterator_call)
502
503        self.assertTrue(
504            test_common.metadata_transmitted(
505                _CLIENT_METADATA, self._servicer.received_client_metadata()))
506        self.assertTrue(
507            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
508                                             received_initial_metadata))
509        self.assertTrue(
510            test_common.metadata_transmitted(
511                _SERVER_TRAILING_METADATA,
512                exception_context.exception.trailing_metadata()))
513        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
514        self.assertEqual(_DETAILS, exception_context.exception.details())
515
516    def testCustomCodeExceptionUnaryUnary(self):
517        self._servicer.set_code(_NON_OK_CODE)
518        self._servicer.set_details(_DETAILS)
519        self._servicer.set_exception()
520
521        with self.assertRaises(grpc.RpcError) as exception_context:
522            self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
523
524        self.assertTrue(
525            test_common.metadata_transmitted(
526                _CLIENT_METADATA, self._servicer.received_client_metadata()))
527        self.assertTrue(
528            test_common.metadata_transmitted(
529                _SERVER_INITIAL_METADATA,
530                exception_context.exception.initial_metadata()))
531        self.assertTrue(
532            test_common.metadata_transmitted(
533                _SERVER_TRAILING_METADATA,
534                exception_context.exception.trailing_metadata()))
535        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
536        self.assertEqual(_DETAILS, exception_context.exception.details())
537
538    def testCustomCodeExceptionUnaryStream(self):
539        self._servicer.set_code(_NON_OK_CODE)
540        self._servicer.set_details(_DETAILS)
541        self._servicer.set_exception()
542
543        response_iterator_call = self._unary_stream(
544            _SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
545        received_initial_metadata = response_iterator_call.initial_metadata()
546        with self.assertRaises(grpc.RpcError):
547            list(response_iterator_call)
548
549        self.assertTrue(
550            test_common.metadata_transmitted(
551                _CLIENT_METADATA, self._servicer.received_client_metadata()))
552        self.assertTrue(
553            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
554                                             received_initial_metadata))
555        self.assertTrue(
556            test_common.metadata_transmitted(
557                _SERVER_TRAILING_METADATA,
558                response_iterator_call.trailing_metadata()))
559        self.assertIs(_NON_OK_CODE, response_iterator_call.code())
560        self.assertEqual(_DETAILS, response_iterator_call.details())
561
562    def testCustomCodeExceptionStreamUnary(self):
563        self._servicer.set_code(_NON_OK_CODE)
564        self._servicer.set_details(_DETAILS)
565        self._servicer.set_exception()
566
567        with self.assertRaises(grpc.RpcError) as exception_context:
568            self._stream_unary.with_call(
569                iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
570                metadata=_CLIENT_METADATA)
571
572        self.assertTrue(
573            test_common.metadata_transmitted(
574                _CLIENT_METADATA, self._servicer.received_client_metadata()))
575        self.assertTrue(
576            test_common.metadata_transmitted(
577                _SERVER_INITIAL_METADATA,
578                exception_context.exception.initial_metadata()))
579        self.assertTrue(
580            test_common.metadata_transmitted(
581                _SERVER_TRAILING_METADATA,
582                exception_context.exception.trailing_metadata()))
583        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
584        self.assertEqual(_DETAILS, exception_context.exception.details())
585
586    def testCustomCodeExceptionStreamStream(self):
587        self._servicer.set_code(_NON_OK_CODE)
588        self._servicer.set_details(_DETAILS)
589        self._servicer.set_exception()
590
591        response_iterator_call = self._stream_stream(
592            iter([object()] * test_constants.STREAM_LENGTH),
593            metadata=_CLIENT_METADATA)
594        received_initial_metadata = response_iterator_call.initial_metadata()
595        with self.assertRaises(grpc.RpcError):
596            list(response_iterator_call)
597
598        self.assertTrue(
599            test_common.metadata_transmitted(
600                _CLIENT_METADATA, self._servicer.received_client_metadata()))
601        self.assertTrue(
602            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
603                                             received_initial_metadata))
604        self.assertTrue(
605            test_common.metadata_transmitted(
606                _SERVER_TRAILING_METADATA,
607                response_iterator_call.trailing_metadata()))
608        self.assertIs(_NON_OK_CODE, response_iterator_call.code())
609        self.assertEqual(_DETAILS, response_iterator_call.details())
610
611    def testCustomCodeReturnNoneUnaryUnary(self):
612        self._servicer.set_code(_NON_OK_CODE)
613        self._servicer.set_details(_DETAILS)
614        self._servicer.set_return_none()
615
616        with self.assertRaises(grpc.RpcError) as exception_context:
617            self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
618
619        self.assertTrue(
620            test_common.metadata_transmitted(
621                _CLIENT_METADATA, self._servicer.received_client_metadata()))
622        self.assertTrue(
623            test_common.metadata_transmitted(
624                _SERVER_INITIAL_METADATA,
625                exception_context.exception.initial_metadata()))
626        self.assertTrue(
627            test_common.metadata_transmitted(
628                _SERVER_TRAILING_METADATA,
629                exception_context.exception.trailing_metadata()))
630        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
631        self.assertEqual(_DETAILS, exception_context.exception.details())
632
633    def testCustomCodeReturnNoneStreamUnary(self):
634        self._servicer.set_code(_NON_OK_CODE)
635        self._servicer.set_details(_DETAILS)
636        self._servicer.set_return_none()
637
638        with self.assertRaises(grpc.RpcError) as exception_context:
639            self._stream_unary.with_call(
640                iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
641                metadata=_CLIENT_METADATA)
642
643        self.assertTrue(
644            test_common.metadata_transmitted(
645                _CLIENT_METADATA, self._servicer.received_client_metadata()))
646        self.assertTrue(
647            test_common.metadata_transmitted(
648                _SERVER_INITIAL_METADATA,
649                exception_context.exception.initial_metadata()))
650        self.assertTrue(
651            test_common.metadata_transmitted(
652                _SERVER_TRAILING_METADATA,
653                exception_context.exception.trailing_metadata()))
654        self.assertIs(_NON_OK_CODE, exception_context.exception.code())
655        self.assertEqual(_DETAILS, exception_context.exception.details())
656
657
658if __name__ == '__main__':
659    unittest.main(verbosity=2)
660