Skip to content

Commit ed006ca

Browse files
authored
tests: add explicit coverage for retry members (#308)
See also: #283 This PR adds explicit coverage for each member of `google.cloud.storage.retry`. Together with PR #284, should return this package to 100% unit test coverage.
1 parent f072825 commit ed006ca

File tree

3 files changed

+179
-19
lines changed

3 files changed

+179
-19
lines changed

noxfile.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ def lint_setup_py(session):
7070

7171
def default(session):
7272
# Install all test dependencies, then install this package in-place.
73-
session.install("mock", "pytest", "pytest-cov")
73+
session.install(
74+
"mock", "pytest", "pytest-cov",
75+
)
7476
session.install("-e", ".")
7577

7678
# Run py.test against the unit tests.
@@ -144,7 +146,7 @@ def cover(session):
144146
test runs (not system test runs), and then erases coverage data.
145147
"""
146148
session.install("coverage", "pytest-cov")
147-
session.run("coverage", "report", "--show-missing", "--fail-under=99")
149+
session.run("coverage", "report", "--show-missing", "--fail-under=100")
148150

149151
session.run("coverage", "erase")
150152

synth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# Add templated files
2626
# ----------------------------------------------------------------------------
2727
templated_files = common.py_library(
28-
cov_level=99,
28+
cov_level=100,
2929
system_test_external_dependencies=[
3030
"google-cloud-iam",
3131
"google-cloud-pubsub < 2.0.0",

tests/unit/test_retry.py

Lines changed: 174 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,64 +14,222 @@
1414

1515
import unittest
1616

17-
from google.cloud.storage.retry import DEFAULT_RETRY
18-
from google.cloud.storage.retry import DEFAULT_RETRY_IF_GENERATION_SPECIFIED
19-
from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
20-
from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON
17+
import mock
18+
19+
20+
class Test_should_retry(unittest.TestCase):
21+
def _call_fut(self, exc):
22+
from google.cloud.storage import retry
23+
24+
return retry._should_retry(exc)
25+
26+
def test_w_retryable_types(self):
27+
from google.cloud.storage import retry
28+
29+
for exc_type in retry._RETRYABLE_TYPES:
30+
exc = exc_type("testing")
31+
self.assertTrue(self._call_fut(exc))
32+
33+
def test_w_google_api_call_error_hit(self):
34+
from google.api_core import exceptions
35+
36+
exc = exceptions.GoogleAPICallError("testing")
37+
exc.code = 408
38+
self.assertTrue(self._call_fut(exc))
39+
40+
def test_w_google_api_call_error_miss(self):
41+
from google.api_core import exceptions
42+
43+
exc = exceptions.GoogleAPICallError("testing")
44+
exc.code = 999
45+
self.assertFalse(self._call_fut(exc))
46+
47+
def test_w_requests_connection_error(self):
48+
exc = ValueError("testing")
49+
self.assertFalse(self._call_fut(exc))
2150

2251

2352
class TestConditionalRetryPolicy(unittest.TestCase):
53+
def _make_one(self, retry_policy, conditional_predicate, required_kwargs):
54+
from google.cloud.storage import retry
55+
56+
return retry.ConditionalRetryPolicy(
57+
retry_policy, conditional_predicate, required_kwargs
58+
)
59+
60+
def test_ctor(self):
61+
retry_policy = mock.Mock()
62+
conditional_predicate = mock.Mock()
63+
required_kwargs = ("kwarg",)
64+
65+
policy = self._make_one(retry_policy, conditional_predicate, required_kwargs)
66+
67+
self.assertIs(policy.retry_policy, retry_policy)
68+
self.assertIs(policy.conditional_predicate, conditional_predicate)
69+
self.assertEqual(policy.required_kwargs, required_kwargs)
70+
71+
def test_get_retry_policy_if_conditions_met_single_kwarg_hit(self):
72+
retry_policy = mock.Mock()
73+
conditional_predicate = mock.Mock(return_value=True)
74+
required_kwargs = ("foo",)
75+
policy = self._make_one(retry_policy, conditional_predicate, required_kwargs)
76+
77+
kwargs = {"foo": 1, "bar": 2, "baz": 3}
78+
result = policy.get_retry_policy_if_conditions_met(**kwargs)
79+
80+
self.assertIs(result, retry_policy)
81+
82+
conditional_predicate.assert_called_once_with(1)
83+
84+
def test_get_retry_policy_if_conditions_met_multiple_kwargs_miss(self):
85+
retry_policy = mock.Mock()
86+
conditional_predicate = mock.Mock(return_value=False)
87+
required_kwargs = ("foo", "bar")
88+
policy = self._make_one(retry_policy, conditional_predicate, required_kwargs)
89+
90+
kwargs = {"foo": 1, "bar": 2, "baz": 3}
91+
result = policy.get_retry_policy_if_conditions_met(**kwargs)
92+
93+
self.assertIsNone(result)
94+
95+
conditional_predicate.assert_called_once_with(1, 2)
96+
97+
98+
class Test_is_generation_specified(unittest.TestCase):
99+
def _call_fut(self, query_params):
100+
from google.cloud.storage import retry
101+
102+
return retry.is_generation_specified(query_params)
103+
104+
def test_w_empty(self):
105+
query_params = {}
106+
107+
self.assertFalse(self._call_fut(query_params))
108+
109+
def test_w_generation(self):
110+
query_params = {"generation": 123}
111+
112+
self.assertTrue(self._call_fut(query_params))
113+
114+
def test_wo_generation_w_if_generation_match(self):
115+
query_params = {"if_generation_match": 123}
116+
117+
self.assertTrue(self._call_fut(query_params))
118+
119+
120+
class Test_is_metageneration_specified(unittest.TestCase):
121+
def _call_fut(self, query_params):
122+
from google.cloud.storage import retry
123+
124+
return retry.is_metageneration_specified(query_params)
125+
126+
def test_w_empty(self):
127+
query_params = {}
128+
129+
self.assertFalse(self._call_fut(query_params))
130+
131+
def test_w_if_metageneration_match(self):
132+
query_params = {"if_metageneration_match": 123}
133+
134+
self.assertTrue(self._call_fut(query_params))
135+
136+
137+
class Test_is_etag_in_json(unittest.TestCase):
138+
def _call_fut(self, data):
139+
from google.cloud.storage import retry
140+
141+
return retry.is_etag_in_json(data)
142+
143+
@staticmethod
144+
def _make_json_data(**kw):
145+
import json
146+
147+
return json.dumps(kw)
148+
149+
def test_w_empty(self):
150+
data = self._make_json_data()
151+
152+
self.assertFalse(self._call_fut(data))
153+
154+
def test_w_etag_in_data(self):
155+
data = self._make_json_data(etag="123")
156+
157+
self.assertTrue(self._call_fut(data))
158+
159+
def test_w_empty_data(self):
160+
data = ""
161+
162+
self.assertFalse(self._call_fut(data))
163+
164+
165+
class Test_default_conditional_retry_policies(unittest.TestCase):
24166
def test_is_generation_specified_match_metageneration(self):
25-
conditional_policy = DEFAULT_RETRY_IF_GENERATION_SPECIFIED
167+
from google.cloud.storage import retry
168+
169+
conditional_policy = retry.DEFAULT_RETRY_IF_GENERATION_SPECIFIED
26170
policy = conditional_policy.get_retry_policy_if_conditions_met(
27171
query_params={"if_generation_match": 1}
28172
)
29-
self.assertEqual(policy, DEFAULT_RETRY)
173+
self.assertEqual(policy, retry.DEFAULT_RETRY)
30174

31175
def test_is_generation_specified_match_generation(self):
32-
conditional_policy = DEFAULT_RETRY_IF_GENERATION_SPECIFIED
176+
from google.cloud.storage import retry
177+
178+
conditional_policy = retry.DEFAULT_RETRY_IF_GENERATION_SPECIFIED
33179
policy = conditional_policy.get_retry_policy_if_conditions_met(
34180
query_params={"generation": 1}
35181
)
36-
self.assertEqual(policy, DEFAULT_RETRY)
182+
self.assertEqual(policy, retry.DEFAULT_RETRY)
37183

38184
def test_is_generation_specified_mismatch(self):
39-
conditional_policy = DEFAULT_RETRY_IF_GENERATION_SPECIFIED
185+
from google.cloud.storage import retry
186+
187+
conditional_policy = retry.DEFAULT_RETRY_IF_GENERATION_SPECIFIED
40188
policy = conditional_policy.get_retry_policy_if_conditions_met(
41189
query_params={"if_metageneration_match": 1}
42190
)
43191
self.assertEqual(policy, None)
44192

45193
def test_is_metageneration_specified_match(self):
46-
conditional_policy = DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
194+
from google.cloud.storage import retry
195+
196+
conditional_policy = retry.DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
47197
policy = conditional_policy.get_retry_policy_if_conditions_met(
48198
query_params={"if_metageneration_match": 1}
49199
)
50-
self.assertEqual(policy, DEFAULT_RETRY)
200+
self.assertEqual(policy, retry.DEFAULT_RETRY)
51201

52202
def test_is_metageneration_specified_mismatch(self):
53-
conditional_policy = DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
203+
from google.cloud.storage import retry
204+
205+
conditional_policy = retry.DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
54206
policy = conditional_policy.get_retry_policy_if_conditions_met(
55207
query_params={"if_generation_match": 1}
56208
)
57209
self.assertEqual(policy, None)
58210

59211
def test_is_etag_in_json_etag_match(self):
60-
conditional_policy = DEFAULT_RETRY_IF_ETAG_IN_JSON
212+
from google.cloud.storage import retry
213+
214+
conditional_policy = retry.DEFAULT_RETRY_IF_ETAG_IN_JSON
61215
policy = conditional_policy.get_retry_policy_if_conditions_met(
62216
query_params={"if_generation_match": 1}, data='{"etag": "12345678"}'
63217
)
64-
self.assertEqual(policy, DEFAULT_RETRY)
218+
self.assertEqual(policy, retry.DEFAULT_RETRY)
65219

66220
def test_is_etag_in_json_mismatch(self):
67-
conditional_policy = DEFAULT_RETRY_IF_ETAG_IN_JSON
221+
from google.cloud.storage import retry
222+
223+
conditional_policy = retry.DEFAULT_RETRY_IF_ETAG_IN_JSON
68224
policy = conditional_policy.get_retry_policy_if_conditions_met(
69225
query_params={"if_generation_match": 1}, data="{}"
70226
)
71227
self.assertEqual(policy, None)
72228

73229
def test_is_meta_or_etag_in_json_invalid(self):
74-
conditional_policy = DEFAULT_RETRY_IF_ETAG_IN_JSON
230+
from google.cloud.storage import retry
231+
232+
conditional_policy = retry.DEFAULT_RETRY_IF_ETAG_IN_JSON
75233
policy = conditional_policy.get_retry_policy_if_conditions_met(
76234
query_params={"if_generation_match": 1}, data="I am invalid JSON!"
77235
)

0 commit comments

Comments
 (0)