Merge ~woutervb/snapstore-client:move_to_pytest into snapstore-client:master
- Git
- lp:~woutervb/snapstore-client
- move_to_pytest
- Merge into master
Status: | Merged |
---|---|
Approved by: | Wouter van Bommel |
Approved revision: | 36af623c06a1bf7199697f412f5ce55450dfcdd7 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~woutervb/snapstore-client:move_to_pytest |
Merge into: | snapstore-client:master |
Diff against target: |
1820 lines (+534/-698) 10 files modified
Makefile (+4/-3) conftest.py (+70/-0) dev/null (+0/-67) requirements-dev.txt (+2/-3) snapstore_client/logic/tests/test_login.py (+95/-126) snapstore_client/logic/tests/test_overrides.py (+132/-156) snapstore_client/logic/tests/test_push.py (+32/-54) snapstore_client/tests/test_config.py (+52/-76) snapstore_client/tests/test_presentation_helpers.py (+71/-108) snapstore_client/tests/test_webservices.py (+76/-105) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Maximiliano Bertacchini | Approve | ||
Jonathan Hartley (community) | Approve | ||
Review via email: mp+414940@code.launchpad.net |
This proposal supersedes a proposal from 2022-01-28.
Commit message
Convert the testing to pytest
This will simplify changes in the future and resulted in a big cleanup.
The test_cli.py has been removed, as the cli will be replaced by click and has to be done completely.
Description of the change
Convert the testing to pytest
This will simplify changes in the future and resulted in a big cleanup.
The test_cli.py has been removed, as the cli will be replaced by click and has to be done completely.
Maximiliano Bertacchini (maxiberta) wrote : Posted in a previous version of this proposal | # |
Wouter van Bommel (woutervb) wrote : Posted in a previous version of this proposal | # |
Thanks for the feedback, will work on the comments.
Won't hide it for broader public, but it at least made me realize that we need some kind of styleguide on how / where to define fixtures
Jonathan Hartley (tartley) : Posted in a previous version of this proposal | # |
Jonathan Hartley (tartley) wrote : | # |
Bravely fought, tackling this churn!
I have one minor superficial FYI in the diffs, and one here. Ignore them if they are not today's problem:
Just FYI, when I run these test on a focal lxc, I get deprecation warnings from the use of 'responses' in test_login.py. I don't think this is due to your edits, but thought I'd mention it just in case you weren't aware and wanted to know:
=======
snapstore_
/home/
warn(
Jonathan Hartley (tartley) wrote : | # |
Another thought...
Maximiliano Bertacchini (maxiberta) wrote : | # |
+1 awesome. Check a couple of non-blocking comments below. Thanks!
Wouter van Bommel (woutervb) wrote : | # |
Thanks for the responses, will update (most) things you both found.
Preview Diff
1 | diff --git a/Makefile b/Makefile |
2 | index 76ddd0a..be1be80 100644 |
3 | --- a/Makefile |
4 | +++ b/Makefile |
5 | @@ -28,7 +28,7 @@ snap: |
6 | snapcraft |
7 | |
8 | test: $(ENV)/dev |
9 | - $(PYTHON3) -m unittest $(TESTS) 2>&1 |
10 | + $(PYTHON3) -m pytest |
11 | $(MAKE) --silent lint |
12 | |
13 | /snap/bin/documentation-builder: |
14 | @@ -39,7 +39,7 @@ docs: /snap/bin/documentation-builder |
15 | |
16 | |
17 | lint: $(ENV)/dev |
18 | - $(FLAKE8) $(SERVICE_PACKAGE) |
19 | + $(FLAKE8) $(SERVICE_PACKAGE) conftest.py |
20 | $(BLACK) --check . |
21 | |
22 | black: $(ENV)/dev |
23 | @@ -47,8 +47,9 @@ black: $(ENV)/dev |
24 | |
25 | coverage: $(ENV)/dev |
26 | $(PYTHON3) -m coverage erase |
27 | - $(PYTHON3) -m coverage run --include "$(SERVICE_PACKAGE)*" -m unittest $(TESTS) |
28 | + $(PYTHON3) -m coverage run --include "$(SERVICE_PACKAGE)*" -m pytest |
29 | $(PYTHON3) -m coverage html |
30 | + $(PYTHON3) -m coverage report |
31 | |
32 | clean: |
33 | rm -rf $(TMPDIR) |
34 | diff --git a/conftest.py b/conftest.py |
35 | new file mode 100644 |
36 | index 0000000..06c7ca0 |
37 | --- /dev/null |
38 | +++ b/conftest.py |
39 | @@ -0,0 +1,70 @@ |
40 | +import os.path |
41 | +import tempfile |
42 | +from unittest import mock |
43 | +from unittest.mock import patch |
44 | + |
45 | +from pymacaroons import Macaroon |
46 | +import pytest |
47 | + |
48 | +from snapstore_client.config import Config |
49 | + |
50 | + |
51 | +@pytest.fixture(scope="function") |
52 | +def ftmpdir(tmpdir): |
53 | + """Takes the tmpdir, but add a random path per function invocation""" |
54 | + with tempfile.TemporaryDirectory(dir=tmpdir) as new_tmpdir: |
55 | + yield new_tmpdir |
56 | + |
57 | + |
58 | +@pytest.fixture |
59 | +def mocked_xdgconfig(ftmpdir): |
60 | + with patch("xdg.BaseDirectory.xdg_config_home", ftmpdir), patch( |
61 | + "xdg.BaseDirectory.xdg_config_dirs", [ftmpdir] |
62 | + ): |
63 | + yield ftmpdir |
64 | + |
65 | + |
66 | +@pytest.fixture |
67 | +def mocked_config(mocked_xdgconfig): |
68 | + app_config_path = os.path.join(mocked_xdgconfig, "snap-store-proxy-client") |
69 | + os.makedirs(app_config_path) |
70 | + root = Macaroon(key="random-key") |
71 | + root.add_third_party_caveat("login.example.com", "sso-key", "payload") |
72 | + unbound_discharge = Macaroon( |
73 | + location="login.example.com", identifier="payload", key="sso-key" |
74 | + ) |
75 | + with open(os.path.join(app_config_path, "config.ini"), "w") as f: |
76 | + f.write( |
77 | + ( |
78 | + "[store:default]\n" |
79 | + "gw_url = {gw_url}\n" |
80 | + "sso_url = {sso_url}\n" |
81 | + "root = {root}\n" |
82 | + "unbound_discharge = {unbound_discharge}\n" |
83 | + ).format( |
84 | + gw_url="http://store.local/", |
85 | + sso_url="http://sso.local/", |
86 | + root=root.serialize(), |
87 | + unbound_discharge=unbound_discharge.serialize(), |
88 | + ) |
89 | + ) |
90 | + |
91 | + yield Config() |
92 | + |
93 | + |
94 | +@pytest.fixture |
95 | +def mocked_empty_config(mocked_xdgconfig): |
96 | + app_config_path = os.path.join(mocked_xdgconfig, "snap-store-proxy-client") |
97 | + os.makedirs(app_config_path) |
98 | + |
99 | + |
100 | +@pytest.fixture |
101 | +def mock_input(): |
102 | + with mock.patch("builtins.input") as input: |
103 | + yield input |
104 | + |
105 | + |
106 | +@pytest.fixture |
107 | +def mock_getpass(): |
108 | + with mock.patch("getpass.getpass") as getpass: |
109 | + yield getpass |
110 | diff --git a/requirements-dev.txt b/requirements-dev.txt |
111 | index 72daeb2..d9285a2 100644 |
112 | --- a/requirements-dev.txt |
113 | +++ b/requirements-dev.txt |
114 | @@ -1,8 +1,7 @@ |
115 | acceptable>=0.9 |
116 | coverage |
117 | -fixtures |
118 | flake8 |
119 | responses |
120 | -testscenarios |
121 | -testtools |
122 | black |
123 | +pytest |
124 | +testtools |
125 | \ No newline at end of file |
126 | diff --git a/snapstore_client/logic/tests/test_login.py b/snapstore_client/logic/tests/test_login.py |
127 | index d61ac1b..7dbfea1 100644 |
128 | --- a/snapstore_client/logic/tests/test_login.py |
129 | +++ b/snapstore_client/logic/tests/test_login.py |
130 | @@ -1,13 +1,13 @@ |
131 | # Copyright 2017 Canonical Ltd. |
132 | |
133 | +import pytest |
134 | import json |
135 | from unittest import mock |
136 | from urllib.parse import urljoin, urlparse |
137 | |
138 | -import fixtures |
139 | + |
140 | from pymacaroons import Macaroon |
141 | import responses |
142 | -from testtools import TestCase |
143 | from testtools.matchers import ( |
144 | ContainsDict, |
145 | Equals, |
146 | @@ -22,23 +22,11 @@ from snapstore_client.logic.login import login |
147 | from snapstore_client.tests import factory |
148 | |
149 | |
150 | -class LoginTests(TestCase): |
151 | - def setUp(self): |
152 | - super().setUp() |
153 | - self.default_gw_url = "http://store.local/" |
154 | - self.default_sso_url = "https://login.staging.ubuntu.com/" |
155 | - self.logger = self.useFixture(fixtures.FakeLogger()) |
156 | - self.config_path = self.useFixture(fixtures.TempDir()).path |
157 | - self.useFixture( |
158 | - fixtures.MonkeyPatch("xdg.BaseDirectory.xdg_config_home", self.config_path) |
159 | - ) |
160 | - self.useFixture( |
161 | - fixtures.MonkeyPatch( |
162 | - "xdg.BaseDirectory.xdg_config_dirs", [self.config_path] |
163 | - ) |
164 | - ) |
165 | - self.mock_input = self.useFixture(fixtures.MockPatch("builtins.input")).mock |
166 | - self.mock_getpass = self.useFixture(fixtures.MockPatch("getpass.getpass")).mock |
167 | +@pytest.mark.usefixtures("mocked_config") |
168 | +class TestLogin: |
169 | + |
170 | + default_gw_url = "http://store.local/" |
171 | + default_sso_url = "https://login.staging.ubuntu.com/" |
172 | |
173 | def make_responses_callback(self, response_templates): |
174 | full_responses = [] |
175 | @@ -86,21 +74,21 @@ class LoginTests(TestCase): |
176 | return macaroon.serialize() |
177 | |
178 | @responses.activate |
179 | - def test_login_sso_mismatch(self): |
180 | - self.mock_input.return_value = "user@example.org" |
181 | - self.mock_getpass.return_value = "secret" |
182 | + def test_login_sso_mismatch(self, mock_input, mock_getpass): |
183 | + mock_input.return_value = "user@example.org" |
184 | + mock_getpass.returnvalue = "secret" |
185 | macaroon = Macaroon() |
186 | macaroon.add_third_party_caveat("another.example.com", "", "") |
187 | self.add_issue_store_admin_response( |
188 | {"status": 200, "json": {"macaroon": macaroon.serialize()}} |
189 | ) |
190 | self.add_get_sso_discharge_response({"status": 401}) |
191 | - self.assertRaises(exceptions.StoreMacaroonSSOMismatch, login, self.make_args()) |
192 | + pytest.raises(exceptions.StoreMacaroonSSOMismatch, login, self.make_args()) |
193 | |
194 | @responses.activate |
195 | - def test_login_sso_bad_email(self): |
196 | - self.mock_input.return_value = "" |
197 | - self.mock_getpass.return_value = "" |
198 | + def test_login_sso_bad_email(self, mock_input, mock_getpass, caplog): |
199 | + mock_input.return_value = "" |
200 | + mock_getpass.return_value = "" |
201 | self.add_issue_store_admin_response( |
202 | {"status": 200, "json": {"macaroon": self.make_root_macaroon()}} |
203 | ) |
204 | @@ -111,19 +99,17 @@ class LoginTests(TestCase): |
205 | self.add_get_sso_discharge_response( |
206 | {"status": 401, "json": {"error_list": [auth_error]}} |
207 | ) |
208 | - self.assertEqual(1, login(self.make_args())) |
209 | - self.assertEqual( |
210 | - "Enter your Ubuntu One SSO credentials.\n" |
211 | - "Login failed.\n" |
212 | - "Authentication error: Invalid request data\n" |
213 | - "email: Enter a valid email address.\n", |
214 | - self.logger.output, |
215 | - ) |
216 | + assert 1 == login(self.make_args()) |
217 | + assert [ |
218 | + "Login failed.", |
219 | + "Authentication error: Invalid request data", |
220 | + "email: Enter a valid email address.", |
221 | + ] == caplog.messages |
222 | |
223 | @responses.activate |
224 | - def test_login_sso_unauthorized(self): |
225 | - self.mock_input.return_value = "user@example.org" |
226 | - self.mock_getpass.return_value = "secret" |
227 | + def test_login_sso_unauthorized(self, mock_input, mock_getpass, caplog): |
228 | + mock_input.return_value = "user@example.org" |
229 | + mock_getpass.return_value = "secret" |
230 | self.add_issue_store_admin_response( |
231 | {"status": 200, "json": {"macaroon": self.make_root_macaroon()}} |
232 | ) |
233 | @@ -131,51 +117,41 @@ class LoginTests(TestCase): |
234 | self.add_get_sso_discharge_response( |
235 | {"status": 401, "json": {"error_list": [auth_error]}} |
236 | ) |
237 | - self.assertEqual(1, login(self.make_args())) |
238 | - self.assertEqual( |
239 | - "Enter your Ubuntu One SSO credentials.\n" |
240 | - "Login failed.\n" |
241 | - "Authentication error: Provided email/password is not correct.\n", |
242 | - self.logger.output, |
243 | - ) |
244 | + assert 1 == login(self.make_args()) |
245 | + assert [ |
246 | + "Login failed.", |
247 | + "Authentication error: Provided email/password is not correct.", |
248 | + ] == caplog.messages |
249 | |
250 | @responses.activate |
251 | - def test_login_twofactor_required(self): |
252 | - self.mock_input.side_effect = ("user@example.org", "123456") |
253 | - self.mock_getpass.return_value = "secret" |
254 | + def test_login_twofactor_required(self, mock_input, mock_getpass): |
255 | + mock_input.side_effect = ("user@example.org", "123456") |
256 | + mock_getpass.return_value = "secret" |
257 | root = self.make_root_macaroon() |
258 | self.add_issue_store_admin_response({"status": 200, "json": {"macaroon": root}}) |
259 | self.add_get_sso_discharge_response( |
260 | {"status": 401, "json": {"error_list": [{"code": "twofactor-required"}]}}, |
261 | {"status": 200, "json": {"discharge_macaroon": "dummy"}}, |
262 | ) |
263 | - self.assertEqual(0, login(self.make_args())) |
264 | + assert 0 == login(self.make_args()) |
265 | |
266 | - self.assertIn("Enter your Ubuntu One SSO credentials.", self.logger.output) |
267 | - self.mock_input.assert_has_calls( |
268 | + mock_input.assert_has_calls( |
269 | [mock.call("Email: "), mock.call("Second-factor auth: ")] |
270 | ) |
271 | - self.mock_getpass.assert_called_once_with("Password: ") |
272 | - self.assertEqual(3, len(responses.calls)) |
273 | - self.assertEqual( |
274 | - { |
275 | - "email": "user@example.org", |
276 | - "password": "secret", |
277 | - "caveat_id": "payload", |
278 | - }, |
279 | - json.loads(responses.calls[1].request.body.decode()), |
280 | - ) |
281 | - self.assertEqual( |
282 | - { |
283 | - "email": "user@example.org", |
284 | - "password": "secret", |
285 | - "caveat_id": "payload", |
286 | - "otp": "123456", |
287 | - }, |
288 | - json.loads(responses.calls[2].request.body.decode()), |
289 | - ) |
290 | - self.assertThat( |
291 | - config.Config().parser, |
292 | + mock_getpass.assert_called_once_with("Password: ") |
293 | + assert 3 == len(responses.calls) |
294 | + assert { |
295 | + "email": "user@example.org", |
296 | + "password": "secret", |
297 | + "caveat_id": "payload", |
298 | + } == json.loads(responses.calls[1].request.body.decode()) |
299 | + assert { |
300 | + "email": "user@example.org", |
301 | + "password": "secret", |
302 | + "caveat_id": "payload", |
303 | + "otp": "123456", |
304 | + } == json.loads(responses.calls[2].request.body.decode()) |
305 | + assert ( |
306 | ContainsDict( |
307 | { |
308 | "store:default": MatchesDict( |
309 | @@ -188,13 +164,14 @@ class LoginTests(TestCase): |
310 | } |
311 | ), |
312 | } |
313 | - ), |
314 | + ).match(config.Config().parser) |
315 | + is None |
316 | ) |
317 | |
318 | @responses.activate |
319 | - def test_login_twofactor_not_required(self): |
320 | - self.mock_input.return_value = "user@example.org" |
321 | - self.mock_getpass.return_value = "secret" |
322 | + def test_login_twofactor_not_required(self, mock_input, mock_getpass): |
323 | + mock_input.return_value = "user@example.org" |
324 | + mock_getpass.return_value = "secret" |
325 | root = self.make_root_macaroon() |
326 | self.add_issue_store_admin_response({"status": 200, "json": {"macaroon": root}}) |
327 | self.add_get_sso_discharge_response( |
328 | @@ -202,20 +179,15 @@ class LoginTests(TestCase): |
329 | ) |
330 | login(self.make_args()) |
331 | |
332 | - self.assertIn("Enter your Ubuntu One SSO credentials.", self.logger.output) |
333 | - self.mock_input.assert_called_once_with("Email: ") |
334 | - self.mock_getpass.assert_called_once_with("Password: ") |
335 | - self.assertEqual(2, len(responses.calls)) |
336 | - self.assertEqual( |
337 | - { |
338 | - "email": "user@example.org", |
339 | - "password": "secret", |
340 | - "caveat_id": "payload", |
341 | - }, |
342 | - json.loads(responses.calls[1].request.body.decode()), |
343 | - ) |
344 | - self.assertThat( |
345 | - config.Config().parser, |
346 | + mock_input.assert_called_once_with("Email: ") |
347 | + mock_getpass.assert_called_once_with("Password: ") |
348 | + assert 2 == len(responses.calls) |
349 | + assert { |
350 | + "email": "user@example.org", |
351 | + "password": "secret", |
352 | + "caveat_id": "payload", |
353 | + } == json.loads(responses.calls[1].request.body.decode()) |
354 | + assert ( |
355 | ContainsDict( |
356 | { |
357 | "store:default": MatchesDict( |
358 | @@ -228,13 +200,14 @@ class LoginTests(TestCase): |
359 | } |
360 | ), |
361 | } |
362 | - ), |
363 | + ).match(config.Config().parser) |
364 | + is None |
365 | ) |
366 | |
367 | @responses.activate |
368 | - def test_login_with_email(self): |
369 | - self.mock_input.side_effect = Exception("shouldn't be called") |
370 | - self.mock_getpass.return_value = "secret" |
371 | + def test_login_with_email(self, mock_input, mock_getpass): |
372 | + mock_input.side_effect = Exception("shouldn't be called") |
373 | + mock_getpass.return_value = "secret" |
374 | root = self.make_root_macaroon() |
375 | self.add_issue_store_admin_response({"status": 200, "json": {"macaroon": root}}) |
376 | self.add_get_sso_discharge_response( |
377 | @@ -242,20 +215,15 @@ class LoginTests(TestCase): |
378 | ) |
379 | login(self.make_args(email="user@example.org")) |
380 | |
381 | - self.assertIn("Enter your Ubuntu One SSO credentials.", self.logger.output) |
382 | - self.mock_input.assert_not_called() |
383 | - self.mock_getpass.assert_called_once_with("Password: ") |
384 | - self.assertEqual(2, len(responses.calls)) |
385 | - self.assertEqual( |
386 | - { |
387 | - "email": "user@example.org", |
388 | - "password": "secret", |
389 | - "caveat_id": "payload", |
390 | - }, |
391 | - json.loads(responses.calls[1].request.body.decode()), |
392 | - ) |
393 | - self.assertThat( |
394 | - config.Config().parser, |
395 | + mock_input.assert_not_called() |
396 | + mock_getpass.assert_called_once_with("Password: ") |
397 | + assert 2 == len(responses.calls) |
398 | + assert { |
399 | + "email": "user@example.org", |
400 | + "password": "secret", |
401 | + "caveat_id": "payload", |
402 | + } == json.loads(responses.calls[1].request.body.decode()) |
403 | + assert ( |
404 | ContainsDict( |
405 | { |
406 | "store:default": MatchesDict( |
407 | @@ -268,15 +236,16 @@ class LoginTests(TestCase): |
408 | } |
409 | ), |
410 | } |
411 | - ), |
412 | + ).match(config.Config().parser) |
413 | + is None |
414 | ) |
415 | |
416 | @responses.activate |
417 | - def test_store_url(self): |
418 | + def test_store_url(self, mock_input, mock_getpass): |
419 | gw_url = "http://otherstore.local:1234/" |
420 | |
421 | - self.mock_input.return_value = "user@example.org" |
422 | - self.mock_getpass.return_value = "secret" |
423 | + mock_input.return_value = "user@example.org" |
424 | + mock_getpass.return_value = "secret" |
425 | root = self.make_root_macaroon() |
426 | self.add_issue_store_admin_response( |
427 | {"status": 200, "json": {"macaroon": root}}, gw_url=gw_url |
428 | @@ -286,11 +255,10 @@ class LoginTests(TestCase): |
429 | ) |
430 | login(self.make_args(store_url=gw_url)) |
431 | |
432 | - self.assertEqual(2, len(responses.calls)) |
433 | - self.assertEqual(responses.calls[0].request.url[: len(gw_url)], gw_url) |
434 | - self.assertTrue(responses.calls[1].request.url.startswith(self.default_sso_url)) |
435 | - self.assertThat( |
436 | - config.Config().parser, |
437 | + assert 2 == len(responses.calls) |
438 | + assert responses.calls[0].request.url[: len(gw_url)] == gw_url |
439 | + assert responses.calls[1].request.url.startswith(self.default_sso_url) |
440 | + assert ( |
441 | ContainsDict( |
442 | { |
443 | "store:default": ContainsDict( |
444 | @@ -300,15 +268,16 @@ class LoginTests(TestCase): |
445 | } |
446 | ), |
447 | } |
448 | - ), |
449 | + ).match(config.Config().parser) |
450 | + is None |
451 | ) |
452 | |
453 | @responses.activate |
454 | - def test_sso_url(self): |
455 | + def test_sso_url(self, mock_input, mock_getpass): |
456 | sso_url = "https://othersso.local:1234/" |
457 | |
458 | - self.mock_input.return_value = "user@example.org" |
459 | - self.mock_getpass.return_value = "secret" |
460 | + mock_input.return_value = "user@example.org" |
461 | + mock_getpass.return_value = "secret" |
462 | root = self.make_root_macaroon(sso_url=sso_url) |
463 | self.add_issue_store_admin_response({"status": 200, "json": {"macaroon": root}}) |
464 | self.add_get_sso_discharge_response( |
465 | @@ -316,11 +285,10 @@ class LoginTests(TestCase): |
466 | ) |
467 | login(self.make_args(sso_url=sso_url)) |
468 | |
469 | - self.assertEqual(2, len(responses.calls)) |
470 | - self.assertTrue(responses.calls[0].request.url.startswith(self.default_gw_url)) |
471 | - self.assertEqual(responses.calls[1].request.url[: len(sso_url)], sso_url) |
472 | - self.assertThat( |
473 | - config.Config().parser, |
474 | + assert 2 == len(responses.calls) |
475 | + assert responses.calls[0].request.url.startswith(self.default_gw_url) |
476 | + assert responses.calls[1].request.url[: len(sso_url)] == sso_url |
477 | + assert ( |
478 | ContainsDict( |
479 | { |
480 | "store:default": ContainsDict( |
481 | @@ -330,5 +298,6 @@ class LoginTests(TestCase): |
482 | } |
483 | ), |
484 | } |
485 | - ), |
486 | + ).match(config.Config().parser) |
487 | + is None |
488 | ) |
489 | diff --git a/snapstore_client/logic/tests/test_overrides.py b/snapstore_client/logic/tests/test_overrides.py |
490 | index 591b55d..c628810 100644 |
491 | --- a/snapstore_client/logic/tests/test_overrides.py |
492 | +++ b/snapstore_client/logic/tests/test_overrides.py |
493 | @@ -1,11 +1,11 @@ |
494 | # Copyright 2017 Canonical Ltd. |
495 | |
496 | import json |
497 | +import logging |
498 | from urllib.parse import urljoin |
499 | |
500 | -import fixtures |
501 | import responses |
502 | -from testtools import TestCase |
503 | +import pytest |
504 | |
505 | from snapstore_client import config |
506 | from snapstore_client.logic.overrides import ( |
507 | @@ -15,26 +15,23 @@ from snapstore_client.logic.overrides import ( |
508 | ) |
509 | from snapstore_client.tests import ( |
510 | factory, |
511 | - testfixtures, |
512 | ) |
513 | |
514 | |
515 | -class OverridesTests(TestCase): |
516 | - def test_list_overrides_no_store_config(self): |
517 | - self.useFixture(testfixtures.ConfigFixture(empty=True)) |
518 | - logger = self.useFixture(fixtures.FakeLogger()) |
519 | +class TestOverrides: |
520 | + @pytest.mark.usefixtures("mocked_empty_config") |
521 | + def test_list_overrides_no_store_config(self, caplog): |
522 | rc = list_overrides(factory.Args(snap_name="some-snap", series="16")) |
523 | - self.assertEqual(rc, 1) |
524 | - self.assertEqual( |
525 | - logger.output, |
526 | + assert rc == 1 |
527 | + assert [ |
528 | "No store configuration found. " |
529 | - 'Have you run "snap-store-proxy-client login"?\n', |
530 | - ) |
531 | + 'Have you run "snap-store-proxy-client login"?' |
532 | + ] == caplog.messages |
533 | |
534 | + @pytest.mark.usefixtures("mocked_config") |
535 | @responses.activate |
536 | - def test_list_overrides_online(self): |
537 | - self.useFixture(testfixtures.ConfigFixture()) |
538 | - logger = self.useFixture(fixtures.FakeLogger()) |
539 | + def test_list_overrides_online(self, caplog): |
540 | + caplog.set_level(logging.DEBUG) |
541 | snap_id = factory.generate_snap_id() |
542 | overrides = [ |
543 | factory.SnapDeviceGateway.Override(snap_id=snap_id, snap_name="mysnap"), |
544 | @@ -56,18 +53,17 @@ class OverridesTests(TestCase): |
545 | responses.add("GET", overrides_url, status=200, json={"overrides": overrides}) |
546 | |
547 | list_overrides(factory.Args(snap_name="mysnap", series="16", password=False)) |
548 | - self.assertEqual( |
549 | - "mysnap stable amd64 1 (upstream 2)\n" |
550 | - "mysnap foo/stable i386 3 (upstream 4)\n", |
551 | - logger.output, |
552 | - ) |
553 | + assert [ |
554 | + "mysnap stable amd64 1 (upstream 2)", |
555 | + "mysnap foo/stable i386 3 (upstream 4)", |
556 | + ] == caplog.messages |
557 | # We shouldn't have Basic Authorization headers, but Macaroon |
558 | - self.assertNotIn("Basic", responses.calls[0].request.headers["Authorization"]) |
559 | + assert "Basic" not in responses.calls[0].request.headers["Authorization"] |
560 | |
561 | + @pytest.mark.usefixtures("mocked_config") |
562 | @responses.activate |
563 | - def test_list_overrides_offline(self): |
564 | - self.useFixture(testfixtures.ConfigFixture()) |
565 | - logger = self.useFixture(fixtures.FakeLogger()) |
566 | + def test_list_overrides_offline(self, caplog): |
567 | + caplog.set_level(logging.DEBUG) |
568 | snap_id = factory.generate_snap_id() |
569 | overrides = [ |
570 | factory.SnapDeviceGateway.Override(snap_id=snap_id, snap_name="mysnap"), |
571 | @@ -89,19 +85,17 @@ class OverridesTests(TestCase): |
572 | responses.add("GET", overrides_url, status=200, json={"overrides": overrides}) |
573 | |
574 | list_overrides(factory.Args(snap_name="mysnap", series="16", password="test")) |
575 | - self.assertEqual( |
576 | - "mysnap stable amd64 1 (upstream 2)\n" |
577 | - "mysnap foo/stable i386 3 (upstream 4)\n", |
578 | - logger.output, |
579 | - ) |
580 | - self.assertEqual( |
581 | - "Basic YWRtaW46dGVzdA==", |
582 | - responses.calls[0].request.headers["Authorization"], |
583 | + assert [ |
584 | + "mysnap stable amd64 1 (upstream 2)", |
585 | + "mysnap foo/stable i386 3 (upstream 4)", |
586 | + ] == caplog.messages |
587 | + assert ( |
588 | + "Basic YWRtaW46dGVzdA==" |
589 | + == responses.calls[0].request.headers["Authorization"] |
590 | ) |
591 | |
592 | - def test_override_no_store_config(self): |
593 | - self.useFixture(testfixtures.ConfigFixture(empty=True)) |
594 | - logger = self.useFixture(fixtures.FakeLogger()) |
595 | + @pytest.mark.usefixtures("mocked_empty_config") |
596 | + def test_override_no_store_config(self, caplog): |
597 | rc = override( |
598 | factory.Args( |
599 | snap_name="some-snap", |
600 | @@ -110,17 +104,16 @@ class OverridesTests(TestCase): |
601 | password=False, |
602 | ) |
603 | ) |
604 | - self.assertEqual(rc, 1) |
605 | - self.assertEqual( |
606 | - logger.output, |
607 | + assert rc == 1 |
608 | + assert [ |
609 | "No store configuration found. " |
610 | - 'Have you run "snap-store-proxy-client login"?\n', |
611 | - ) |
612 | + 'Have you run "snap-store-proxy-client login"?' |
613 | + ] == caplog.messages |
614 | |
615 | + @pytest.mark.usefixtures("mocked_config") |
616 | @responses.activate |
617 | - def test_override_online(self): |
618 | - self.useFixture(testfixtures.ConfigFixture()) |
619 | - logger = self.useFixture(fixtures.FakeLogger()) |
620 | + def test_override_online(self, caplog): |
621 | + caplog.set_level(logging.DEBUG) |
622 | snap_id = factory.generate_snap_id() |
623 | overrides = [ |
624 | factory.SnapDeviceGateway.Override(snap_id=snap_id, snap_name="mysnap"), |
625 | @@ -149,35 +142,32 @@ class OverridesTests(TestCase): |
626 | password=False, |
627 | ) |
628 | ) |
629 | - self.assertEqual( |
630 | - [ |
631 | - { |
632 | - "snap_name": "mysnap", |
633 | - "revision": 1, |
634 | - "channel": "stable", |
635 | - "series": "16", |
636 | - }, |
637 | - { |
638 | - "snap_name": "mysnap", |
639 | - "revision": 3, |
640 | - "channel": "foo/stable", |
641 | - "series": "16", |
642 | - }, |
643 | - ], |
644 | - json.loads(responses.calls[0].request.body.decode()), |
645 | - ) |
646 | - self.assertEqual( |
647 | - "mysnap stable amd64 1 (upstream 2)\n" |
648 | - "mysnap foo/stable i386 3 (upstream 4)\n", |
649 | - logger.output, |
650 | - ) |
651 | + assert [ |
652 | + { |
653 | + "snap_name": "mysnap", |
654 | + "revision": 1, |
655 | + "channel": "stable", |
656 | + "series": "16", |
657 | + }, |
658 | + { |
659 | + "snap_name": "mysnap", |
660 | + "revision": 3, |
661 | + "channel": "foo/stable", |
662 | + "series": "16", |
663 | + }, |
664 | + ] == json.loads(responses.calls[0].request.body.decode()) |
665 | + assert [ |
666 | + "mysnap stable amd64 1 (upstream 2)", |
667 | + "mysnap foo/stable i386 3 (upstream 4)", |
668 | + ] == caplog.messages |
669 | + |
670 | # We shouldn't have Basic Authorization headers, but Macaroon |
671 | - self.assertNotIn("Basic", responses.calls[0].request.headers["Authorization"]) |
672 | + assert "Basic" not in responses.calls[0].request.headers["Authorization"] |
673 | |
674 | + @pytest.mark.usefixtures("mocked_config") |
675 | @responses.activate |
676 | - def test_override_offline(self): |
677 | - self.useFixture(testfixtures.ConfigFixture()) |
678 | - logger = self.useFixture(fixtures.FakeLogger()) |
679 | + def test_override_offline(self, caplog): |
680 | + caplog.set_level(logging.DEBUG) |
681 | snap_id = factory.generate_snap_id() |
682 | overrides = [ |
683 | factory.SnapDeviceGateway.Override(snap_id=snap_id, snap_name="mysnap"), |
684 | @@ -206,52 +196,46 @@ class OverridesTests(TestCase): |
685 | password="test", |
686 | ) |
687 | ) |
688 | - self.assertEqual( |
689 | - [ |
690 | - { |
691 | - "snap_name": "mysnap", |
692 | - "revision": 1, |
693 | - "channel": "stable", |
694 | - "series": "16", |
695 | - }, |
696 | - { |
697 | - "snap_name": "mysnap", |
698 | - "revision": 3, |
699 | - "channel": "foo/stable", |
700 | - "series": "16", |
701 | - }, |
702 | - ], |
703 | - json.loads(responses.calls[0].request.body.decode()), |
704 | - ) |
705 | - self.assertEqual( |
706 | - "mysnap stable amd64 1 (upstream 2)\n" |
707 | - "mysnap foo/stable i386 3 (upstream 4)\n", |
708 | - logger.output, |
709 | - ) |
710 | - self.assertEqual( |
711 | - "Basic YWRtaW46dGVzdA==", |
712 | - responses.calls[0].request.headers["Authorization"], |
713 | + assert [ |
714 | + { |
715 | + "snap_name": "mysnap", |
716 | + "revision": 1, |
717 | + "channel": "stable", |
718 | + "series": "16", |
719 | + }, |
720 | + { |
721 | + "snap_name": "mysnap", |
722 | + "revision": 3, |
723 | + "channel": "foo/stable", |
724 | + "series": "16", |
725 | + }, |
726 | + ] == json.loads(responses.calls[0].request.body.decode()) |
727 | + assert [ |
728 | + "mysnap stable amd64 1 (upstream 2)", |
729 | + "mysnap foo/stable i386 3 (upstream 4)", |
730 | + ] == caplog.messages |
731 | + assert ( |
732 | + "Basic YWRtaW46dGVzdA==" |
733 | + == responses.calls[0].request.headers["Authorization"] |
734 | ) |
735 | |
736 | - def test_delete_override_no_store_config(self): |
737 | - self.useFixture(testfixtures.ConfigFixture(empty=True)) |
738 | - logger = self.useFixture(fixtures.FakeLogger()) |
739 | + @pytest.mark.usefixtures("mocked_empty_config") |
740 | + def test_delete_override_no_store_config(self, caplog): |
741 | rc = delete_override( |
742 | factory.Args( |
743 | snap_name="some-snap", channels=["stable"], series="16", password=False |
744 | ) |
745 | ) |
746 | - self.assertEqual(rc, 1) |
747 | - self.assertEqual( |
748 | - logger.output, |
749 | + assert rc == 1 |
750 | + assert [ |
751 | "No store configuration found. " |
752 | - 'Have you run "snap-store-proxy-client login"?\n', |
753 | - ) |
754 | + 'Have you run "snap-store-proxy-client login"?' |
755 | + ] == caplog.messages |
756 | |
757 | + @pytest.mark.usefixtures("mocked_config") |
758 | @responses.activate |
759 | - def test_delete_override_online(self): |
760 | - self.useFixture(testfixtures.ConfigFixture()) |
761 | - logger = self.useFixture(fixtures.FakeLogger()) |
762 | + def test_delete_override_online(self, caplog): |
763 | + caplog.set_level(logging.DEBUG) |
764 | snap_id = factory.generate_snap_id() |
765 | overrides = [ |
766 | factory.SnapDeviceGateway.Override( |
767 | @@ -282,35 +266,31 @@ class OverridesTests(TestCase): |
768 | password=False, |
769 | ) |
770 | ) |
771 | - self.assertEqual( |
772 | - [ |
773 | - { |
774 | - "snap_name": "mysnap", |
775 | - "revision": None, |
776 | - "channel": "stable", |
777 | - "series": "16", |
778 | - }, |
779 | - { |
780 | - "snap_name": "mysnap", |
781 | - "revision": None, |
782 | - "channel": "foo/stable", |
783 | - "series": "16", |
784 | - }, |
785 | - ], |
786 | - json.loads(responses.calls[0].request.body.decode()), |
787 | - ) |
788 | - self.assertEqual( |
789 | - "mysnap stable amd64 is tracking upstream (revision 2)\n" |
790 | - "mysnap foo/stable i386 is tracking upstream (revision 4)\n", |
791 | - logger.output, |
792 | - ) |
793 | + assert [ |
794 | + { |
795 | + "snap_name": "mysnap", |
796 | + "revision": None, |
797 | + "channel": "stable", |
798 | + "series": "16", |
799 | + }, |
800 | + { |
801 | + "snap_name": "mysnap", |
802 | + "revision": None, |
803 | + "channel": "foo/stable", |
804 | + "series": "16", |
805 | + }, |
806 | + ] == json.loads(responses.calls[0].request.body.decode()) |
807 | + assert [ |
808 | + "mysnap stable amd64 is tracking upstream (revision 2)", |
809 | + "mysnap foo/stable i386 is tracking upstream (revision 4)", |
810 | + ] == caplog.messages |
811 | # We shouldn't have Basic Authorization headers, but Macaroon |
812 | - self.assertNotIn("Basic", responses.calls[0].request.headers["Authorization"]) |
813 | + assert "Basic" not in responses.calls[0].request.headers["Authorization"] |
814 | |
815 | + @pytest.mark.usefixtures("mocked_config") |
816 | @responses.activate |
817 | - def test_delete_override_offline(self): |
818 | - self.useFixture(testfixtures.ConfigFixture()) |
819 | - logger = self.useFixture(fixtures.FakeLogger()) |
820 | + def test_delete_override_offline(self, caplog): |
821 | + caplog.set_level(logging.DEBUG) |
822 | snap_id = factory.generate_snap_id() |
823 | overrides = [ |
824 | factory.SnapDeviceGateway.Override( |
825 | @@ -341,29 +321,25 @@ class OverridesTests(TestCase): |
826 | password="test", |
827 | ) |
828 | ) |
829 | - self.assertEqual( |
830 | - [ |
831 | - { |
832 | - "snap_name": "mysnap", |
833 | - "revision": None, |
834 | - "channel": "stable", |
835 | - "series": "16", |
836 | - }, |
837 | - { |
838 | - "snap_name": "mysnap", |
839 | - "revision": None, |
840 | - "channel": "foo/stable", |
841 | - "series": "16", |
842 | - }, |
843 | - ], |
844 | - json.loads(responses.calls[0].request.body.decode()), |
845 | - ) |
846 | - self.assertEqual( |
847 | - "mysnap stable amd64 is tracking upstream (revision 2)\n" |
848 | - "mysnap foo/stable i386 is tracking upstream (revision 4)\n", |
849 | - logger.output, |
850 | - ) |
851 | - self.assertEqual( |
852 | - "Basic YWRtaW46dGVzdA==", |
853 | - responses.calls[0].request.headers["Authorization"], |
854 | + assert [ |
855 | + { |
856 | + "snap_name": "mysnap", |
857 | + "revision": None, |
858 | + "channel": "stable", |
859 | + "series": "16", |
860 | + }, |
861 | + { |
862 | + "snap_name": "mysnap", |
863 | + "revision": None, |
864 | + "channel": "foo/stable", |
865 | + "series": "16", |
866 | + }, |
867 | + ] == json.loads(responses.calls[0].request.body.decode()) |
868 | + assert [ |
869 | + "mysnap stable amd64 is tracking upstream (revision 2)", |
870 | + "mysnap foo/stable i386 is tracking upstream (revision 4)", |
871 | + ] == caplog.messages |
872 | + assert ( |
873 | + "Basic YWRtaW46dGVzdA==" |
874 | + == responses.calls[0].request.headers["Authorization"] |
875 | ) |
876 | diff --git a/snapstore_client/logic/tests/test_push.py b/snapstore_client/logic/tests/test_push.py |
877 | index e96088f..05b4cee 100644 |
878 | --- a/snapstore_client/logic/tests/test_push.py |
879 | +++ b/snapstore_client/logic/tests/test_push.py |
880 | @@ -1,10 +1,9 @@ |
881 | +import pytest |
882 | import json |
883 | from pathlib import Path |
884 | from urllib.parse import urljoin |
885 | |
886 | -import fixtures |
887 | import responses |
888 | -from testtools import TestCase |
889 | |
890 | from snapstore_client.logic.push import ( |
891 | ChannelMapExistsException, |
892 | @@ -17,11 +16,9 @@ from snapstore_client.logic.push import ( |
893 | ) |
894 | |
895 | |
896 | -class pushTests(TestCase): |
897 | - def setUp(self): |
898 | - super().setUp() |
899 | +class Testpush: |
900 | + def setup_method(self): |
901 | self.default_gw_url = "http://store.local" |
902 | - self.logger = self.useFixture(fixtures.FakeLogger()) |
903 | current_path = Path(__file__).resolve().parent |
904 | with (current_path / "test-snap-map.json").open() as fh: |
905 | self.snap_map = json.load(fh) |
906 | @@ -39,21 +36,15 @@ class pushTests(TestCase): |
907 | request = responses.calls[0].request |
908 | payload = json.loads(request.body.decode("utf-8")) |
909 | |
910 | - self.assertEqual( |
911 | - payload["snaps"][0]["package_type"], |
912 | - "snap", |
913 | - ) |
914 | - self.assertEqual( |
915 | - "Basic YWRtaW46dGVzdA==", |
916 | - request.headers["Authorization"], |
917 | - ) |
918 | + assert payload["snaps"][0]["package_type"] == "snap" |
919 | + assert "Basic YWRtaW46dGVzdA==" == request.headers["Authorization"] |
920 | |
921 | @responses.activate |
922 | def test_push_ident_failed(self): |
923 | ident_url = urljoin(self.default_gw_url, "/snaps/update") |
924 | responses.add("POST", ident_url, status=500) |
925 | |
926 | - self.assertRaises(pushException, _push_ident, self.store, "test", self.snap_map) |
927 | + pytest.raises(pushException, _push_ident, self.store, "test", self.snap_map) |
928 | |
929 | @responses.activate |
930 | def test_push_revs(self): |
931 | @@ -65,25 +56,22 @@ class pushTests(TestCase): |
932 | request = responses.calls[0].request |
933 | payload = json.loads(request.body.decode("utf-8")) |
934 | |
935 | - self.assertEqual(payload[0]["package_type"], "snap") |
936 | - self.assertEqual( |
937 | - "Basic YWRtaW46dGVzdA==", |
938 | - request.headers["Authorization"], |
939 | - ) |
940 | + assert payload[0]["package_type"] == "snap" |
941 | + assert "Basic YWRtaW46dGVzdA==" == request.headers["Authorization"] |
942 | |
943 | @responses.activate |
944 | def test_push_revs_unexpected_status_code(self): |
945 | revs_url = urljoin(self.default_gw_url, "/revisions/create") |
946 | responses.add("POST", revs_url, status=302) |
947 | |
948 | - self.assertRaises(pushException, _push_revs, self.store, "test", self.snap_map) |
949 | + pytest.raises(pushException, _push_revs, self.store, "test", self.snap_map) |
950 | |
951 | @responses.activate |
952 | def test_push_revs_failed(self): |
953 | revs_url = urljoin(self.default_gw_url, "/revisions/create") |
954 | responses.add("POST", revs_url, status=500) |
955 | |
956 | - self.assertRaises(pushException, _push_revs, self.store, "test", self.snap_map) |
957 | + pytest.raises(pushException, _push_revs, self.store, "test", self.snap_map) |
958 | |
959 | @responses.activate |
960 | def test_push_map(self): |
961 | @@ -96,29 +84,20 @@ class pushTests(TestCase): |
962 | |
963 | filter_request = responses.calls[0].request |
964 | filter_payload = json.loads(filter_request.body.decode("utf-8")) |
965 | - self.assertEqual( |
966 | - filter_payload["filters"], |
967 | - [ |
968 | - { |
969 | - "series": "16", |
970 | - "package_type": "snap", |
971 | - "snap_id": self.snap_map["snap-id"], |
972 | - }, |
973 | - ], |
974 | - ) |
975 | - self.assertEqual( |
976 | - "Basic YWRtaW46dGVzdA==", |
977 | - filter_request.headers["Authorization"], |
978 | - ) |
979 | + assert filter_payload["filters"] == [ |
980 | + { |
981 | + "series": "16", |
982 | + "package_type": "snap", |
983 | + "snap_id": self.snap_map["snap-id"], |
984 | + }, |
985 | + ] |
986 | + assert "Basic YWRtaW46dGVzdA==" == filter_request.headers["Authorization"] |
987 | |
988 | chanmap_update_request = responses.calls[1].request |
989 | chanmap_update_payload = json.loads( |
990 | chanmap_update_request.body.decode("utf-8"), |
991 | ) |
992 | - self.assertEqual( |
993 | - chanmap_update_payload["release_requests"][0]["package_type"], |
994 | - "snap", |
995 | - ) |
996 | + assert chanmap_update_payload["release_requests"][0]["package_type"] == "snap" |
997 | |
998 | @responses.activate |
999 | def test_push_map_failed(self): |
1000 | @@ -127,7 +106,7 @@ class pushTests(TestCase): |
1001 | responses.add("POST", filter_url, status=200, json={}) |
1002 | responses.add("POST", update_url, status=500) |
1003 | |
1004 | - self.assertRaises( |
1005 | + pytest.raises( |
1006 | pushException, _push_channelmap, self.store, "test", self.snap_map |
1007 | ) |
1008 | |
1009 | @@ -139,7 +118,7 @@ class pushTests(TestCase): |
1010 | responses.add("POST", filter_url, status=200, json=exists) |
1011 | responses.add("POST", update_url, status=200) |
1012 | |
1013 | - self.assertRaises( |
1014 | + pytest.raises( |
1015 | ChannelMapExistsException, |
1016 | _push_channelmap, |
1017 | self.store, |
1018 | @@ -157,9 +136,9 @@ class pushTests(TestCase): |
1019 | |
1020 | _push_channelmap(self.store, "test", self.snap_map, True) |
1021 | |
1022 | - self.assertEqual( |
1023 | - "Basic YWRtaW46dGVzdA==", |
1024 | - responses.calls[0].request.headers["Authorization"], |
1025 | + assert ( |
1026 | + "Basic YWRtaW46dGVzdA==" |
1027 | + == responses.calls[0].request.headers["Authorization"] |
1028 | ) |
1029 | |
1030 | def test_split_assertions(self): |
1031 | @@ -180,13 +159,12 @@ class pushTests(TestCase): |
1032 | split_assertions = _split_assertions(self.snap_assert) |
1033 | _add_assertion_to_service(self.store, "test", split_assertions) |
1034 | |
1035 | - self.assertIn( |
1036 | - "display-name: Tom Wardill (Ω)", |
1037 | - responses.calls[0].request.body.decode("utf-8"), |
1038 | - ) |
1039 | - self.assertEqual( |
1040 | - "Basic YWRtaW46dGVzdA==", |
1041 | - responses.calls[0].request.headers["Authorization"], |
1042 | + assert "display-name: Tom Wardill (Ω)" in responses.calls[ |
1043 | + 0 |
1044 | + ].request.body.decode("utf-8") |
1045 | + assert ( |
1046 | + "Basic YWRtaW46dGVzdA==" |
1047 | + == responses.calls[0].request.headers["Authorization"] |
1048 | ) |
1049 | |
1050 | @responses.activate |
1051 | @@ -195,7 +173,7 @@ class pushTests(TestCase): |
1052 | responses.add("POST", assert_url, status=302) |
1053 | |
1054 | split_assertions = _split_assertions(self.snap_assert) |
1055 | - self.assertRaises( |
1056 | + pytest.raises( |
1057 | pushException, |
1058 | _add_assertion_to_service, |
1059 | self.store, |
1060 | @@ -209,7 +187,7 @@ class pushTests(TestCase): |
1061 | responses.add("POST", assert_url, status=500) |
1062 | |
1063 | split_assertions = _split_assertions(self.snap_assert) |
1064 | - self.assertRaises( |
1065 | + pytest.raises( |
1066 | pushException, |
1067 | _add_assertion_to_service, |
1068 | self.store, |
1069 | diff --git a/snapstore_client/tests/test_cli.py b/snapstore_client/tests/test_cli.py |
1070 | deleted file mode 100644 |
1071 | index 3ba9dc9..0000000 |
1072 | --- a/snapstore_client/tests/test_cli.py |
1073 | +++ /dev/null |
1074 | @@ -1,67 +0,0 @@ |
1075 | -# Copyright 2017 Canonical Ltd. This software is licensed under the |
1076 | -# GNU General Public License version 3 (see the file LICENSE). |
1077 | - |
1078 | -import logging |
1079 | - |
1080 | -import fixtures |
1081 | -from testtools import TestCase |
1082 | - |
1083 | -from snapstore_client import cli |
1084 | - |
1085 | - |
1086 | -class ConfigureLoggingTests(TestCase): |
1087 | - def setUp(self): |
1088 | - super().setUp() |
1089 | - self.logger = logging.getLogger(__name__) |
1090 | - self.addCleanup( |
1091 | - self._restoreLogger, |
1092 | - self.logger, |
1093 | - self.logger.level, |
1094 | - list(self.logger.handlers), |
1095 | - ) |
1096 | - self.stdout = self.useFixture(fixtures.StringStream("stdout")).stream |
1097 | - self.stdout.fileno = lambda: 1 |
1098 | - self.useFixture(fixtures.MonkeyPatch("sys.stdout", self.stdout)) |
1099 | - self.stderr = self.useFixture(fixtures.StringStream("stderr")).stream |
1100 | - self.useFixture(fixtures.MonkeyPatch("sys.stderr", self.stderr)) |
1101 | - |
1102 | - @staticmethod |
1103 | - def _restoreLogger(logger, level, handlers): |
1104 | - logger.setLevel(logger.level) |
1105 | - for handler in list(logger.handlers): |
1106 | - logger.removeHandler(handler) |
1107 | - for handler in handlers: |
1108 | - logger.addHandler(handler) |
1109 | - |
1110 | - def test_log_levels(self): |
1111 | - self.useFixture(fixtures.MonkeyPatch("os.isatty", lambda fd: True)) |
1112 | - cli.configure_logging(__name__) |
1113 | - self.assertEqual(logging.INFO, self.logger.level) |
1114 | - self.logger.debug("Debug") |
1115 | - self.logger.info("Info") |
1116 | - self.logger.warning("Warning: %s", "smoke") |
1117 | - self.logger.error("Error: %s", "fire") |
1118 | - self.stdout.seek(0) |
1119 | - self.assertEqual("Info\nWarning: smoke\n", self.stdout.read()) |
1120 | - self.stderr.seek(0) |
1121 | - self.assertEqual("\033[0;31mError: fire\033[0m\n", self.stderr.read()) |
1122 | - |
1123 | - def test_requests_log_level_default(self): |
1124 | - cli.configure_logging(__name__) |
1125 | - self.assertEqual(logging.WARNING, logging.getLogger("requests").level) |
1126 | - |
1127 | - def test_requests_log_level_debug(self): |
1128 | - cli.configure_logging(__name__, logging.DEBUG) |
1129 | - self.assertEqual(logging.DEBUG, logging.getLogger("requests").level) |
1130 | - |
1131 | - def test_requests_log_level_error(self): |
1132 | - cli.configure_logging(__name__, logging.ERROR) |
1133 | - self.assertEqual(logging.ERROR, logging.getLogger("requests").level) |
1134 | - |
1135 | - def test_no_tty(self): |
1136 | - self.useFixture(fixtures.MonkeyPatch("os.isatty", lambda fd: False)) |
1137 | - self.useFixture(fixtures.EnvironmentVariable("TERM", "xterm")) |
1138 | - cli.configure_logging(__name__) |
1139 | - self.logger.error("Error: %s", "fire") |
1140 | - self.stderr.seek(0) |
1141 | - self.assertEqual("Error: fire\n", self.stderr.read()) |
1142 | diff --git a/snapstore_client/tests/test_config.py b/snapstore_client/tests/test_config.py |
1143 | index 7243554..c2cca69 100644 |
1144 | --- a/snapstore_client/tests/test_config.py |
1145 | +++ b/snapstore_client/tests/test_config.py |
1146 | @@ -1,81 +1,57 @@ |
1147 | # Copyright 2017 Canonical Ltd. This software is licensed under the |
1148 | # GNU General Public License version 3 (see the file LICENSE). |
1149 | +import os |
1150 | |
1151 | -import os.path |
1152 | -from textwrap import dedent |
1153 | +from snapstore_client.config import Config |
1154 | |
1155 | -from testtools import TestCase |
1156 | |
1157 | -from snapstore_client.config import Config |
1158 | -from snapstore_client.tests.testfixtures import ( |
1159 | - ConfigFixture, |
1160 | - XDGConfigDirFixture, |
1161 | -) |
1162 | - |
1163 | - |
1164 | -class ConfigTests(TestCase): |
1165 | - def test_no_config(self): |
1166 | - xdg_path = self.useFixture(XDGConfigDirFixture()).path |
1167 | - config_ini = os.path.join(xdg_path, Config.xdg_name, "config.ini") |
1168 | - self.assertFalse(os.path.exists(config_ini)) |
1169 | - Config() |
1170 | - |
1171 | - def test_init_loads(self): |
1172 | - self.useFixture(ConfigFixture()) |
1173 | - cfg = Config() |
1174 | - self.assertIsNotNone(cfg.get("store:default", "gw_url")) |
1175 | - |
1176 | - def test_save(self): |
1177 | - xdg_path = self.useFixture(XDGConfigDirFixture()).path |
1178 | - config_ini = os.path.join(xdg_path, "snap-store-proxy-client", "config.ini") |
1179 | - self.assertFalse(os.path.exists(config_ini)) |
1180 | - |
1181 | - cfg = Config() |
1182 | - cfg.set("s", "k", "v") |
1183 | - cfg.save() |
1184 | - |
1185 | - self.assertTrue(os.path.exists(config_ini)) |
1186 | - with open(config_ini) as f: |
1187 | - content = f.read() |
1188 | - self.assertEqual( |
1189 | - content, |
1190 | - dedent( |
1191 | - """\ |
1192 | - [s] |
1193 | - k = v |
1194 | - |
1195 | - """ |
1196 | - ), |
1197 | - ) |
1198 | - |
1199 | - def test_get_missing(self): |
1200 | - self.useFixture(XDGConfigDirFixture()) |
1201 | - cfg = Config() |
1202 | - self.assertIsNone(cfg.get("s", "k")) |
1203 | - |
1204 | - def test_get(self): |
1205 | - self.useFixture(XDGConfigDirFixture()) |
1206 | - cfg = Config() |
1207 | - cfg.set("s", "k", "v") |
1208 | - self.assertEqual(cfg.get("s", "k"), "v") |
1209 | - |
1210 | - def test_section(self): |
1211 | - self.useFixture(XDGConfigDirFixture()) |
1212 | - cfg = Config() |
1213 | - s = cfg.section("s") |
1214 | - s.set("k", "v") |
1215 | - self.assertEqual(s.get("k"), "v") |
1216 | - self.assertEqual(cfg.get("s", "k"), "v") |
1217 | - |
1218 | - def test_store_section(self): |
1219 | - self.useFixture(XDGConfigDirFixture()) |
1220 | - cfg = Config() |
1221 | - store = cfg.store_section("foo") |
1222 | - store.set("k", "v") |
1223 | - self.assertEqual(cfg.get("store:foo", "k"), "v") |
1224 | - |
1225 | - |
1226 | -def test_suite(): |
1227 | - from unittest import TestLoader |
1228 | - |
1229 | - return TestLoader().loadTestsFromName(__name__) |
1230 | +def test_no_config(mocked_xdgconfig): |
1231 | + config_ini = os.path.join(mocked_xdgconfig, Config.xdg_name, "config.ini") |
1232 | + assert not os.path.exists(config_ini) |
1233 | + Config() |
1234 | + |
1235 | + |
1236 | +def test_init_loads(mocked_config): |
1237 | + cfg = Config() |
1238 | + assert cfg.get("store:default", "gw_url") |
1239 | + |
1240 | + |
1241 | +def test_save(mocked_xdgconfig): |
1242 | + config_ini = os.path.join(mocked_xdgconfig, "snap-store-proxy-client", "config.ini") |
1243 | + assert not os.path.exists(config_ini) |
1244 | + |
1245 | + cfg = Config() |
1246 | + cfg.set("s", "k", "v") |
1247 | + cfg.save() |
1248 | + |
1249 | + assert os.path.exists(config_ini) |
1250 | + |
1251 | + with open(config_ini) as f: |
1252 | + content = f.read() |
1253 | + assert content == ("[s]\n" "k = v\n" "\n") |
1254 | + |
1255 | + |
1256 | +def test_get_missing(mocked_xdgconfig): |
1257 | + cfg = Config() |
1258 | + assert not cfg.get("s", "k") |
1259 | + |
1260 | + |
1261 | +def test_get(mocked_xdgconfig): |
1262 | + cfg = Config() |
1263 | + cfg.set("s", "k", "v") |
1264 | + assert cfg.get("s", "k") == "v" |
1265 | + |
1266 | + |
1267 | +def test_section(mocked_xdgconfig): |
1268 | + cfg = Config() |
1269 | + s = cfg.section("s") |
1270 | + s.set("k", "v") |
1271 | + assert s.get("k") == "v" |
1272 | + assert cfg.get("s", "k") == "v" |
1273 | + |
1274 | + |
1275 | +def test_store_section(mocked_xdgconfig): |
1276 | + cfg = Config() |
1277 | + store = cfg.store_section("foo") |
1278 | + store.set("k", "v") |
1279 | + assert cfg.get("store:foo", "k") == "v" |
1280 | diff --git a/snapstore_client/tests/test_presentation_helpers.py b/snapstore_client/tests/test_presentation_helpers.py |
1281 | index 7399f91..e58e9e9 100644 |
1282 | --- a/snapstore_client/tests/test_presentation_helpers.py |
1283 | +++ b/snapstore_client/tests/test_presentation_helpers.py |
1284 | @@ -1,7 +1,6 @@ |
1285 | # Copyright 2017 Canonical Ltd. |
1286 | |
1287 | -from testtools import TestCase |
1288 | -from testscenarios import WithScenarios |
1289 | +import pytest |
1290 | |
1291 | from snapstore_client.presentation_helpers import ( |
1292 | channel_map_string_to_tuple, |
1293 | @@ -9,129 +8,93 @@ from snapstore_client.presentation_helpers import ( |
1294 | ) |
1295 | |
1296 | |
1297 | -class ChannelMapStringToTupleScenarioTests(WithScenarios, TestCase): |
1298 | - |
1299 | - scenarios = [ |
1300 | - ( |
1301 | - "with risk", |
1302 | - { |
1303 | - "channel_map": "stable=1", |
1304 | - "terms": ("stable", 1), |
1305 | - }, |
1306 | - ), |
1307 | - ( |
1308 | - "with track and risk", |
1309 | - { |
1310 | - "channel_map": "2.1/stable=2", |
1311 | - "terms": ("2.1/stable", 2), |
1312 | - }, |
1313 | - ), |
1314 | - ( |
1315 | - "with risk and branch", |
1316 | - { |
1317 | - "channel_map": "stable/hot-fix=42", |
1318 | - "terms": ("stable/hot-fix", 42), |
1319 | - }, |
1320 | - ), |
1321 | - ( |
1322 | - "with track, risk and branch", |
1323 | - { |
1324 | - "channel_map": "2.1/stable/hot-fix=123", |
1325 | - "terms": ("2.1/stable/hot-fix", 123), |
1326 | - }, |
1327 | - ), |
1328 | - ] |
1329 | - |
1330 | - def test_run_scenario(self): |
1331 | - self.assertEqual(self.terms, channel_map_string_to_tuple(self.channel_map)) |
1332 | - |
1333 | - |
1334 | -class ChannelMapStringToTupleErrorTests(WithScenarios, TestCase): |
1335 | - |
1336 | - scenarios = [ |
1337 | - ( |
1338 | - "missing revision", |
1339 | - { |
1340 | - "channel_map": "stable", |
1341 | - "error_message": "Invalid channel map string: 'stable'", |
1342 | - }, |
1343 | - ), |
1344 | - ( |
1345 | - "non-integer revision", |
1346 | - { |
1347 | - "channel_map": "stable=nonsense", |
1348 | - "error_message": "Invalid revision string: 'nonsense'", |
1349 | - }, |
1350 | - ), |
1351 | - ] |
1352 | +@pytest.mark.parametrize( |
1353 | + "channel_map,terms", |
1354 | + [ |
1355 | + ("stable=1", ("stable", 1)), |
1356 | + ("2.1/stable=2", ("2.1/stable", 2)), |
1357 | + ("stable/hot-fix=42", ("stable/hot-fix", 42)), |
1358 | + ("2.1/stable/hot-fix=123", ("2.1/stable/hot-fix", 123)), |
1359 | + ], |
1360 | + ids=[ |
1361 | + "with risk", |
1362 | + "with track and risk", |
1363 | + "with risk and branch", |
1364 | + "with track, risk and branch", |
1365 | + ], |
1366 | +) |
1367 | +def test_channel_map_string_to_tuple(channel_map, terms): |
1368 | + assert terms == channel_map_string_to_tuple(channel_map) |
1369 | |
1370 | - def test_run_scenario(self): |
1371 | - error = self.assertRaises( |
1372 | - ValueError, channel_map_string_to_tuple, self.channel_map |
1373 | - ) |
1374 | - self.assertEqual(self.error_message, str(error)) |
1375 | |
1376 | +@pytest.mark.parametrize( |
1377 | + "channel_map,error_message", |
1378 | + [ |
1379 | + ("stable", "Invalid channel map string: 'stable'"), |
1380 | + ("stable=nonsense", "Invalid revision string: 'nonsense'"), |
1381 | + ], |
1382 | + ids=["missing revision", "non-integer revision"], |
1383 | +) |
1384 | +def test_channel_map_string_to_tuple_exceptions(channel_map, error_message): |
1385 | + with pytest.raises(ValueError) as error: |
1386 | + channel_map_string_to_tuple(channel_map) |
1387 | + assert error_message == str(error.value) |
1388 | |
1389 | -class OverrideToStringTests(WithScenarios, TestCase): |
1390 | |
1391 | - scenarios = [ |
1392 | +@pytest.mark.parametrize( |
1393 | + "override,string", |
1394 | + [ |
1395 | ( |
1396 | - "without revision or upstream revision", |
1397 | { |
1398 | - "override": { |
1399 | - "snap_id": "dummy", |
1400 | - "snap_name": "mysnap", |
1401 | - "revision": None, |
1402 | - "upstream_revision": None, |
1403 | - "channel": "stable", |
1404 | - "architecture": "amd64", |
1405 | - }, |
1406 | - "string": "mysnap stable amd64 is tracking upstream", |
1407 | + "snap_id": "dummy", |
1408 | + "snap_name": "mysnap", |
1409 | + "revision": None, |
1410 | + "upstream_revision": None, |
1411 | + "channel": "stable", |
1412 | + "architecture": "amd64", |
1413 | }, |
1414 | + "mysnap stable amd64 is tracking upstream", |
1415 | ), |
1416 | ( |
1417 | - "without revision but with upstream revision", |
1418 | { |
1419 | - "override": { |
1420 | - "snap_id": "dummy", |
1421 | - "snap_name": "mysnap", |
1422 | - "revision": None, |
1423 | - "upstream_revision": 2, |
1424 | - "channel": "stable", |
1425 | - "architecture": "amd64", |
1426 | - }, |
1427 | - "string": "mysnap stable amd64 is tracking upstream (revision 2)", |
1428 | + "snap_id": "dummy", |
1429 | + "snap_name": "mysnap", |
1430 | + "revision": None, |
1431 | + "upstream_revision": 2, |
1432 | + "channel": "stable", |
1433 | + "architecture": "amd64", |
1434 | }, |
1435 | + "mysnap stable amd64 is tracking upstream (revision 2)", |
1436 | ), |
1437 | ( |
1438 | - "with revision but without upstream revision", |
1439 | { |
1440 | - "override": { |
1441 | - "snap_id": "dummy", |
1442 | - "snap_name": "mysnap", |
1443 | - "revision": 1, |
1444 | - "upstream_revision": None, |
1445 | - "channel": "stable", |
1446 | - "architecture": "amd64", |
1447 | - }, |
1448 | - "string": "mysnap stable amd64 1", |
1449 | + "snap_id": "dummy", |
1450 | + "snap_name": "mysnap", |
1451 | + "revision": 1, |
1452 | + "upstream_revision": None, |
1453 | + "channel": "stable", |
1454 | + "architecture": "amd64", |
1455 | }, |
1456 | + "mysnap stable amd64 1", |
1457 | ), |
1458 | ( |
1459 | - "with revision and upstream revision", |
1460 | { |
1461 | - "override": { |
1462 | - "snap_id": "dummy", |
1463 | - "snap_name": "mysnap", |
1464 | - "revision": 1, |
1465 | - "upstream_revision": 2, |
1466 | - "channel": "stable", |
1467 | - "architecture": "amd64", |
1468 | - }, |
1469 | - "string": "mysnap stable amd64 1 (upstream 2)", |
1470 | + "snap_id": "dummy", |
1471 | + "snap_name": "mysnap", |
1472 | + "revision": 1, |
1473 | + "upstream_revision": 2, |
1474 | + "channel": "stable", |
1475 | + "architecture": "amd64", |
1476 | }, |
1477 | + "mysnap stable amd64 1 (upstream 2)", |
1478 | ), |
1479 | - ] |
1480 | - |
1481 | - def test_run_scenario(self): |
1482 | - self.assertEqual(self.string, override_to_string(self.override)) |
1483 | + ], |
1484 | + ids=[ |
1485 | + "without revision or upstream revision", |
1486 | + "without revision but with upstream revision", |
1487 | + "with revision but without upstream revision", |
1488 | + "with revision and upstream revision", |
1489 | + ], |
1490 | +) |
1491 | +def test_override_to_string(override, string): |
1492 | + assert string == override_to_string(override) |
1493 | diff --git a/snapstore_client/tests/test_webservices.py b/snapstore_client/tests/test_webservices.py |
1494 | index ec2019d..3c667bb 100644 |
1495 | --- a/snapstore_client/tests/test_webservices.py |
1496 | +++ b/snapstore_client/tests/test_webservices.py |
1497 | @@ -1,13 +1,12 @@ |
1498 | # Copyright 2017 Canonical Ltd. |
1499 | |
1500 | +import pytest |
1501 | import json |
1502 | import sys |
1503 | from urllib.parse import urljoin |
1504 | |
1505 | -import fixtures |
1506 | from requests.exceptions import HTTPError |
1507 | import responses |
1508 | -from testtools import TestCase |
1509 | |
1510 | from snapstore_client import ( |
1511 | config, |
1512 | @@ -17,18 +16,14 @@ from snapstore_client import ( |
1513 | from snapstore_client.tests import ( |
1514 | factory, |
1515 | matchers, |
1516 | - testfixtures, |
1517 | ) |
1518 | |
1519 | if sys.version < "3.6": |
1520 | import sha3 # noqa |
1521 | |
1522 | |
1523 | -class WebservicesTests(TestCase): |
1524 | - def setUp(self): |
1525 | - super().setUp() |
1526 | - self.config = self.useFixture(testfixtures.ConfigFixture()) |
1527 | - |
1528 | +@pytest.mark.usefixtures("mocked_config") |
1529 | +class TestWebservices: |
1530 | @responses.activate |
1531 | def test_issue_store_admin_success(self): |
1532 | gw_url = "http://store.local/" |
1533 | @@ -37,11 +32,10 @@ class WebservicesTests(TestCase): |
1534 | "POST", issue_store_admin_url, status=200, json={"macaroon": "dummy"} |
1535 | ) |
1536 | |
1537 | - self.assertEqual("dummy", webservices.issue_store_admin(gw_url)) |
1538 | + assert "dummy" == webservices.issue_store_admin(gw_url) |
1539 | |
1540 | @responses.activate |
1541 | - def test_issue_store_admin_error(self): |
1542 | - logger = self.useFixture(fixtures.FakeLogger()) |
1543 | + def test_issue_store_admin_error(self, caplog): |
1544 | gw_url = "http://store.local/" |
1545 | issue_store_admin_url = urljoin(gw_url, "/v2/auth/issue-store-admin") |
1546 | responses.add( |
1547 | @@ -51,11 +45,11 @@ class WebservicesTests(TestCase): |
1548 | json=factory.APIError.single("Something went wrong").to_dict(), |
1549 | ) |
1550 | |
1551 | - self.assertRaises(HTTPError, webservices.issue_store_admin, gw_url) |
1552 | - self.assertEqual( |
1553 | - "Failed to issue store_admin macaroon:\nSomething went wrong\n", |
1554 | - logger.output, |
1555 | - ) |
1556 | + pytest.raises(HTTPError, webservices.issue_store_admin, gw_url) |
1557 | + assert [ |
1558 | + "Failed to issue store_admin macaroon:", |
1559 | + "Something went wrong", |
1560 | + ] == caplog.messages |
1561 | |
1562 | @responses.activate |
1563 | def test_get_sso_discharge_success(self): |
1564 | @@ -65,22 +59,16 @@ class WebservicesTests(TestCase): |
1565 | "POST", discharge_url, status=200, json={"discharge_macaroon": "dummy"} |
1566 | ) |
1567 | |
1568 | - self.assertEqual( |
1569 | - "dummy", |
1570 | - webservices.get_sso_discharge( |
1571 | - sso_url, "user@example.org", "secret", "caveat" |
1572 | - ), |
1573 | + assert "dummy" == webservices.get_sso_discharge( |
1574 | + sso_url, "user@example.org", "secret", "caveat" |
1575 | ) |
1576 | request = responses.calls[0].request |
1577 | - self.assertEqual("application/json", request.headers["Content-Type"]) |
1578 | - self.assertEqual( |
1579 | - { |
1580 | - "email": "user@example.org", |
1581 | - "password": "secret", |
1582 | - "caveat_id": "caveat", |
1583 | - }, |
1584 | - json.loads(request.body.decode()), |
1585 | - ) |
1586 | + assert "application/json" == request.headers["Content-Type"] |
1587 | + assert { |
1588 | + "email": "user@example.org", |
1589 | + "password": "secret", |
1590 | + "caveat_id": "caveat", |
1591 | + } == json.loads(request.body.decode()) |
1592 | |
1593 | @responses.activate |
1594 | def test_get_sso_discharge_success_with_otp(self): |
1595 | @@ -90,27 +78,21 @@ class WebservicesTests(TestCase): |
1596 | "POST", discharge_url, status=200, json={"discharge_macaroon": "dummy"} |
1597 | ) |
1598 | |
1599 | - self.assertEqual( |
1600 | - "dummy", |
1601 | - webservices.get_sso_discharge( |
1602 | - sso_url, |
1603 | - "user@example.org", |
1604 | - "secret", |
1605 | - "caveat", |
1606 | - one_time_password="123456", |
1607 | - ), |
1608 | + assert "dummy" == webservices.get_sso_discharge( |
1609 | + sso_url, |
1610 | + "user@example.org", |
1611 | + "secret", |
1612 | + "caveat", |
1613 | + one_time_password="123456", |
1614 | ) |
1615 | request = responses.calls[0].request |
1616 | - self.assertEqual("application/json", request.headers["Content-Type"]) |
1617 | - self.assertEqual( |
1618 | - { |
1619 | - "email": "user@example.org", |
1620 | - "password": "secret", |
1621 | - "caveat_id": "caveat", |
1622 | - "otp": "123456", |
1623 | - }, |
1624 | - json.loads(request.body.decode()), |
1625 | - ) |
1626 | + assert "application/json" == request.headers["Content-Type"] |
1627 | + assert { |
1628 | + "email": "user@example.org", |
1629 | + "password": "secret", |
1630 | + "caveat_id": "caveat", |
1631 | + "otp": "123456", |
1632 | + } == json.loads(request.body.decode()) |
1633 | |
1634 | @responses.activate |
1635 | def test_get_sso_discharge_twofactor_required(self): |
1636 | @@ -123,7 +105,7 @@ class WebservicesTests(TestCase): |
1637 | json={"error_list": [{"code": "twofactor-required"}]}, |
1638 | ) |
1639 | |
1640 | - self.assertRaises( |
1641 | + pytest.raises( |
1642 | exceptions.StoreTwoFactorAuthenticationRequired, |
1643 | webservices.get_sso_discharge, |
1644 | sso_url, |
1645 | @@ -147,7 +129,7 @@ class WebservicesTests(TestCase): |
1646 | }, |
1647 | ) |
1648 | |
1649 | - e = self.assertRaises( |
1650 | + e = pytest.raises( |
1651 | exceptions.StoreAuthenticationError, |
1652 | webservices.get_sso_discharge, |
1653 | sso_url, |
1654 | @@ -155,16 +137,15 @@ class WebservicesTests(TestCase): |
1655 | "secret", |
1656 | "caveat", |
1657 | ) |
1658 | - self.assertEqual("Something went wrong", e.message) |
1659 | + assert "Authentication error: Something went wrong" == str(e.value) |
1660 | |
1661 | @responses.activate |
1662 | - def test_get_sso_discharge_unstructured_error(self): |
1663 | - logger = self.useFixture(fixtures.FakeLogger()) |
1664 | + def test_get_sso_discharge_unstructured_error(self, caplog): |
1665 | sso_url = "http://sso.local/" |
1666 | discharge_url = urljoin(sso_url, "/api/v2/tokens/discharge") |
1667 | responses.add("POST", discharge_url, status=503, body="Try again later.") |
1668 | |
1669 | - self.assertRaises( |
1670 | + pytest.raises( |
1671 | HTTPError, |
1672 | webservices.get_sso_discharge, |
1673 | sso_url, |
1674 | @@ -172,17 +153,15 @@ class WebservicesTests(TestCase): |
1675 | "secret", |
1676 | "caveat", |
1677 | ) |
1678 | - self.assertEqual( |
1679 | - "Failed to get SSO discharge:\n" |
1680 | - "====================\n" |
1681 | - "Try again later.\n" |
1682 | - "====================\n", |
1683 | - logger.output, |
1684 | - ) |
1685 | + assert [ |
1686 | + "Failed to get SSO discharge:", |
1687 | + "====================", |
1688 | + "Try again later.", |
1689 | + "====================", |
1690 | + ] == caplog.messages |
1691 | |
1692 | @responses.activate |
1693 | - def test_get_overrides_success(self): |
1694 | - logger = self.useFixture(fixtures.FakeLogger()) |
1695 | + def test_get_overrides_success(self, caplog): |
1696 | overrides = [factory.SnapDeviceGateway.Override()] |
1697 | # XXX cjwatson 2017-06-26: Use acceptable-generated double once it |
1698 | # exists. |
1699 | @@ -190,17 +169,18 @@ class WebservicesTests(TestCase): |
1700 | overrides_url = urljoin(store.get("gw_url"), "/v2/metadata/overrides/mysnap") |
1701 | responses.add("GET", overrides_url, status=200, json=overrides) |
1702 | |
1703 | - self.assertEqual(overrides, webservices.get_overrides(store, "mysnap")) |
1704 | + assert overrides == webservices.get_overrides(store, "mysnap") |
1705 | request = responses.calls[0].request |
1706 | - self.assertThat( |
1707 | - request.headers["Authorization"], |
1708 | - matchers.MacaroonHeaderVerifies(self.config.key), |
1709 | + assert ( |
1710 | + matchers.MacaroonHeaderVerifies("random-key").match( |
1711 | + request.headers["Authorization"] |
1712 | + ) |
1713 | + is None |
1714 | ) |
1715 | - self.assertNotIn("Failed to get overrides:", logger.output) |
1716 | + assert "Failed to get overrides:" not in caplog.messages |
1717 | |
1718 | @responses.activate |
1719 | - def test_get_overrides_error(self): |
1720 | - logger = self.useFixture(fixtures.FakeLogger()) |
1721 | + def test_get_overrides_error(self, caplog): |
1722 | store = config.Config().store_section("default") |
1723 | overrides_url = urljoin(store.get("gw_url"), "/v2/metadata/overrides/mysnap") |
1724 | responses.add( |
1725 | @@ -210,14 +190,11 @@ class WebservicesTests(TestCase): |
1726 | json=factory.APIError.single("Something went wrong").to_dict(), |
1727 | ) |
1728 | |
1729 | - self.assertRaises(HTTPError, webservices.get_overrides, store, "mysnap") |
1730 | - self.assertEqual( |
1731 | - "Failed to get overrides:\nSomething went wrong\n", logger.output |
1732 | - ) |
1733 | + pytest.raises(HTTPError, webservices.get_overrides, store, "mysnap") |
1734 | + assert ["Failed to get overrides:", "Something went wrong"] == caplog.messages |
1735 | |
1736 | @responses.activate |
1737 | - def test_set_overrides_success(self): |
1738 | - logger = self.useFixture(fixtures.FakeLogger()) |
1739 | + def test_set_overrides_success(self, caplog): |
1740 | override = factory.SnapDeviceGateway.Override() |
1741 | # XXX cjwatson 2017-06-26: Use acceptable-generated double once it |
1742 | # exists. |
1743 | @@ -225,26 +202,8 @@ class WebservicesTests(TestCase): |
1744 | overrides_url = urljoin(store.get("gw_url"), "/v2/metadata/overrides") |
1745 | responses.add("POST", overrides_url, status=200, json=[override]) |
1746 | |
1747 | - self.assertEqual( |
1748 | - [override], |
1749 | - webservices.set_overrides( |
1750 | - store, |
1751 | - [ |
1752 | - { |
1753 | - "snap_name": override["snap_name"], |
1754 | - "revision": override["revision"], |
1755 | - "channel": override["channel"], |
1756 | - "series": override["series"], |
1757 | - } |
1758 | - ], |
1759 | - ), |
1760 | - ) |
1761 | - request = responses.calls[0].request |
1762 | - self.assertThat( |
1763 | - request.headers["Authorization"], |
1764 | - matchers.MacaroonHeaderVerifies(self.config.key), |
1765 | - ) |
1766 | - self.assertEqual( |
1767 | + assert [override] == webservices.set_overrides( |
1768 | + store, |
1769 | [ |
1770 | { |
1771 | "snap_name": override["snap_name"], |
1772 | @@ -253,13 +212,27 @@ class WebservicesTests(TestCase): |
1773 | "series": override["series"], |
1774 | } |
1775 | ], |
1776 | - json.loads(request.body.decode()), |
1777 | ) |
1778 | - self.assertNotIn("Failed to set override:", logger.output) |
1779 | + request = responses.calls[0].request |
1780 | + assert ( |
1781 | + matchers.MacaroonHeaderVerifies("random-key").match( |
1782 | + request.headers["Authorization"] |
1783 | + ) |
1784 | + is None |
1785 | + ) |
1786 | + |
1787 | + assert [ |
1788 | + { |
1789 | + "snap_name": override["snap_name"], |
1790 | + "revision": override["revision"], |
1791 | + "channel": override["channel"], |
1792 | + "series": override["series"], |
1793 | + } |
1794 | + ] == json.loads(request.body.decode()) |
1795 | + assert "Failed to set override:" not in caplog.messages |
1796 | |
1797 | @responses.activate |
1798 | - def test_set_overrides_error(self): |
1799 | - logger = self.useFixture(fixtures.FakeLogger()) |
1800 | + def test_set_overrides_error(self, caplog): |
1801 | override = factory.SnapDeviceGateway.Override() |
1802 | # XXX cjwatson 2017-06-26: Use acceptable-generated double once it |
1803 | # exists. |
1804 | @@ -272,7 +245,7 @@ class WebservicesTests(TestCase): |
1805 | json=factory.APIError.single("Something went wrong").to_dict(), |
1806 | ) |
1807 | |
1808 | - self.assertRaises( |
1809 | + pytest.raises( |
1810 | HTTPError, |
1811 | lambda: webservices.set_overrides( |
1812 | store, |
1813 | @@ -284,6 +257,4 @@ class WebservicesTests(TestCase): |
1814 | }, |
1815 | ), |
1816 | ) |
1817 | - self.assertEqual( |
1818 | - "Failed to set override:\nSomething went wrong\n", logger.output |
1819 | - ) |
1820 | + assert ["Failed to set override:", "Something went wrong"] == caplog.messages |
Looks great to me, thanks. But, I think it'd be wise to announce this migration publicly to the team, given the relative backlash in December's monthly meeting. That said, I'm +1! But please first check comments below.