diff options
author | Jon Wayne Parrott <jonwayne@google.com> | 2017-10-18 12:52:35 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-18 12:52:35 -0700 |
commit | 77fb0f23da16f9d59062b69daf13b50c9dc0d5ff (patch) | |
tree | 3643765a2c1a0767e3a204cbfb16a08b23ef5026 /tests/unit/test_grpc_helpers.py | |
download | python-api-core-77fb0f23da16f9d59062b69daf13b50c9dc0d5ff.tar.gz |
Add api_core package (#4210)
* Add api_core package
* Address review comments
Diffstat (limited to 'tests/unit/test_grpc_helpers.py')
-rw-r--r-- | tests/unit/test_grpc_helpers.py | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/tests/unit/test_grpc_helpers.py b/tests/unit/test_grpc_helpers.py new file mode 100644 index 0000000..d5e0b3c --- /dev/null +++ b/tests/unit/test_grpc_helpers.py @@ -0,0 +1,171 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import grpc +import mock +import pytest + +from google.api_core import exceptions +from google.api_core import grpc_helpers + + +def test__patch_callable_name(): + callable = mock.Mock(spec=['__class__']) + callable.__class__ = mock.Mock(spec=['__name__']) + callable.__class__.__name__ = 'TestCallable' + + grpc_helpers._patch_callable_name(callable) + + assert callable.__name__ == 'TestCallable' + + +def test__patch_callable_name_no_op(): + callable = mock.Mock(spec=['__name__']) + callable.__name__ = 'test_callable' + + grpc_helpers._patch_callable_name(callable) + + assert callable.__name__ == 'test_callable' + + +class RpcErrorImpl(grpc.RpcError, grpc.Call): + def __init__(self, code): + super(RpcErrorImpl, self).__init__() + self._code = code + + def code(self): + return self._code + + def details(self): + return None + + +def test_wrap_unary_errors(): + grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT) + callable_ = mock.Mock(spec=['__call__'], side_effect=grpc_error) + + wrapped_callable = grpc_helpers._wrap_unary_errors(callable_) + + with pytest.raises(exceptions.InvalidArgument) as exc_info: + wrapped_callable(1, 2, three='four') + + callable_.assert_called_once_with(1, 2, three='four') + assert exc_info.value.response == grpc_error + + +def test_wrap_stream_errors_invocation(): + grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT) + callable_ = mock.Mock(spec=['__call__'], side_effect=grpc_error) + + wrapped_callable = grpc_helpers._wrap_stream_errors(callable_) + + with pytest.raises(exceptions.InvalidArgument) as exc_info: + wrapped_callable(1, 2, three='four') + + callable_.assert_called_once_with(1, 2, three='four') + assert exc_info.value.response == grpc_error + + +class RpcResponseIteratorImpl(object): + def __init__(self, exception): + self._exception = exception + + # Note: This matches grpc._channel._Rendezvous._next which is what is + # patched by _wrap_stream_errors. + def _next(self): + raise self._exception + + def __next__(self): # pragma: NO COVER + return self._next() + + def next(self): # pragma: NO COVER + return self._next() + + +def test_wrap_stream_errors_iterator(): + grpc_error = RpcErrorImpl(grpc.StatusCode.UNAVAILABLE) + response_iter = RpcResponseIteratorImpl(grpc_error) + callable_ = mock.Mock(spec=['__call__'], return_value=response_iter) + + wrapped_callable = grpc_helpers._wrap_stream_errors(callable_) + + got_iterator = wrapped_callable(1, 2, three='four') + + with pytest.raises(exceptions.ServiceUnavailable) as exc_info: + next(got_iterator) + + assert got_iterator == response_iter + callable_.assert_called_once_with(1, 2, three='four') + assert exc_info.value.response == grpc_error + + +@mock.patch('google.api_core.grpc_helpers._wrap_unary_errors') +def test_wrap_errors_non_streaming(wrap_unary_errors): + callable_ = mock.create_autospec(grpc.UnaryUnaryMultiCallable) + + result = grpc_helpers.wrap_errors(callable_) + + assert result == wrap_unary_errors.return_value + wrap_unary_errors.assert_called_once_with(callable_) + + +@mock.patch('google.api_core.grpc_helpers._wrap_stream_errors') +def test_wrap_errors_streaming(wrap_stream_errors): + callable_ = mock.create_autospec(grpc.UnaryStreamMultiCallable) + + result = grpc_helpers.wrap_errors(callable_) + + assert result == wrap_stream_errors.return_value + wrap_stream_errors.assert_called_once_with(callable_) + + +@mock.patch( + 'google.auth.default', + return_value=(mock.sentinel.credentials, mock.sentinel.projet)) +@mock.patch('google.auth.transport.grpc.secure_authorized_channel') +def test_create_channel_implicit(secure_authorized_channel, default): + target = 'example.com:443' + + channel = grpc_helpers.create_channel(target) + + assert channel is secure_authorized_channel.return_value + default.assert_called_once_with(scopes=None) + secure_authorized_channel.assert_called_once_with( + mock.sentinel.credentials, mock.ANY, target) + + +@mock.patch( + 'google.auth.default', + return_value=(mock.sentinel.credentials, mock.sentinel.projet)) +@mock.patch('google.auth.transport.grpc.secure_authorized_channel') +def test_create_channel_implicit_with_scopes( + secure_authorized_channel, default): + target = 'example.com:443' + + channel = grpc_helpers.create_channel(target, scopes=['one', 'two']) + + assert channel is secure_authorized_channel.return_value + default.assert_called_once_with(scopes=['one', 'two']) + + +@mock.patch('google.auth.transport.grpc.secure_authorized_channel') +def test_create_channel_explicit(secure_authorized_channel): + target = 'example.com:443' + + channel = grpc_helpers.create_channel( + target, credentials=mock.sentinel.credentials) + + assert channel is secure_authorized_channel.return_value + secure_authorized_channel.assert_called_once_with( + mock.sentinel.credentials, mock.ANY, target) |