aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/gapic
diff options
context:
space:
mode:
authorJon Wayne Parrott <jonwayne@google.com>2017-10-18 12:52:35 -0700
committerGitHub <noreply@github.com>2017-10-18 12:52:35 -0700
commit77fb0f23da16f9d59062b69daf13b50c9dc0d5ff (patch)
tree3643765a2c1a0767e3a204cbfb16a08b23ef5026 /tests/unit/gapic
downloadpython-api-core-77fb0f23da16f9d59062b69daf13b50c9dc0d5ff.tar.gz
Add api_core package (#4210)
* Add api_core package * Address review comments
Diffstat (limited to 'tests/unit/gapic')
-rw-r--r--tests/unit/gapic/test_config.py89
-rw-r--r--tests/unit/gapic/test_method.py226
2 files changed, 315 insertions, 0 deletions
diff --git a/tests/unit/gapic/test_config.py b/tests/unit/gapic/test_config.py
new file mode 100644
index 0000000..75a6e1c
--- /dev/null
+++ b/tests/unit/gapic/test_config.py
@@ -0,0 +1,89 @@
+# 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.
+
+from google.api_core import exceptions
+from google.api_core.gapic_v1 import config
+
+
+INTERFACE_CONFIG = {
+ 'retry_codes': {
+ 'idempotent': ['DEADLINE_EXCEEDED', 'UNAVAILABLE'],
+ 'other': ['FAILED_PRECONDITION'],
+ 'non_idempotent': []
+ },
+ 'retry_params': {
+ 'default': {
+ 'initial_retry_delay_millis': 1000,
+ 'retry_delay_multiplier': 2.5,
+ 'max_retry_delay_millis': 120000,
+ 'initial_rpc_timeout_millis': 120000,
+ 'rpc_timeout_multiplier': 1.0,
+ 'max_rpc_timeout_millis': 120000,
+ 'total_timeout_millis': 600000
+ },
+ 'other': {
+ 'initial_retry_delay_millis': 1000,
+ 'retry_delay_multiplier': 1,
+ 'max_retry_delay_millis': 1000,
+ 'initial_rpc_timeout_millis': 1000,
+ 'rpc_timeout_multiplier': 1,
+ 'max_rpc_timeout_millis': 1000,
+ 'total_timeout_millis': 1000
+ },
+ },
+ 'methods': {
+ 'AnnotateVideo': {
+ 'timeout_millis': 60000,
+ 'retry_codes_name': 'idempotent',
+ 'retry_params_name': 'default'
+ },
+ 'Other': {
+ 'timeout_millis': 60000,
+ 'retry_codes_name': 'other',
+ 'retry_params_name': 'other'
+ },
+ 'Plain': {
+ 'timeout_millis': 30000
+ }
+ }
+}
+
+
+def test_create_method_configs():
+ method_configs = config.parse_method_configs(INTERFACE_CONFIG)
+
+ retry, timeout = method_configs['AnnotateVideo']
+ assert retry._predicate(exceptions.DeadlineExceeded(None))
+ assert retry._predicate(exceptions.ServiceUnavailable(None))
+ assert retry._initial == 1.0
+ assert retry._multiplier == 2.5
+ assert retry._maximum == 120.0
+ assert retry._deadline == 600.0
+ assert timeout._initial == 120.0
+ assert timeout._multiplier == 1.0
+ assert timeout._maximum == 120.0
+
+ retry, timeout = method_configs['Other']
+ assert retry._predicate(exceptions.FailedPrecondition(None))
+ assert retry._initial == 1.0
+ assert retry._multiplier == 1.0
+ assert retry._maximum == 1.0
+ assert retry._deadline == 1.0
+ assert timeout._initial == 1.0
+ assert timeout._multiplier == 1.0
+ assert timeout._maximum == 1.0
+
+ retry, timeout = method_configs['Plain']
+ assert retry is None
+ assert timeout._timeout == 30.0
diff --git a/tests/unit/gapic/test_method.py b/tests/unit/gapic/test_method.py
new file mode 100644
index 0000000..35ac144
--- /dev/null
+++ b/tests/unit/gapic/test_method.py
@@ -0,0 +1,226 @@
+# 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 datetime
+
+import mock
+
+from google.api_core import exceptions
+from google.api_core import retry
+from google.api_core import timeout
+import google.api_core.gapic_v1.method
+import google.api_core.page_iterator
+
+
+def _utcnow_monotonic():
+ curr_value = datetime.datetime.min
+ delta = datetime.timedelta(seconds=0.5)
+ while True:
+ yield curr_value
+ curr_value += delta
+
+
+def test_wrap_method_basic():
+ method = mock.Mock(spec=['__call__'], return_value=42)
+
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, metadata=None)
+
+ result = wrapped_method(1, 2, meep='moop')
+
+ assert result == 42
+ method.assert_called_once_with(1, 2, meep='moop')
+
+
+def test_wrap_method_with_default_metadata():
+ method = mock.Mock(spec=['__call__'])
+
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(method)
+
+ wrapped_method(1, 2, meep='moop')
+
+ method.assert_called_once_with(1, 2, meep='moop', metadata=mock.ANY)
+
+ metadata = method.call_args[1]['metadata']
+ assert len(metadata) == 1
+ assert metadata[0][0] == 'x-goog-api-client'
+ assert 'api-core' in metadata[0][1]
+
+
+def test_wrap_method_with_custom_metadata():
+ method = mock.Mock(spec=['__call__'])
+
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, metadata={'foo': 'bar'})
+
+ wrapped_method(1, 2, meep='moop')
+
+ method.assert_called_once_with(1, 2, meep='moop', metadata=mock.ANY)
+
+ metadata = method.call_args[1]['metadata']
+ assert len(metadata) == 2
+ assert ('foo', 'bar') in metadata
+
+
+def test_wrap_method_with_merged_metadata():
+ method = mock.Mock(spec=['__call__'])
+
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, metadata={'x-goog-api-client': 'foo/1.2.3'})
+
+ wrapped_method(1, 2, meep='moop')
+
+ method.assert_called_once_with(1, 2, meep='moop', metadata=mock.ANY)
+
+ metadata = method.call_args[1]['metadata']
+ assert len(metadata) == 1
+ assert metadata[0][0] == 'x-goog-api-client'
+ assert metadata[0][1].endswith(' foo/1.2.3')
+
+
+@mock.patch('time.sleep')
+def test_wrap_method_with_default_retry_and_timeout(unusued_sleep):
+ method = mock.Mock(
+ spec=['__call__'],
+ side_effect=[exceptions.InternalServerError(None), 42]
+ )
+ default_retry = retry.Retry()
+ default_timeout = timeout.ConstantTimeout(60)
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, default_retry, default_timeout)
+
+ result = wrapped_method()
+
+ assert result == 42
+ assert method.call_count == 2
+ method.assert_called_with(timeout=60, metadata=mock.ANY)
+
+
+@mock.patch('time.sleep')
+def test_wrap_method_with_default_retry_and_timeout_using_sentinel(
+ unusued_sleep):
+ method = mock.Mock(
+ spec=['__call__'],
+ side_effect=[exceptions.InternalServerError(None), 42]
+ )
+ default_retry = retry.Retry()
+ default_timeout = timeout.ConstantTimeout(60)
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, default_retry, default_timeout)
+
+ result = wrapped_method(
+ retry=google.api_core.gapic_v1.method.DEFAULT,
+ timeout=google.api_core.gapic_v1.method.DEFAULT)
+
+ assert result == 42
+ assert method.call_count == 2
+ method.assert_called_with(timeout=60, metadata=mock.ANY)
+
+
+@mock.patch('time.sleep')
+def test_wrap_method_with_overriding_retry_and_timeout(unusued_sleep):
+ method = mock.Mock(
+ spec=['__call__'],
+ side_effect=[exceptions.NotFound(None), 42]
+ )
+ default_retry = retry.Retry()
+ default_timeout = timeout.ConstantTimeout(60)
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, default_retry, default_timeout)
+
+ result = wrapped_method(
+ retry=retry.Retry(retry.if_exception_type(exceptions.NotFound)),
+ timeout=timeout.ConstantTimeout(22))
+
+ assert result == 42
+ assert method.call_count == 2
+ method.assert_called_with(timeout=22, metadata=mock.ANY)
+
+
+@mock.patch('time.sleep')
+@mock.patch(
+ 'google.api_core.datetime_helpers.utcnow',
+ side_effect=_utcnow_monotonic(),
+ autospec=True)
+def test_wrap_method_with_overriding_retry_deadline(utcnow, unused_sleep):
+ method = mock.Mock(
+ spec=['__call__'],
+ side_effect=([exceptions.InternalServerError(None)] * 4) + [42]
+ )
+ default_retry = retry.Retry()
+ default_timeout = timeout.ExponentialTimeout(deadline=60)
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, default_retry, default_timeout)
+
+ # Overriding only the retry's deadline should also override the timeout's
+ # deadline.
+ result = wrapped_method(
+ retry=default_retry.with_deadline(30))
+
+ assert result == 42
+ timeout_args = [call[1]['timeout'] for call in method.call_args_list]
+ assert timeout_args == [5.0, 10.0, 20.0, 26.0, 25.0]
+ assert utcnow.call_count == (
+ 1 + # First to set the deadline.
+ 5 + # One for each min(timeout, maximum, (DEADLINE - NOW).seconds)
+ 5
+ )
+
+
+def test_wrap_method_with_overriding_timeout_as_a_number():
+ method = mock.Mock(spec=['__call__'], return_value=42)
+ default_retry = retry.Retry()
+ default_timeout = timeout.ConstantTimeout(60)
+ wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+ method, default_retry, default_timeout)
+
+ result = wrapped_method(timeout=22)
+
+ assert result == 42
+ method.assert_called_once_with(timeout=22, metadata=mock.ANY)
+
+
+def test_wrap_with_paging():
+ page_one = mock.Mock(
+ spec=['items', 'page_token', 'next_page_token'],
+ items=[1, 2],
+ next_page_token='icanhasnextpls')
+ page_two = mock.Mock(
+ spec=['items', 'page_token', 'next_page_token'],
+ items=[3, 4],
+ next_page_token=None)
+ method = mock.Mock(
+ spec=['__call__', '__name__'], side_effect=(page_one, page_two))
+ method.__name__ = 'mockmethod'
+
+ wrapped_method = google.api_core.gapic_v1.method.wrap_with_paging(
+ method, 'items', 'page_token', 'next_page_token')
+
+ request = mock.Mock(spec=['page_token'], page_token=None)
+ result = wrapped_method(request, extra='param')
+
+ # Should return an iterator and should not have actually called the
+ # method yet.
+ assert isinstance(result, google.api_core.page_iterator.Iterator)
+ method.assert_not_called()
+ assert request.page_token is None
+
+ # Draining the iterator should call the method until no more pages are
+ # returned.
+ results = list(result)
+
+ assert results == [1, 2, 3, 4]
+ assert method.call_count == 2
+ method.assert_called_with(request, extra='param')
+ assert request.page_token == 'icanhasnextpls'