• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 Google LLC
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
15import datetime
16
17import mock
18import pytest
19
20try:
21    import grpc  # noqa: F401
22except ImportError:
23    pytest.skip("No GRPC", allow_module_level=True)
24
25
26from google.api_core import exceptions
27from google.api_core import retry
28from google.api_core import timeout
29import google.api_core.gapic_v1.client_info
30import google.api_core.gapic_v1.method
31import google.api_core.page_iterator
32
33
34def _utcnow_monotonic():
35    curr_value = datetime.datetime.min
36    delta = datetime.timedelta(seconds=0.5)
37    while True:
38        yield curr_value
39        curr_value += delta
40
41
42def test__determine_timeout():
43    # Check _determine_timeout always returns a Timeout object.
44    timeout_type_timeout = timeout.ConstantTimeout(600.0)
45    returned_timeout = google.api_core.gapic_v1.method._determine_timeout(
46        600.0, 600.0, None
47    )
48    assert isinstance(returned_timeout, timeout.ConstantTimeout)
49    returned_timeout = google.api_core.gapic_v1.method._determine_timeout(
50        600.0, timeout_type_timeout, None
51    )
52    assert isinstance(returned_timeout, timeout.ConstantTimeout)
53    returned_timeout = google.api_core.gapic_v1.method._determine_timeout(
54        timeout_type_timeout, 600.0, None
55    )
56    assert isinstance(returned_timeout, timeout.ConstantTimeout)
57    returned_timeout = google.api_core.gapic_v1.method._determine_timeout(
58        timeout_type_timeout, timeout_type_timeout, None
59    )
60    assert isinstance(returned_timeout, timeout.ConstantTimeout)
61
62
63def test_wrap_method_basic():
64    method = mock.Mock(spec=["__call__"], return_value=42)
65
66    wrapped_method = google.api_core.gapic_v1.method.wrap_method(method)
67
68    result = wrapped_method(1, 2, meep="moop")
69
70    assert result == 42
71    method.assert_called_once_with(1, 2, meep="moop", metadata=mock.ANY)
72
73    # Check that the default client info was specified in the metadata.
74    metadata = method.call_args[1]["metadata"]
75    assert len(metadata) == 1
76    client_info = google.api_core.gapic_v1.client_info.DEFAULT_CLIENT_INFO
77    user_agent_metadata = client_info.to_grpc_metadata()
78    assert user_agent_metadata in metadata
79
80
81def test_wrap_method_with_no_client_info():
82    method = mock.Mock(spec=["__call__"])
83
84    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
85        method, client_info=None
86    )
87
88    wrapped_method(1, 2, meep="moop")
89
90    method.assert_called_once_with(1, 2, meep="moop")
91
92
93def test_wrap_method_with_custom_client_info():
94    client_info = google.api_core.gapic_v1.client_info.ClientInfo(
95        python_version=1,
96        grpc_version=2,
97        api_core_version=3,
98        gapic_version=4,
99        client_library_version=5,
100    )
101    method = mock.Mock(spec=["__call__"])
102
103    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
104        method, client_info=client_info
105    )
106
107    wrapped_method(1, 2, meep="moop")
108
109    method.assert_called_once_with(1, 2, meep="moop", metadata=mock.ANY)
110
111    # Check that the custom client info was specified in the metadata.
112    metadata = method.call_args[1]["metadata"]
113    assert client_info.to_grpc_metadata() in metadata
114
115
116def test_invoke_wrapped_method_with_metadata():
117    method = mock.Mock(spec=["__call__"])
118
119    wrapped_method = google.api_core.gapic_v1.method.wrap_method(method)
120
121    wrapped_method(mock.sentinel.request, metadata=[("a", "b")])
122
123    method.assert_called_once_with(mock.sentinel.request, metadata=mock.ANY)
124    metadata = method.call_args[1]["metadata"]
125    # Metadata should have two items: the client info metadata and our custom
126    # metadata.
127    assert len(metadata) == 2
128    assert ("a", "b") in metadata
129
130
131def test_invoke_wrapped_method_with_metadata_as_none():
132    method = mock.Mock(spec=["__call__"])
133
134    wrapped_method = google.api_core.gapic_v1.method.wrap_method(method)
135
136    wrapped_method(mock.sentinel.request, metadata=None)
137
138    method.assert_called_once_with(mock.sentinel.request, metadata=mock.ANY)
139    metadata = method.call_args[1]["metadata"]
140    # Metadata should have just one items: the client info metadata.
141    assert len(metadata) == 1
142
143
144@mock.patch("time.sleep")
145def test_wrap_method_with_default_retry_and_timeout(unusued_sleep):
146    method = mock.Mock(
147        spec=["__call__"], side_effect=[exceptions.InternalServerError(None), 42]
148    )
149    default_retry = retry.Retry()
150    default_timeout = timeout.ConstantTimeout(60)
151    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
152        method, default_retry, default_timeout
153    )
154
155    result = wrapped_method()
156
157    assert result == 42
158    assert method.call_count == 2
159    method.assert_called_with(timeout=60, metadata=mock.ANY)
160
161
162@mock.patch("time.sleep")
163def test_wrap_method_with_default_retry_and_timeout_using_sentinel(unusued_sleep):
164    method = mock.Mock(
165        spec=["__call__"], side_effect=[exceptions.InternalServerError(None), 42]
166    )
167    default_retry = retry.Retry()
168    default_timeout = timeout.ConstantTimeout(60)
169    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
170        method, default_retry, default_timeout
171    )
172
173    result = wrapped_method(
174        retry=google.api_core.gapic_v1.method.DEFAULT,
175        timeout=google.api_core.gapic_v1.method.DEFAULT,
176    )
177
178    assert result == 42
179    assert method.call_count == 2
180    method.assert_called_with(timeout=60, metadata=mock.ANY)
181
182
183@mock.patch("time.sleep")
184def test_wrap_method_with_overriding_retry_and_timeout(unusued_sleep):
185    method = mock.Mock(spec=["__call__"], side_effect=[exceptions.NotFound(None), 42])
186    default_retry = retry.Retry()
187    default_timeout = timeout.ConstantTimeout(60)
188    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
189        method, default_retry, default_timeout
190    )
191
192    result = wrapped_method(
193        retry=retry.Retry(retry.if_exception_type(exceptions.NotFound)),
194        timeout=timeout.ConstantTimeout(22),
195    )
196
197    assert result == 42
198    assert method.call_count == 2
199    method.assert_called_with(timeout=22, metadata=mock.ANY)
200
201
202@mock.patch("time.sleep")
203@mock.patch(
204    "google.api_core.datetime_helpers.utcnow",
205    side_effect=_utcnow_monotonic(),
206    autospec=True,
207)
208def test_wrap_method_with_overriding_retry_deadline(utcnow, unused_sleep):
209    method = mock.Mock(
210        spec=["__call__"],
211        side_effect=([exceptions.InternalServerError(None)] * 4) + [42],
212    )
213    default_retry = retry.Retry()
214    default_timeout = timeout.ExponentialTimeout(deadline=60)
215    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
216        method, default_retry, default_timeout
217    )
218
219    # Overriding only the retry's deadline should also override the timeout's
220    # deadline.
221    result = wrapped_method(retry=default_retry.with_deadline(30))
222
223    assert result == 42
224    timeout_args = [call[1]["timeout"] for call in method.call_args_list]
225    assert timeout_args == [5.0, 10.0, 20.0, 26.0, 25.0]
226    assert utcnow.call_count == (
227        1
228        + 5  # First to set the deadline.
229        + 5  # One for each min(timeout, maximum, (DEADLINE - NOW).seconds)
230    )
231
232
233def test_wrap_method_with_overriding_timeout_as_a_number():
234    method = mock.Mock(spec=["__call__"], return_value=42)
235    default_retry = retry.Retry()
236    default_timeout = timeout.ConstantTimeout(60)
237    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
238        method, default_retry, default_timeout
239    )
240
241    result = wrapped_method(timeout=22)
242
243    assert result == 42
244    method.assert_called_once_with(timeout=22, metadata=mock.ANY)
245