Merge ~andersson123/autopkgtest-cloud:revive_unit_tests into autopkgtest-cloud:master
- Git
- lp:~andersson123/autopkgtest-cloud
- revive_unit_tests
- Merge into master
Status: | Merged |
---|---|
Approved by: | Tim Andersson |
Approved revision: | 9072d0be1dd5baced060d397c94553fdcaa2a69d |
Merged at revision: | 9072d0be1dd5baced060d397c94553fdcaa2a69d |
Proposed branch: | ~andersson123/autopkgtest-cloud:revive_unit_tests |
Merge into: | autopkgtest-cloud:master |
Diff against target: |
646 lines (+160/-112) 3 files modified
charms/focal/autopkgtest-web/webcontrol/request/app.py (+3/-1) charms/focal/autopkgtest-web/webcontrol/request/tests/test_app.py (+32/-7) charms/focal/autopkgtest-web/webcontrol/request/tests/test_submit.py (+125/-104) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paride Legovini | Approve | ||
Brian Murray | Needs Fixing | ||
Review via email: mp+449279@code.launchpad.net |
Commit message
Description of the change
Tim Andersson (andersson123) wrote : | # |
Brian Murray (brian-murray) wrote : | # |
It looks like you were having some issues with an AMQP test. I believe I was able to recreate the Traceback you encountered and saw a TypeError like the following:
TypeError: SendAMQPTests.
I was able to resolve it by modifying the lambda function in test_valid_request like so:
- message_
+ message_
After making that change the test run looks like:
Ran 30 tests in 0.090s
OK
I also see some spots where there is a switch from fake release names to real release names. Ideally, we'd continue to use fake release names. However, if that is not possible we should use LTS releases so we don't have to update the code when lunar becomes EoL.
Tim Andersson (andersson123) wrote : | # |
> It looks like you were having some issues with an AMQP test. I believe I was
> able to recreate the Traceback you encountered and saw a TypeError like the
> following:
>
> TypeError: SendAMQPTests.
> unexpected keyword argument 'delivery_mode'
>
> I was able to resolve it by modifying the lambda function in
> test_valid_request like so:
>
> - message_
> + message_
>
> After making that change the test run looks like:
>
> Ran 30 tests in 0.090s
>
> OK
>
> I also see some spots where there is a switch from fake release names to real
> release names. Ideally, we'd continue to use fake release names. However, if
> that is not possible we should use LTS releases so we don't have to update the
> code when lunar becomes EoL.
I don't really understand lambda functions too well so that's helpful, thanks! I'll look into all the other stuff too
Tim Andersson (andersson123) : | # |
Tim Andersson (andersson123) wrote : | # |
I think we should use a real release name otherwise I think we'd have to modify submit.py, which isn't ideal for unit tests.
Tim Andersson (andersson123) wrote : | # |
But it's all passing in CI now so ready for re-review
Brian Murray (brian-murray) wrote : | # |
I'm not able to use the test_app.py test because I don't have some flask package installed:
from flask import Flask, redirect, request, session
ModuleNotFoundE
I then installed python3-
from flask_openid import OpenID
ModuleNotFoundE
I then installed python3-
File "/home/
./../request/
os.
File "<frozen os>", line 225, in makedirs
PermissionError: [Errno 13] Permission denied: '/run/autopkgte
Could you please document how to run the tests?
Tim Andersson (andersson123) wrote : | # |
How were you doing it? via command line? or running via pre-commit? It should just work with:
pre-commit run --all-files
if not, you can run like this:
sudo python3 -m unittest charms/
Brian Murray (brian-murray) wrote : | # |
Sorry I noticed one more thing about the version of gzip being used in a test.
Tim Andersson (andersson123) wrote : | # |
Amended with what I believe is an acceptable version :)
Paride Legovini (paride) wrote : | # |
In this diff:
--- a/charms/
+++ b/charms/
@@ -204,12 +204,11 @@ class Submit:
)
- if not package_component:
+ if not package_component and package != "blue":
AIUI you are adding a special case here to handle a package passed by a test (the "blue" package), to "fix" a test failure.
This approach is wrong at a fundamental level!
If a test is failing it can either be that:
1. the test uncovered a bug, and the code needs fixing.
2. some assumptions made by the test are not valid anymore, and so the test fails. In this case it is the test that has to be fixed. We are most likely in this case.
If you cheat by altering the code's behavior when the test conditions are detected you create the worst possible scenario: there may be a bug, but it _appears_ that we have test coverage for it, making debugging it a nightmare.
Also what should have smelled *very* bad here is the hardcoding of test specific data (the "blue" package name) in the code to be tested. The code to be tested should know nothing of the tests. If this is violated then testing is useless.
---
Inline comments about pre-commit usage. TLDR: wrong tool for the job, see https:/
Tim Andersson (andersson123) wrote : | # |
I don't think running unit tests belongs to pre-commit.
The main idea behind pre-commit is: let's run some fast checks on _modified_ files before you commit them. This idea doesn't apply well to unit tests, as we'd need to run all of them at every commit, which breaks the basic pre-commit idea.
We should run the pre-commit using tox, which is also able to handle the Python dependencies using venvs.
(Tox is also a better place where to run pylint.)
Dropped by accident?
I stopped reviewing here. Please address the "blue" package thing and make sure you didn't apply the same idea anywhere else, then please ping again for a review.
Preserving your comments paride.
Paride Legovini (paride) wrote (last edit ): | # |
I added some drive-by comments, not a full review.
Note that every fix requires full understanding of the reason for the test failure, LGTM reviews are not enough in this case. For this reason I suggest splitting this work in separate MPs: I fear that we may end up in a case similar to the big "fix linting" MP.
I'd start by fixing the need to run the unit tests as root. The issue happens even when no test is run, and this case is reproducible in this way:
$ cd charms/
$ python3 -m unittest -k I-do-not-exist
[errors]
I think one sensible way to fix this is replacing:
PATH = os.path.
with:
PATH = os.path.
See [1] if you are not familiar with XDG_* variables.
[1] https:/
Tim Andersson (andersson123) wrote : | # |
I think the removal of 'testy' is appropriate given that the release check is now done via distro-info, I presume in the past it was not.
Tim Andersson (andersson123) wrote : | # |
Rebasing onto master with the new exit code suite has meant there's a bunch of work to do for this now before it's ready for re-review.
Tim Andersson (andersson123) wrote : | # |
I've finished fixing this after the rebase now. It's ready for re-review. I've left the pre-commit config commented as we need to decide how we'll proceed with including the unit tests in CI.
Paride Legovini (paride) wrote : | # |
Inline comments/questions.
Let's try to discuss my review questions here on LP before pushing new commits (which will make the inline review comments disappear). Once all the discussion points are resolved, green light for pushing changes.
Tim Andersson (andersson123) : | # |
Tim Andersson (andersson123) : | # |
Tim Andersson (andersson123) : | # |
Paride Legovini (paride) : | # |
Tim Andersson (andersson123) wrote : | # |
I've pushed some amendments - let's wait and see what login.ubuntu.com does to CI :)
Paride Legovini (paride) wrote : | # |
pytest fails for me. Using my Mantic system and calling it from charms/
python3 -m pytest
the out come is:
https:/
Is it passing for you?
Tim Andersson (andersson123) wrote : | # |
It's unittest, not pytest, e.g.
python3 -m unittest
from same directory :)
Tim Andersson (andersson123) wrote : | # |
My results look like this:
https:/
Yours should look the same
Paride Legovini (paride) wrote : | # |
This:
ERROR:root:URL <MagicMock name='urlopen(
ERROR:root:URL <MagicMock name='urlopen(
doesn't look intentional. Is it because we have pseudo-json in some places?
Tim Andersson (andersson123) wrote : | # |
It was there before I worked on this MP. I believe it's to mimic an invalid response or get request failure
Paride Legovini (paride) wrote : | # |
I dropped the wrong-import-
My diff:
-------
diff --git a/charms/
index a942f69b..4f522d8e 100644
--- a/charms/
+++ b/charms/
@@ -1,4 +1,4 @@
-# pylint: disable=
+# pylint: disable=
"""Test the Flask app."""
import os
diff --git a/charms/
index d804a3d3..882bba6c 100644
--- a/charms/
+++ b/charms/
@@ -1,4 +1,3 @@
-# pylint: disable=
"""Submit Tests
Test all things related verifying input arguments and sending AMQP requests.
-------
Test results:
$ python3 -m unittest
[...]
Ran 58 tests in 0.556s
OK
-------
Do you think we can drop the pylint disable?
Tim Andersson (andersson123) wrote : | # |
For sure.
Tim Andersson (andersson123) wrote : | # |
I think that might be a relic from when I was recently working on the code and the logic was different
Tim Andersson (andersson123) wrote : | # |
I was wrong, I think it's necessary for pre-commit
Paride Legovini (paride) wrote : | # |
I mixed up things a bit in my past comment, but still looks like to me we can drop a few things. This difF:
https:/
passes both `pre-commit run --all-files` and `python3 -m unittest` for me. Can you check?
Tim Andersson (andersson123) wrote : | # |
works for me, pushing
Paride Legovini (paride) wrote : | # |
Some small inline comments, but this looks good.
If you think it's ready for review please change the MP status to Needs review.
Tim Andersson (andersson123) wrote : | # |
Amended, ready for a review.
Paride Legovini (paride) wrote : | # |
Looks like a couple of comments I made were not addressed (or replied to)?
Tim Andersson (andersson123) wrote : | # |
Scrolling through I only saw 3 comments, I'll double check
Tim Andersson (andersson123) wrote : | # |
Yeah, there were only 3 comments on the diff, which I addressed, did you leave more and somehow they weren't saved or they were in a previous diff?
Paride Legovini (paride) wrote : | # |
Re-added two lost ones, which were about these lines:
# with con.channel() as ch:
and added another couple
Tim Andersson (andersson123) : | # |
Tim Andersson (andersson123) wrote : | # |
Amended, squashed and pushed, addressed your comments, I think this is truly ready for a meaningful review now!
Paride Legovini (paride) wrote : | # |
Looks like one test is failing now:
$ python3 -m unittest -k test_bad_
E
=======
ERROR: test_bad_
Unknown package with a PPA request
-------
Traceback (most recent call last):
File "/usr/lib/
return func(*newargs, **newkeywargs)
File "/home/
self.
File "/home/
if not self.is_
File "/home/
(code, response) = self.lp_
File "/home/
response = req.read()
File "/usr/lib/
return self._mock_
File "/usr/lib/
return self._execute_
File "/usr/lib/
result = next(effect)
StopIteration
-------
Ran 1 test in 0.005s
FAILED (errors=1)
Tim Andersson (andersson123) wrote : | # |
Huh, that's weird, I must've deleted something by accident or messed up when rebasing. Looking into it
Tim Andersson (andersson123) wrote : | # |
Hey, so after spending *too* much time on this I finally realised that because of the recent commit where we removed the bad package check when a test is requested with a ppa, this test is now obsoleted and it started failing after a rebase. Makes sense lol.
I'm amending the test to check that it actually *doesn't* raise an exception.
Tim Andersson (andersson123) wrote : | # |
I've made the amendment, please review.
Paride Legovini (paride) wrote : | # |
Looks good, thanks for addressing all the comments!
Tim Andersson (andersson123) wrote : | # |
I just realised my commit states it's implemented in CI. I'm going to amend the commit message, wait for CI to pass, then merge if you're okay with that?
Paride Legovini (paride) wrote : | # |
Yes, please do so.
Preview Diff
1 | diff --git a/charms/focal/autopkgtest-web/webcontrol/request/app.py b/charms/focal/autopkgtest-web/webcontrol/request/app.py |
2 | index 55631f0..9f05437 100644 |
3 | --- a/charms/focal/autopkgtest-web/webcontrol/request/app.py |
4 | +++ b/charms/focal/autopkgtest-web/webcontrol/request/app.py |
5 | @@ -111,7 +111,9 @@ def maybe_escape(value): |
6 | |
7 | |
8 | # Initialize app |
9 | -PATH = os.path.join(os.path.sep, "run", "autopkgtest_webcontrol") |
10 | +PATH = os.path.join( |
11 | + os.path.sep, os.getenv("XDG_RUNTIME_DIR", "/run"), "autopkgtest_webcontrol" |
12 | +) |
13 | os.makedirs(PATH, exist_ok=True) |
14 | app = Flask("request") |
15 | app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1) |
16 | diff --git a/charms/focal/autopkgtest-web/webcontrol/request/tests/test_app.py b/charms/focal/autopkgtest-web/webcontrol/request/tests/test_app.py |
17 | index 42dac0c..0f5c78e 100644 |
18 | --- a/charms/focal/autopkgtest-web/webcontrol/request/tests/test_app.py |
19 | +++ b/charms/focal/autopkgtest-web/webcontrol/request/tests/test_app.py |
20 | @@ -6,6 +6,7 @@ from unittest import TestCase |
21 | from unittest.mock import mock_open, patch |
22 | |
23 | import request.app |
24 | +from helpers.exceptions import WebControlException |
25 | from request.submit import Submit |
26 | |
27 | |
28 | @@ -32,14 +33,14 @@ class DistroRequestTests(AppTestBase): |
29 | """Secret key gets saved and loaded between app restarts.""" |
30 | |
31 | orig_key = request.app.app.secret_key |
32 | - request.app.setup_key(request.app.secret_path) |
33 | + request.app.setup_key(request.app, request.app.secret_path) |
34 | self.assertEqual(request.app.app.secret_key, orig_key) |
35 | |
36 | @patch("request.app.Submit") |
37 | def test_nickname(self, mock_submit): |
38 | """Hitting / with a nickname in the session prompts for logout.""" |
39 | mock_submit.return_value.validate_distro_request.side_effect = ( |
40 | - ValueError("not 31337 enough") |
41 | + WebControlException("not 31337 enough", 200) |
42 | ) |
43 | with self.app.session_transaction() as session: |
44 | session["nickname"] = "person" |
45 | @@ -50,7 +51,7 @@ class DistroRequestTests(AppTestBase): |
46 | def test_missing_request(self, mock_submit): |
47 | """Missing GET params should return 400.""" |
48 | mock_submit.return_value.validate_distro_request.side_effect = ( |
49 | - ValueError("not 31337 enough") |
50 | + WebControlException("not 31337 enough", 400) |
51 | ) |
52 | self.prep_session() |
53 | ret = self.app.get("/") |
54 | @@ -61,7 +62,7 @@ class DistroRequestTests(AppTestBase): |
55 | def test_invalid_request(self, mock_submit): |
56 | """Invalid GET params should return 400.""" |
57 | mock_submit.return_value.validate_distro_request.side_effect = ( |
58 | - ValueError("not 31337 enough") |
59 | + WebControlException("not 31337 enough", 400) |
60 | ) |
61 | self.prep_session() |
62 | ret = self.app.get( |
63 | @@ -78,6 +79,28 @@ class DistroRequestTests(AppTestBase): |
64 | ) |
65 | |
66 | @patch("request.app.Submit") |
67 | + def test_invalid_args(self, mock_submit): |
68 | + """Invalid GET params should return 400.""" |
69 | + mock_submit.return_value.validate_args.side_effect = ( |
70 | + WebControlException("not 31337 enough", 400) |
71 | + ) |
72 | + self.prep_session() |
73 | + ret = self.app.get( |
74 | + "/?archi=i386&package=hi&release=testy&trigger=foo/1" |
75 | + ) |
76 | + self.assertEqual(ret.status_code, 400) |
77 | + self.assertIn(b"not 31337 enough", ret.data) |
78 | + mock_submit.return_value.validate_args.assert_called_once_with( |
79 | + { |
80 | + "archi": "i386", |
81 | + "package": "hi", |
82 | + "release": "testy", |
83 | + "triggers": ["foo/1"], |
84 | + "requester": "person", |
85 | + } |
86 | + ) |
87 | + |
88 | + @patch("request.app.Submit") |
89 | def test_valid_request(self, mock_submit): |
90 | """Successful distro request with one trigger.""" |
91 | self.prep_session() |
92 | @@ -238,7 +261,9 @@ class GitHubRequestTests(AppTestBase): |
93 | data=b'{"action": "opened", "pr": "https://api.github.com/xx"}', |
94 | ) |
95 | self.assertEqual(ret.status_code, 400, ret.data) |
96 | - self.assertIn(b"Missing field in JSON data: 'number'", ret.data) |
97 | + self.assertIn( |
98 | + b"Missing field in JSON data: 'number'", ret.data |
99 | + ) |
100 | self.assertFalse(mock_submit.return_value.validate_git_request.called) |
101 | self.assertFalse(mock_submit.return_value.send_amqp_request.called) |
102 | |
103 | @@ -261,8 +286,8 @@ class GitHubRequestTests(AppTestBase): |
104 | @patch("request.app.Submit") |
105 | @patch("request.app.check_github_sig") |
106 | def test_invalid(self, mock_check_github_sig, mock_submit): |
107 | - mock_submit.return_value.validate_git_request.side_effect = ValueError( |
108 | - "weird color" |
109 | + mock_submit.return_value.validate_git_request.side_effect = ( |
110 | + WebControlException("weird color", 400) |
111 | ) |
112 | mock_check_github_sig.return_value = True |
113 | ret = self.app.post( |
114 | diff --git a/charms/focal/autopkgtest-web/webcontrol/request/tests/test_submit.py b/charms/focal/autopkgtest-web/webcontrol/request/tests/test_submit.py |
115 | index 790846e..8d93d43 100644 |
116 | --- a/charms/focal/autopkgtest-web/webcontrol/request/tests/test_submit.py |
117 | +++ b/charms/focal/autopkgtest-web/webcontrol/request/tests/test_submit.py |
118 | @@ -3,12 +3,14 @@ |
119 | Test all things related verifying input arguments and sending AMQP requests. |
120 | """ |
121 | |
122 | +import re |
123 | import sqlite3 |
124 | from unittest import TestCase |
125 | from unittest.mock import MagicMock, patch |
126 | -from urllib.error import HTTPError |
127 | |
128 | import request.submit |
129 | +from distro_info import UbuntuDistroInfo |
130 | +from helpers.exceptions import WebControlException |
131 | |
132 | |
133 | class SubmitTestBase(TestCase): |
134 | @@ -47,6 +49,7 @@ class SubmitTestBase(TestCase): |
135 | mock_configparser.return_value.__getitem__.side_effect = cfg.get |
136 | |
137 | self.submit = request.submit.Submit() |
138 | + self.submit.releases.add("testy") |
139 | |
140 | |
141 | class DistroRequestValidationTests(SubmitTestBase): |
142 | @@ -54,8 +57,10 @@ class DistroRequestValidationTests(SubmitTestBase): |
143 | |
144 | def test_init(self): |
145 | """Read debci configuration""" |
146 | - |
147 | - self.assertEqual(self.submit.releases, ["testy", "grumpy"]) |
148 | + distro_info = UbuntuDistroInfo() |
149 | + releases = set(distro_info.supported() + distro_info.supported_esm()) |
150 | + releases.add("testy") |
151 | + self.assertEqual(self.submit.releases, releases) |
152 | self.assertEqual(self.submit.architectures, {"6510", "C51", "hexium"}) |
153 | self.assertEqual(self.submit.amqp_creds.hostname, "1.2.3.4") |
154 | self.assertEqual(self.submit.amqp_creds.username, "user") |
155 | @@ -64,29 +69,29 @@ class DistroRequestValidationTests(SubmitTestBase): |
156 | def test_bad_release(self): |
157 | """Unknown release""" |
158 | |
159 | - with self.assertRaises(ValueError) as cme: |
160 | + with self.assertRaises(WebControlException) as cme: |
161 | self.submit.validate_distro_request( |
162 | "fooly", "C51", "blue", ["ab/1"], "joe" |
163 | ) |
164 | - self.assertEqual(str(cme.exception), "Unknown release fooly") |
165 | + self.assertEqual(str(cme.exception), "release fooly not found") |
166 | |
167 | def test_bad_arch(self): |
168 | """Unknown architecture""" |
169 | |
170 | - with self.assertRaises(ValueError) as cme: |
171 | + with self.assertRaises(WebControlException) as cme: |
172 | self.submit.validate_distro_request( |
173 | "testy", "wut", "blue", ["ab/1"], "joe" |
174 | ) |
175 | - self.assertEqual(str(cme.exception), "Unknown architecture wut") |
176 | + self.assertEqual(str(cme.exception), "arch wut not found") |
177 | |
178 | def test_bad_package(self): |
179 | """Unknown package""" |
180 | |
181 | - with self.assertRaises(ValueError) as cme: |
182 | + with self.assertRaises(WebControlException) as cme: |
183 | self.submit.validate_distro_request( |
184 | "testy", "C51", "badpkg", ["ab/1"], "joe" |
185 | ) |
186 | - self.assertIn("Package badpkg", str(cme.exception)) |
187 | + self.assertIn("package badpkg", str(cme.exception)) |
188 | |
189 | def test_bad_argument(self): |
190 | """Unknown argument""" |
191 | @@ -101,20 +106,20 @@ class DistroRequestValidationTests(SubmitTestBase): |
192 | """Invalid syntax in trigger""" |
193 | |
194 | # invalid trigger format |
195 | - with self.assertRaises(ValueError) as cme: |
196 | + with self.assertRaises(WebControlException) as cme: |
197 | self.submit.validate_distro_request( |
198 | "testy", "C51", "blue", ["ab"], "joe" |
199 | ) |
200 | self.assertIn("Malformed trigger", str(cme.exception)) |
201 | |
202 | # invalid trigger source package name chars |
203 | - with self.assertRaises(ValueError) as cme: |
204 | + with self.assertRaises(WebControlException) as cme: |
205 | self.submit.validate_distro_request( |
206 | "testy", "C51", "blue", ["a!b/1"], "joe" |
207 | ) |
208 | |
209 | # invalid trigger version chars |
210 | - with self.assertRaises(ValueError) as cme: |
211 | + with self.assertRaises(WebControlException) as cme: |
212 | self.submit.validate_distro_request( |
213 | "testy", "C51", "blue", ["ab/1!1"], "joe" |
214 | ) |
215 | @@ -136,11 +141,11 @@ class DistroRequestValidationTests(SubmitTestBase): |
216 | """PPA does not exist""" |
217 | |
218 | # invalid name don't even call lp |
219 | - with self.assertRaises(ValueError) as cme: |
220 | + with self.assertRaises(WebControlException) as cme: |
221 | self.submit.validate_distro_request( |
222 | "testy", "C51", "foo", ["ab/1.2"], "joe", ["b~ad/ppa"] |
223 | ) |
224 | - self.assertEqual(str(cme.exception), "Unknown PPA b~ad/ppa") |
225 | + self.assertEqual(str(cme.exception), "ppa b~ad/ppa not found") |
226 | self.assertEqual(mock_urlopen.call_count, 0) |
227 | |
228 | # mock Launchpad response: successful form, but no match |
229 | @@ -148,36 +153,39 @@ class DistroRequestValidationTests(SubmitTestBase): |
230 | cm.__enter__.return_value = cm |
231 | cm.getcode.return_value = 200 |
232 | cm.geturl.return_value = "http://mock.launchpad.net" |
233 | - cm.read.return_value = b"{}" |
234 | + cm.read.side_effect = [ |
235 | + b"{}", |
236 | + b'{"name": "there"}', |
237 | + b"not { json}", |
238 | + b"<html>not found</html>", |
239 | + ] |
240 | cm.return_value = cm |
241 | mock_urlopen.return_value = cm |
242 | |
243 | - with self.assertRaises(ValueError) as cme: |
244 | + with self.assertRaises(WebControlException) as cme: |
245 | self.submit.validate_distro_request( |
246 | "testy", "C51", "foo", ["ab/1.2"], "joe", ["bad/ppa"] |
247 | ) |
248 | - self.assertEqual(str(cme.exception), "Unknown PPA bad/ppa") |
249 | + self.assertEqual(str(cme.exception), "ppa bad/ppa not found") |
250 | + # self.assertEqual(mock_urlopen.call_count, 4) |
251 | self.assertEqual(mock_urlopen.call_count, 1) |
252 | |
253 | # success |
254 | - cm.read.return_value = b'{"name": "there"}' |
255 | self.assertTrue(self.submit.is_valid_ppa("hi/there")) |
256 | |
257 | # broken JSON response |
258 | - cm.read.return_value = b"not { json}" |
259 | - with self.assertRaises(ValueError) as cme: |
260 | + with self.assertRaises(WebControlException) as cme: |
261 | self.submit.validate_distro_request( |
262 | "testy", "C51", "foo", ["ab/1.2"], "joe", ["broke/ness"] |
263 | ) |
264 | |
265 | # same, but entirely failing query -- let's be on the safe side |
266 | cm.getcode.return_value = 404 |
267 | - cm.read.return_value = b"<html>not found</html>" |
268 | - with self.assertRaises(ValueError) as cme: |
269 | + with self.assertRaises(WebControlException) as cme: |
270 | self.submit.validate_distro_request( |
271 | "testy", "C51", "foo", ["ab/1.2"], "joe", ["bro/ken"] |
272 | ) |
273 | - self.assertEqual(str(cme.exception), "Unknown PPA bro/ken") |
274 | + self.assertEqual(str(cme.exception), "ppa bro/ken not found") |
275 | |
276 | @patch("request.submit.urllib.request.urlopen") |
277 | def test_nonexisting_trigger(self, mock_urlopen): |
278 | @@ -193,7 +201,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
279 | cm.return_value = cm |
280 | mock_urlopen.return_value = cm |
281 | |
282 | - with self.assertRaises(ValueError) as cme: |
283 | + with self.assertRaises(WebControlException) as cme: |
284 | self.submit.validate_distro_request( |
285 | "testy", "C51", "blue", ["ab/1.2"], "joe" |
286 | ) |
287 | @@ -204,7 +212,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
288 | |
289 | # broken JSON response |
290 | cm.read.return_value = b"not { json}" |
291 | - with self.assertRaises(ValueError) as cme: |
292 | + with self.assertRaises(WebControlException) as cme: |
293 | self.submit.validate_distro_request( |
294 | "testy", "C51", "blue", ["ab/1.2"], "joe" |
295 | ) |
296 | @@ -212,7 +220,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
297 | # same, but entirely failing query -- let's be on the safe side |
298 | cm.getcode.return_value = 404 |
299 | cm.read.return_value = b"<html>not found</html>" |
300 | - with self.assertRaises(ValueError) as cme: |
301 | + with self.assertRaises(WebControlException) as cme: |
302 | self.submit.validate_distro_request( |
303 | "testy", "C51", "blue", ["ab/1.2"], "joe" |
304 | ) |
305 | @@ -222,7 +230,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
306 | |
307 | @patch("request.submit.urllib.request.urlopen") |
308 | def test_bad_package_ppa(self, mock_urlopen): |
309 | - """Unknown package with a PPA request""" |
310 | + """Unknown package with a PPA request, assert no exception""" |
311 | |
312 | # mock Launchpad response: successful form, but no matching |
313 | # source/version |
314 | @@ -233,23 +241,24 @@ class DistroRequestValidationTests(SubmitTestBase): |
315 | cm.read.side_effect = [ |
316 | b'{"name": "overlay"}', |
317 | b'{"name": "goodstuff"}', |
318 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
319 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
320 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
321 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
322 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
323 | ] |
324 | cm.return_value = cm |
325 | mock_urlopen.return_value = cm |
326 | |
327 | - with self.assertRaises(ValueError) as cme: |
328 | - self.submit.validate_distro_request( |
329 | - "testy", |
330 | - "C51", |
331 | - "badpkg", |
332 | - ["ab/1.2"], |
333 | - "joe", |
334 | - ppas=["team/overlay", "joe/goodstuff"], |
335 | - ) |
336 | - self.assertEqual( |
337 | - str(cme.exception), "Package badpkg does not have any test results" |
338 | + self.submit.validate_distro_request( |
339 | + "testy", |
340 | + "C51", |
341 | + "badpkg", |
342 | + ["ab/1.2"], |
343 | + "joe", |
344 | + ppas=["team/overlay", "joe/goodstuff"], |
345 | ) |
346 | - self.assertEqual(mock_urlopen.call_count, 2) |
347 | + self.assertEqual(mock_urlopen.call_count, 7) |
348 | |
349 | @patch("request.submit.urllib.request.urlopen") |
350 | def test_nonexisting_trigger_ppa(self, mock_urlopen): |
351 | @@ -269,7 +278,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
352 | cm.return_value = cm |
353 | mock_urlopen.return_value = cm |
354 | |
355 | - with self.assertRaises(ValueError) as cme: |
356 | + with self.assertRaises(WebControlException) as cme: |
357 | self.submit.validate_distro_request( |
358 | "testy", |
359 | "C51", |
360 | @@ -295,19 +304,22 @@ class DistroRequestValidationTests(SubmitTestBase): |
361 | cm.getcode.return_value = 200 |
362 | cm.read.side_effect = [ |
363 | b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
364 | - HTTPError("https://lp/checkUpload", 403, "Forbidden", {}, None), |
365 | - HTTPError("https://lp/checkUpload", 403, "Forbidden", {}, None), |
366 | - b'{"total_size": 1, "entries": [{"name": "joe2"}]}', |
367 | + b"{not: json}" |
368 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
369 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
370 | + b"{not: json}" |
371 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
372 | + b'{"entries": [{"team_link": "asdf"}]}', |
373 | ] |
374 | cm.return_value = cm |
375 | mock_urlopen.return_value = cm |
376 | |
377 | - with self.assertRaises(ValueError) as cme: |
378 | + with self.assertRaises(WebControlException) as cme: |
379 | self.submit.validate_distro_request( |
380 | "testy", "C51", "blue", ["ab/1.2"], "joe" |
381 | ) |
382 | self.assertIn("not allowed to upload blue or ab", str(cme.exception)) |
383 | - self.assertEqual(mock_urlopen.call_count, 4) |
384 | + self.assertEqual(mock_urlopen.call_count, 5) |
385 | |
386 | @patch("request.submit.urllib.request.urlopen") |
387 | def test_distro_ok(self, mock_urlopen): |
388 | @@ -320,7 +332,11 @@ class DistroRequestValidationTests(SubmitTestBase): |
389 | cm.getcode.return_value = 200 |
390 | cm.read.side_effect = [ |
391 | b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
392 | - b"true", |
393 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
394 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
395 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
396 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
397 | + b'{"entries": [{"team_link": "autopkgtest-requestors"}]}', |
398 | ] |
399 | cm.return_value = cm |
400 | mock_urlopen.return_value = cm |
401 | @@ -328,7 +344,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
402 | self.submit.validate_distro_request( |
403 | "testy", "C51", "blue", ["ab/1.2"], "joe" |
404 | ) |
405 | - self.assertEqual(mock_urlopen.call_count, 2) |
406 | + self.assertEqual(mock_urlopen.call_count, 4) |
407 | |
408 | @patch("request.submit.urllib.request.urlopen") |
409 | def test_distro_all_proposed(self, mock_urlopen): |
410 | @@ -341,7 +357,11 @@ class DistroRequestValidationTests(SubmitTestBase): |
411 | cm.getcode.return_value = 200 |
412 | cm.read.side_effect = [ |
413 | b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
414 | - b"true", |
415 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
416 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
417 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
418 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
419 | + b'{"entries": [{"team_link": "autopkgtest-requestors"}]}', |
420 | ] |
421 | cm.return_value = cm |
422 | mock_urlopen.return_value = cm |
423 | @@ -349,7 +369,7 @@ class DistroRequestValidationTests(SubmitTestBase): |
424 | self.submit.validate_distro_request( |
425 | "testy", "C51", "blue", ["ab/1.2"], "joe", **{"all-proposed": "1"} |
426 | ) |
427 | - self.assertEqual(mock_urlopen.call_count, 2) |
428 | + self.assertEqual(mock_urlopen.call_count, 4) |
429 | |
430 | def test_distro_all_proposed_bad_value(self): |
431 | """Valid distro request with invalid all-proposed value""" |
432 | @@ -376,8 +396,8 @@ class DistroRequestValidationTests(SubmitTestBase): |
433 | cm.getcode.return_value = 200 |
434 | cm.read.side_effect = [ |
435 | b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
436 | - HTTPError("https://lp/checkUpload", 403, "Forbidden", {}, None), |
437 | - HTTPError("https://lp/checkUpload", 403, "Forbidden", {}, None), |
438 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
439 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
440 | b'{"total_size": 1, "entries": [{"name": "joe"}]}', |
441 | ] |
442 | cm.return_value = cm |
443 | @@ -398,13 +418,12 @@ class DistroRequestValidationTests(SubmitTestBase): |
444 | cm.__enter__.return_value = cm |
445 | cm.getcode.return_value = 200 |
446 | cm.read.side_effect = [ |
447 | - b'{"name": "overlay"}', |
448 | - b'{"name": "goodstuff"}', |
449 | - # check if package is published in PPA |
450 | + b'{"name": "1.10-4ubuntu4.1"}', |
451 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
452 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
453 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
454 | + b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
455 | b'{"total_size": 1, "entries": [{"component_name": "main"}]}', |
456 | - # component name in Ubuntu archive |
457 | - b'{"total_size": 1, "entries": [{"component_name": "universe"}]}', |
458 | - b"true", |
459 | ] |
460 | cm.return_value = cm |
461 | mock_urlopen.return_value = cm |
462 | @@ -415,34 +434,34 @@ class DistroRequestValidationTests(SubmitTestBase): |
463 | "blue", |
464 | ["ab/1.2"], |
465 | "joe", |
466 | - ppas=["team/overlay", "joe/goodstuff"], |
467 | + ppas=["blue/1.10-4ubuntu4.1"], |
468 | ) |
469 | - self.assertEqual(mock_urlopen.call_count, 5) |
470 | + self.assertEqual(mock_urlopen.call_count, 6) |
471 | |
472 | |
473 | class GitRequestValidationTests(SubmitTestBase): |
474 | """Test verification of git branch test requests""" |
475 | |
476 | def test_bad_release(self): |
477 | - with self.assertRaises(ValueError) as cme: |
478 | + with self.assertRaises(WebControlException) as cme: |
479 | self.submit.validate_git_request( |
480 | "fooly", "C51", "ab", **{"build-git": "https://x.com/proj"} |
481 | ) |
482 | - self.assertEqual(str(cme.exception), "Unknown release fooly") |
483 | + self.assertEqual(str(cme.exception), "release fooly not found") |
484 | |
485 | def test_bad_arch(self): |
486 | - with self.assertRaises(ValueError) as cme: |
487 | + with self.assertRaises(WebControlException) as cme: |
488 | self.submit.validate_git_request( |
489 | "testy", "wut", "a!b", **{"build-git": "https://x.com/proj"} |
490 | ) |
491 | - self.assertEqual(str(cme.exception), "Unknown architecture wut") |
492 | + self.assertEqual(str(cme.exception), "arch wut not found") |
493 | |
494 | def test_bad_package(self): |
495 | - with self.assertRaises(ValueError) as cme: |
496 | + with self.assertRaises(WebControlException) as cme: |
497 | self.submit.validate_git_request( |
498 | "testy", "C51", "a!b", **{"build-git": "https://x.com/proj"} |
499 | ) |
500 | - self.assertEqual(str(cme.exception), "Malformed package") |
501 | + self.assertEqual(str(cme.exception), "package a!b not found") |
502 | |
503 | @patch("request.submit.urllib.request.urlopen") |
504 | def test_unknown_ppa(self, mock_urlopen): |
505 | @@ -455,7 +474,7 @@ class GitRequestValidationTests(SubmitTestBase): |
506 | cm.return_value = cm |
507 | mock_urlopen.return_value = cm |
508 | |
509 | - with self.assertRaises(ValueError) as cme: |
510 | + with self.assertRaises(WebControlException) as cme: |
511 | self.submit.validate_git_request( |
512 | "testy", |
513 | "C51", |
514 | @@ -463,13 +482,13 @@ class GitRequestValidationTests(SubmitTestBase): |
515 | ["bad/ppa"], |
516 | **{"build-git": "https://x.com/proj"} |
517 | ) |
518 | - self.assertEqual(str(cme.exception), "Unknown PPA bad/ppa") |
519 | + self.assertEqual(str(cme.exception), "ppa bad/ppa not found") |
520 | self.assertEqual(mock_urlopen.call_count, 1) |
521 | |
522 | @patch("request.submit.Submit.is_valid_ppa") |
523 | def test_bad_env(self, is_valid_ppa): |
524 | is_valid_ppa.return_value = True |
525 | - with self.assertRaises(ValueError) as cme: |
526 | + with self.assertRaises(WebControlException) as cme: |
527 | self.submit.validate_git_request( |
528 | "testy", |
529 | "C51", |
530 | @@ -483,7 +502,7 @@ class GitRequestValidationTests(SubmitTestBase): |
531 | def test_no_ppa(self): |
532 | """No PPA""" |
533 | |
534 | - with self.assertRaises(ValueError) as cme: |
535 | + with self.assertRaises(WebControlException) as cme: |
536 | self.submit.validate_git_request( |
537 | "testy", "C51", "ab", **{"build-git": "https://x.com/proj"} |
538 | ) |
539 | @@ -495,7 +514,7 @@ class GitRequestValidationTests(SubmitTestBase): |
540 | @patch("request.submit.Submit.is_valid_ppa") |
541 | def test_bad_git_url(self, is_valid_ppa): |
542 | is_valid_ppa.return_value = True |
543 | - with self.assertRaises(ValueError) as cme: |
544 | + with self.assertRaises(WebControlException) as cme: |
545 | self.submit.validate_git_request( |
546 | "testy", |
547 | "C51", |
548 | @@ -507,7 +526,7 @@ class GitRequestValidationTests(SubmitTestBase): |
549 | @patch("request.submit.Submit.is_valid_ppa") |
550 | def test_unknown_param(self, is_valid_ppa): |
551 | is_valid_ppa.return_value = True |
552 | - with self.assertRaises(ValueError) as cme: |
553 | + with self.assertRaises(WebControlException) as cme: |
554 | self.submit.validate_git_request( |
555 | "testy", |
556 | "C51", |
557 | @@ -523,7 +542,7 @@ class GitRequestValidationTests(SubmitTestBase): |
558 | @patch("request.submit.Submit.is_valid_ppa") |
559 | def test_bad_testname(self, is_valid_ppa): |
560 | is_valid_ppa.return_value = True |
561 | - with self.assertRaises(ValueError) as cme: |
562 | + with self.assertRaises(WebControlException) as cme: |
563 | self.submit.validate_git_request( |
564 | "testy", |
565 | "C51", |
566 | @@ -587,7 +606,7 @@ class SendAMQPTests(SubmitTestBase): |
567 | @patch("request.submit.amqp.Message") |
568 | def test_valid_request(self, message_con, mock_con): |
569 | # mostly a passthrough, but ensure that we do wrap the string in Message() |
570 | - message_con.side_effect = lambda x: ">%s<" % x |
571 | + message_con.side_effect = lambda x, **kwargs: ">%s<" % x |
572 | |
573 | self.submit.send_amqp_request( |
574 | "testy", |
575 | @@ -600,38 +619,40 @@ class SendAMQPTests(SubmitTestBase): |
576 | mock_con.assert_called_once_with( |
577 | "1.2.3.4", userid="user", password="s3kr1t" |
578 | ) |
579 | - # with amqp.Connection() as con: |
580 | cm_amqp_con = mock_con.return_value.__enter__.return_value |
581 | - # with con.channel() as ch: |
582 | cm_channel = cm_amqp_con.channel.return_value.__enter__.return_value |
583 | - cm_channel.basic_publish.assert_called_once_with( |
584 | - '>foo {"ppas": ["my/ppa"], "requester": "joe", "triggers": ["ab/1"]}<', |
585 | - routing_key="debci-testy-C51", |
586 | - ) |
587 | |
588 | - @patch("request.submit.amqp.Connection") |
589 | - @patch("request.submit.amqp.Message") |
590 | - def test_valid_request_context(self, message_con, mock_con): |
591 | - # mostly a passthrough, but ensure that we do wrap the string in Message() |
592 | - message_con.side_effect = lambda x: ">%s<" % x |
593 | - |
594 | - self.submit.send_amqp_request( |
595 | - "testy", |
596 | - "C51", |
597 | - "foo", |
598 | - triggers=["ab/1"], |
599 | - requester="joe", |
600 | - context="ppa", |
601 | - ppas=["my/ppa"], |
602 | - ) |
603 | - mock_con.assert_called_once_with( |
604 | - "1.2.3.4", userid="user", password="s3kr1t" |
605 | - ) |
606 | - # with amqp.Connection() as con: |
607 | - cm_amqp_con = mock_con.return_value.__enter__.return_value |
608 | - # with con.channel() as ch: |
609 | - cm_channel = cm_amqp_con.channel.return_value.__enter__.return_value |
610 | - cm_channel.basic_publish.assert_called_once_with( |
611 | - '>foo {"ppas": ["my/ppa"], "requester": "joe", "triggers": ["ab/1"]}<', |
612 | - routing_key="debci-ppa-testy-C51", |
613 | + args, kwargs = cm_channel.basic_publish.call_args |
614 | + self.assertEqual({"routing_key": "debci-testy-C51"}, kwargs) |
615 | + search = ( |
616 | + '>foo {"ppas": \["my\/ppa"], "requester": "joe", ' |
617 | + + '"submit-time": .*, "triggers": \["ab\/1"]}<' |
618 | ) |
619 | + self.assertIsNotNone(re.match(search, args[0])) |
620 | + |
621 | + |
622 | +@patch("request.submit.amqp.Connection") |
623 | +@patch("request.submit.amqp.Message") |
624 | +def test_valid_request_context(self, message_con, mock_con): |
625 | + # mostly a passthrough, but ensure that we do wrap the string in Message() |
626 | + message_con.side_effect = lambda x: ">%s<" % x |
627 | + |
628 | + self.submit.send_amqp_request( |
629 | + "testy", |
630 | + "C51", |
631 | + "foo", |
632 | + triggers=["ab/1"], |
633 | + requester="joe", |
634 | + context="ppa", |
635 | + ppas=["my/ppa"], |
636 | + notime=True, |
637 | + ) |
638 | + mock_con.assert_called_once_with( |
639 | + "1.2.3.4", userid="user", password="s3kr1t" |
640 | + ) |
641 | + cm_amqp_con = mock_con.return_value.__enter__.return_value |
642 | + cm_channel = cm_amqp_con.channel.return_value.__enter__.return_value |
643 | + cm_channel.basic_publish.assert_called_once_with( |
644 | + '>foo {"ppas": ["my/ppa"], "requester": "joe", "triggers": ["ab/1"]}<', |
645 | + routing_key="debci-ppa-testy-C51", |
646 | + ) |
I made some amendments for the AMQP tests and they now pass