Merge ~ilasc/launchpad:add-get-snapbuild-by-revision into launchpad:master
- Git
- lp:~ilasc/launchpad
- add-get-snapbuild-by-revision
- Merge into master
Proposed by
Ioana Lasc
Status: | Merged |
---|---|
Approved by: | Ioana Lasc |
Approved revision: | 54adb9f372ec8e62c9ef5cd34452cf5351c0d0e0 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~ilasc/launchpad:add-get-snapbuild-by-revision |
Merge into: | launchpad:master |
Prerequisite: | ~ilasc/launchpad:populate-store-upload-revision |
Diff against target: |
333 lines (+123/-36) 6 files modified
lib/lp/scripts/tests/test_garbo.py (+18/-36) lib/lp/snappy/interfaces/snap.py (+15/-0) lib/lp/snappy/model/snap.py (+14/-0) lib/lp/snappy/model/snapbuildjob.py (+1/-0) lib/lp/snappy/tests/test_snap.py (+49/-0) lib/lp/snappy/tests/test_snapbuildjob.py (+26/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+407781@code.launchpad.net |
Commit message
Add getBuildByStore
Description of the change
This needs the new column "_store_
To post a comment you must log in.
- 5d86f07... by Ioana Lasc
-
Merge branch 'populate-
store-upload- revision' into add-get- snapbuild- by-revision - df6797e... by Ioana Lasc
-
Address code review comments
Revision history for this message
Colin Watson (cjwatson) : | # |
review:
Approve
- 54adb9f... by Ioana Lasc
-
Remove MP number from comment
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py |
2 | index 3a43045..5fb7f77 100644 |
3 | --- a/lib/lp/scripts/tests/test_garbo.py |
4 | +++ b/lib/lp/scripts/tests/test_garbo.py |
5 | @@ -2013,52 +2013,34 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory): |
6 | with dbuser(config.ISnapStoreUploadJobSource.dbuser): |
7 | run_isolated_jobs([job]) |
8 | |
9 | - # this mimics what we have in the DB right now: |
10 | - # uploaded snaps that do not have the new DB column |
11 | - # _store_upload_revision populated yet |
12 | - populator = PopulateSnapBuildStoreRevision(None) |
13 | - filter = populator.findSnapBuilds() |
14 | + # The _store_upload_revision now gets populated when |
15 | + # uploading the build as part of the |
16 | + # `SnapStoreUploadJob.store_revision` property setter. |
17 | + # Assert that upload job above populated _store_upload_revision |
18 | + # for build1: |
19 | build1 = removeSecurityProxy(build1) |
20 | - self.assertEqual(1, filter.count()) |
21 | - self.assertEqual(build1, filter.one()) |
22 | - self.assertEqual(build1._store_upload_revision, None) |
23 | - |
24 | - # run the garbo job and verify _store_upload_revision |
25 | - # is not populated with the value assigned to the build during upload |
26 | - self.runDaily() |
27 | - switch_dbuser('testadmin') |
28 | self.assertEqual(build1._store_upload_revision, 1) |
29 | |
30 | - # Tests that of all builds for the same snap only those that have |
31 | - # been uploaded to the store will get |
32 | - # their new _store_upload_revision DB column updated |
33 | - build2 = self.factory.makeSnapBuild( |
34 | - snap=snap1, |
35 | - status=BuildStatus.FULLYBUILT) |
36 | - build3 = self.factory.makeSnapBuild( |
37 | - snap=snap1, |
38 | - status=BuildStatus.FULLYBUILT) |
39 | - job = getUtility(ISnapStoreUploadJobSource).create(build2) |
40 | - client = FakeSnapStoreClient() |
41 | - client.upload.result = ( |
42 | - "http://sca.example/dev/api/snaps/1/builds/2/status") |
43 | - client.checkStatus.result = ( |
44 | - "http://sca.example/dev/click-apps/1/rev/2/", 1) |
45 | - self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient)) |
46 | - with dbuser(config.ISnapStoreUploadJobSource.dbuser): |
47 | - run_isolated_jobs([job]) |
48 | + # and that the populator job doesn't pick up build1 anymore. |
49 | + populator = PopulateSnapBuildStoreRevision(None) |
50 | + filter = populator.findSnapBuilds() |
51 | + self.assertEqual(0, filter.count()) |
52 | + |
53 | + # We manually simulate here the situation |
54 | + # where a job to upload snap to the store has run in the past |
55 | + # without populating the new column (prior to MP 407781). |
56 | + build1._store_upload_revision = None |
57 | |
58 | + # in this case the populator garbo job should pick up build1 |
59 | + # to update the _store_upload_revision for it: |
60 | populator = PopulateSnapBuildStoreRevision(None) |
61 | filter = populator.findSnapBuilds() |
62 | self.assertEqual(1, filter.count()) |
63 | - self.assertEqual(build2, filter.one()) |
64 | + self.assertEqual(build1, filter.one()) |
65 | |
66 | self.runDaily() |
67 | switch_dbuser('testadmin') |
68 | - build2 = removeSecurityProxy(build2) |
69 | - self.assertEqual(build2._store_upload_revision, 1) |
70 | - build3 = removeSecurityProxy(build3) |
71 | - self.assertIsNone(build3._store_upload_revision) |
72 | + self.assertEqual(build1._store_upload_revision, 1) |
73 | |
74 | |
75 | class TestGarboTasks(TestCaseWithFactory): |
76 | diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py |
77 | index 2445553..088af8c 100644 |
78 | --- a/lib/lp/snappy/interfaces/snap.py |
79 | +++ b/lib/lp/snappy/interfaces/snap.py |
80 | @@ -529,6 +529,21 @@ class ISnapView(Interface): |
81 | |
82 | @call_with(user=REQUEST_USER) |
83 | @operation_parameters( |
84 | + store_upload_revision=Int(title="Store revision", |
85 | + required=True)) |
86 | + @export_read_operation() |
87 | + @operation_for_version("devel") |
88 | + def getBuildByStoreRevision(store_upload_revision, user=None): |
89 | + """Returns the build (if any) of that snap recipe |
90 | + that has the given store_upload_revision. |
91 | + |
92 | + :param store_upload_revision: The revision assigned by the store. |
93 | + :param user: The `IPerson` requesting this information. |
94 | + :return: An 'ISnapBuild' or None. |
95 | + """ |
96 | + |
97 | + @call_with(user=REQUEST_USER) |
98 | + @operation_parameters( |
99 | request_ids=List( |
100 | title=_("A list of snap build request IDs."), value_type=Int(), |
101 | required=False), |
102 | diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py |
103 | index 24aa2be..e68182e 100644 |
104 | --- a/lib/lp/snappy/model/snap.py |
105 | +++ b/lib/lp/snappy/model/snap.py |
106 | @@ -1111,6 +1111,20 @@ class Snap(Storm, WebhookTargetMixin): |
107 | |
108 | return result |
109 | |
110 | + def getBuildByStoreRevision(self, store_upload_revision, user=None): |
111 | + build = Store.of(self).find( |
112 | + SnapBuild, |
113 | + SnapBuild.snap == self, |
114 | + SnapBuild._store_upload_revision == store_upload_revision, |
115 | + SnapBuild.archive == Archive.id, |
116 | + Archive._enabled, |
117 | + get_enabled_archive_filter( |
118 | + user, |
119 | + include_public=True, |
120 | + include_subscribed=True) |
121 | + ).one() |
122 | + return build |
123 | + |
124 | @property |
125 | def builds(self): |
126 | """See `ISnap`.""" |
127 | diff --git a/lib/lp/snappy/model/snapbuildjob.py b/lib/lp/snappy/model/snapbuildjob.py |
128 | index 9634f62..a8fc49f 100644 |
129 | --- a/lib/lp/snappy/model/snapbuildjob.py |
130 | +++ b/lib/lp/snappy/model/snapbuildjob.py |
131 | @@ -263,6 +263,7 @@ class SnapStoreUploadJob(SnapBuildJobDerived): |
132 | if self.snapbuild.store_upload_metadata is None: |
133 | self.snapbuild.store_upload_metadata = {} |
134 | self.snapbuild.store_upload_metadata["store_revision"] = revision |
135 | + self.snapbuild._store_upload_revision = revision |
136 | |
137 | @property |
138 | def status_url(self): |
139 | diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py |
140 | index 4d9c92f..adb8cfa 100644 |
141 | --- a/lib/lp/snappy/tests/test_snap.py |
142 | +++ b/lib/lp/snappy/tests/test_snap.py |
143 | @@ -125,6 +125,7 @@ from lp.snappy.interfaces.snapbase import ( |
144 | from lp.snappy.interfaces.snapbuild import ( |
145 | ISnapBuild, |
146 | ISnapBuildSet, |
147 | + SnapBuildStoreUploadStatus, |
148 | ) |
149 | from lp.snappy.interfaces.snapbuildjob import ISnapStoreUploadJobSource |
150 | from lp.snappy.interfaces.snapjob import ISnapRequestBuildsJobSource |
151 | @@ -137,6 +138,10 @@ from lp.snappy.model.snap import ( |
152 | from lp.snappy.model.snapbuild import SnapFile |
153 | from lp.snappy.model.snapbuildjob import SnapBuildJob |
154 | from lp.snappy.model.snapjob import SnapJob |
155 | +from lp.snappy.tests.test_snapbuildjob import ( |
156 | + FakeSnapStoreClient, |
157 | + run_isolated_jobs, |
158 | + ) |
159 | from lp.testing import ( |
160 | admin_logged_in, |
161 | ANONYMOUS, |
162 | @@ -1079,6 +1084,50 @@ class TestSnap(TestCaseWithFactory): |
163 | snap.destroySelf() |
164 | self.assertFalse(getUtility(ISnapSet).exists(owner, "condemned")) |
165 | |
166 | + def test_getBuildByStoreRevision(self): |
167 | + snap1 = self.factory.makeSnap() |
168 | + build = self.factory.makeSnapBuild( |
169 | + snap=snap1, |
170 | + status=BuildStatus.FULLYBUILT) |
171 | + |
172 | + # There is no build with revision 5 for snap1 |
173 | + self.assertIsNone(snap1.getBuildByStoreRevision(5)) |
174 | + |
175 | + # Upload build1 and check we return it by version 1 |
176 | + job = getUtility(ISnapStoreUploadJobSource).create(build) |
177 | + client = FakeSnapStoreClient() |
178 | + client.upload.result = ( |
179 | + "http://sca.example/dev/api/snaps/1/builds/1/status") |
180 | + client.checkStatus.result = ( |
181 | + "http://sca.example/dev/click-apps/1/rev/1/", 1) |
182 | + self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient)) |
183 | + with dbuser(config.ISnapStoreUploadJobSource.dbuser): |
184 | + run_isolated_jobs([job]) |
185 | + self.assertEqual( |
186 | + SnapBuildStoreUploadStatus.UPLOADED, build.store_upload_status) |
187 | + self.assertEqual(build.store_upload_revision, 1) |
188 | + self.assertEqual(snap1.getBuildByStoreRevision(1), build) |
189 | + |
190 | + # build & upload again, check revision |
191 | + # and that we return the second build for revision 2 |
192 | + build2 = self.factory.makeSnapBuild( |
193 | + snap=snap1, |
194 | + status=BuildStatus.FULLYBUILT) |
195 | + job = getUtility(ISnapStoreUploadJobSource).create(build2) |
196 | + client = FakeSnapStoreClient() |
197 | + client.upload.result = ( |
198 | + "http://sca.example/dev/api/snaps/1/builds/2/status") |
199 | + client.checkStatus.result = ( |
200 | + "http://sca.example/dev/click-apps/1/rev/2/", 2) |
201 | + self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient)) |
202 | + with dbuser(config.ISnapStoreUploadJobSource.dbuser): |
203 | + run_isolated_jobs([job]) |
204 | + self.assertEqual( |
205 | + SnapBuildStoreUploadStatus.UPLOADED, build2.store_upload_status) |
206 | + self.assertEqual(build2.store_upload_revision, 2) |
207 | + self.assertEqual(snap1.getBuildByStoreRevision(2), build2) |
208 | + self.assertEqual(snap1.getBuildByStoreRevision(1), build) |
209 | + |
210 | def test_getBuildSummariesForSnapBuildIds(self): |
211 | snap1 = self.factory.makeSnap() |
212 | snap2 = self.factory.makeSnap() |
213 | diff --git a/lib/lp/snappy/tests/test_snapbuildjob.py b/lib/lp/snappy/tests/test_snapbuildjob.py |
214 | index 3acefa2..5b56264 100644 |
215 | --- a/lib/lp/snappy/tests/test_snapbuildjob.py |
216 | +++ b/lib/lp/snappy/tests/test_snapbuildjob.py |
217 | @@ -178,6 +178,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
218 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
219 | self.assertEqual(self.store_url, job.store_url) |
220 | self.assertEqual(1, job.store_revision) |
221 | + self.assertEqual(1, |
222 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
223 | self.assertIsNone(job.error_message) |
224 | self.assertEqual([], pop_notifications()) |
225 | self.assertWebhookDeliveries( |
226 | @@ -199,6 +201,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
227 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
228 | self.assertIsNone(job.store_url) |
229 | self.assertIsNone(job.store_revision) |
230 | + self.assertIsNone( |
231 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
232 | self.assertEqual("An upload failure", job.error_message) |
233 | self.assertEqual([], pop_notifications()) |
234 | self.assertWebhookDeliveries( |
235 | @@ -225,6 +229,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
236 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
237 | self.assertIsNone(job.store_url) |
238 | self.assertIsNone(job.store_revision) |
239 | + self.assertIsNone( |
240 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
241 | self.assertEqual("Authorization failed.", job.error_message) |
242 | [notification] = pop_notifications() |
243 | self.assertEqual( |
244 | @@ -272,6 +278,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
245 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
246 | self.assertIsNone(job.store_url) |
247 | self.assertIsNone(job.store_revision) |
248 | + self.assertIsNone( |
249 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
250 | self.assertIsNone(job.error_message) |
251 | self.assertEqual([], pop_notifications()) |
252 | self.assertEqual(JobStatus.WAITING, job.job.status) |
253 | @@ -290,6 +298,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
254 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
255 | self.assertEqual(self.store_url, job.store_url) |
256 | self.assertEqual(1, job.store_revision) |
257 | + self.assertEqual(1, |
258 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
259 | self.assertIsNone(job.error_message) |
260 | self.assertEqual([], pop_notifications()) |
261 | self.assertEqual(JobStatus.COMPLETED, job.job.status) |
262 | @@ -317,6 +327,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
263 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
264 | self.assertIsNone(job.store_url) |
265 | self.assertIsNone(job.store_revision) |
266 | + self.assertIsNone( |
267 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
268 | self.assertEqual("SSO melted.", job.error_message) |
269 | [notification] = pop_notifications() |
270 | self.assertEqual( |
271 | @@ -369,6 +381,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
272 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
273 | self.assertIsNone(job.store_url) |
274 | self.assertIsNone(job.store_revision) |
275 | + self.assertIsNone( |
276 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
277 | self.assertEqual("Failed to upload", job.error_message) |
278 | [notification] = pop_notifications() |
279 | self.assertEqual( |
280 | @@ -419,6 +433,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
281 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
282 | self.assertIsNone(job.store_url) |
283 | self.assertIsNone(job.store_revision) |
284 | + self.assertIsNone( |
285 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
286 | self.assertIsNone(job.error_message) |
287 | self.assertEqual([], pop_notifications()) |
288 | self.assertEqual(JobStatus.WAITING, job.job.status) |
289 | @@ -437,6 +453,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
290 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
291 | self.assertEqual(self.store_url, job.store_url) |
292 | self.assertEqual(1, job.store_revision) |
293 | + self.assertEqual(1, |
294 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
295 | self.assertIsNone(job.error_message) |
296 | self.assertEqual([], pop_notifications()) |
297 | self.assertEqual(JobStatus.COMPLETED, job.job.status) |
298 | @@ -468,6 +486,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
299 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
300 | self.assertIsNone(job.store_url) |
301 | self.assertIsNone(job.store_revision) |
302 | + self.assertIsNone( |
303 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
304 | self.assertEqual( |
305 | "Scan failed.\nConfinement not allowed.", job.error_message) |
306 | self.assertEqual([ |
307 | @@ -519,6 +539,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
308 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
309 | self.assertIsNone(job.store_url) |
310 | self.assertIsNone(job.store_revision) |
311 | + self.assertIsNone( |
312 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
313 | self.assertIsNone(job.error_message) |
314 | self.assertEqual([], pop_notifications()) |
315 | self.assertWebhookDeliveries( |
316 | @@ -542,6 +564,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
317 | self.assertContentEqual([job], snapbuild.store_upload_jobs) |
318 | self.assertEqual(self.store_url, job.store_url) |
319 | self.assertEqual(1, job.store_revision) |
320 | + self.assertEqual(1, |
321 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
322 | self.assertIsNone(job.error_message) |
323 | self.assertEqual([], pop_notifications()) |
324 | self.assertWebhookDeliveries( |
325 | @@ -603,6 +627,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory): |
326 | # Check we uploaded as expected |
327 | self.assertEqual(self.store_url, job.store_url) |
328 | self.assertEqual(1, job.store_revision) |
329 | + self.assertEqual(1, |
330 | + removeSecurityProxy(snapbuild)._store_upload_revision) |
331 | self.assertEqual(timedelta(seconds=60), job.retry_delay) |
332 | self.assertEqual(1, len(client.upload.calls)) |
333 | self.assertIsNone(job.error_message) |
As I noted in comments on the prerequisite MP, it seems likely that you'll need to adjust garbo tests here.