Merge ~ilasc/launchpad:add-get-snapbuild-by-revision into launchpad: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)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+407781@code.launchpad.net

Commit message

Add getBuildByStoreRevision to Snap

Description of the change

This needs the new column "_store_upload_revision" to be added to SnapBuild and populated (prerequisite branch: populate-store-upload-revision).

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

As I noted in comments on the prerequisite MP, it seems likely that you'll need to adjust garbo tests here.

review: Needs Fixing
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
diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
index 3a43045..5fb7f77 100644
--- a/lib/lp/scripts/tests/test_garbo.py
+++ b/lib/lp/scripts/tests/test_garbo.py
@@ -2013,52 +2013,34 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
2013 with dbuser(config.ISnapStoreUploadJobSource.dbuser):2013 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
2014 run_isolated_jobs([job])2014 run_isolated_jobs([job])
20152015
2016 # this mimics what we have in the DB right now:2016 # The _store_upload_revision now gets populated when
2017 # uploaded snaps that do not have the new DB column2017 # uploading the build as part of the
2018 # _store_upload_revision populated yet2018 # `SnapStoreUploadJob.store_revision` property setter.
2019 populator = PopulateSnapBuildStoreRevision(None)2019 # Assert that upload job above populated _store_upload_revision
2020 filter = populator.findSnapBuilds()2020 # for build1:
2021 build1 = removeSecurityProxy(build1)2021 build1 = removeSecurityProxy(build1)
2022 self.assertEqual(1, filter.count())
2023 self.assertEqual(build1, filter.one())
2024 self.assertEqual(build1._store_upload_revision, None)
2025
2026 # run the garbo job and verify _store_upload_revision
2027 # is not populated with the value assigned to the build during upload
2028 self.runDaily()
2029 switch_dbuser('testadmin')
2030 self.assertEqual(build1._store_upload_revision, 1)2022 self.assertEqual(build1._store_upload_revision, 1)
20312023
2032 # Tests that of all builds for the same snap only those that have2024 # and that the populator job doesn't pick up build1 anymore.
2033 # been uploaded to the store will get2025 populator = PopulateSnapBuildStoreRevision(None)
2034 # their new _store_upload_revision DB column updated2026 filter = populator.findSnapBuilds()
2035 build2 = self.factory.makeSnapBuild(2027 self.assertEqual(0, filter.count())
2036 snap=snap1,2028
2037 status=BuildStatus.FULLYBUILT)2029 # We manually simulate here the situation
2038 build3 = self.factory.makeSnapBuild(2030 # where a job to upload snap to the store has run in the past
2039 snap=snap1,2031 # without populating the new column (prior to MP 407781).
2040 status=BuildStatus.FULLYBUILT)2032 build1._store_upload_revision = None
2041 job = getUtility(ISnapStoreUploadJobSource).create(build2)
2042 client = FakeSnapStoreClient()
2043 client.upload.result = (
2044 "http://sca.example/dev/api/snaps/1/builds/2/status")
2045 client.checkStatus.result = (
2046 "http://sca.example/dev/click-apps/1/rev/2/", 1)
2047 self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient))
2048 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
2049 run_isolated_jobs([job])
20502033
2034 # in this case the populator garbo job should pick up build1
2035 # to update the _store_upload_revision for it:
2051 populator = PopulateSnapBuildStoreRevision(None)2036 populator = PopulateSnapBuildStoreRevision(None)
2052 filter = populator.findSnapBuilds()2037 filter = populator.findSnapBuilds()
2053 self.assertEqual(1, filter.count())2038 self.assertEqual(1, filter.count())
2054 self.assertEqual(build2, filter.one())2039 self.assertEqual(build1, filter.one())
20552040
2056 self.runDaily()2041 self.runDaily()
2057 switch_dbuser('testadmin')2042 switch_dbuser('testadmin')
2058 build2 = removeSecurityProxy(build2)2043 self.assertEqual(build1._store_upload_revision, 1)
2059 self.assertEqual(build2._store_upload_revision, 1)
2060 build3 = removeSecurityProxy(build3)
2061 self.assertIsNone(build3._store_upload_revision)
20622044
20632045
2064class TestGarboTasks(TestCaseWithFactory):2046class TestGarboTasks(TestCaseWithFactory):
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index 2445553..088af8c 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -529,6 +529,21 @@ class ISnapView(Interface):
529529
530 @call_with(user=REQUEST_USER)530 @call_with(user=REQUEST_USER)
531 @operation_parameters(531 @operation_parameters(
532 store_upload_revision=Int(title="Store revision",
533 required=True))
534 @export_read_operation()
535 @operation_for_version("devel")
536 def getBuildByStoreRevision(store_upload_revision, user=None):
537 """Returns the build (if any) of that snap recipe
538 that has the given store_upload_revision.
539
540 :param store_upload_revision: The revision assigned by the store.
541 :param user: The `IPerson` requesting this information.
542 :return: An 'ISnapBuild' or None.
543 """
544
545 @call_with(user=REQUEST_USER)
546 @operation_parameters(
532 request_ids=List(547 request_ids=List(
533 title=_("A list of snap build request IDs."), value_type=Int(),548 title=_("A list of snap build request IDs."), value_type=Int(),
534 required=False),549 required=False),
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 24aa2be..e68182e 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -1111,6 +1111,20 @@ class Snap(Storm, WebhookTargetMixin):
11111111
1112 return result1112 return result
11131113
1114 def getBuildByStoreRevision(self, store_upload_revision, user=None):
1115 build = Store.of(self).find(
1116 SnapBuild,
1117 SnapBuild.snap == self,
1118 SnapBuild._store_upload_revision == store_upload_revision,
1119 SnapBuild.archive == Archive.id,
1120 Archive._enabled,
1121 get_enabled_archive_filter(
1122 user,
1123 include_public=True,
1124 include_subscribed=True)
1125 ).one()
1126 return build
1127
1114 @property1128 @property
1115 def builds(self):1129 def builds(self):
1116 """See `ISnap`."""1130 """See `ISnap`."""
diff --git a/lib/lp/snappy/model/snapbuildjob.py b/lib/lp/snappy/model/snapbuildjob.py
index 9634f62..a8fc49f 100644
--- a/lib/lp/snappy/model/snapbuildjob.py
+++ b/lib/lp/snappy/model/snapbuildjob.py
@@ -263,6 +263,7 @@ class SnapStoreUploadJob(SnapBuildJobDerived):
263 if self.snapbuild.store_upload_metadata is None:263 if self.snapbuild.store_upload_metadata is None:
264 self.snapbuild.store_upload_metadata = {}264 self.snapbuild.store_upload_metadata = {}
265 self.snapbuild.store_upload_metadata["store_revision"] = revision265 self.snapbuild.store_upload_metadata["store_revision"] = revision
266 self.snapbuild._store_upload_revision = revision
266267
267 @property268 @property
268 def status_url(self):269 def status_url(self):
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index 4d9c92f..adb8cfa 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -125,6 +125,7 @@ from lp.snappy.interfaces.snapbase import (
125from lp.snappy.interfaces.snapbuild import (125from lp.snappy.interfaces.snapbuild import (
126 ISnapBuild,126 ISnapBuild,
127 ISnapBuildSet,127 ISnapBuildSet,
128 SnapBuildStoreUploadStatus,
128 )129 )
129from lp.snappy.interfaces.snapbuildjob import ISnapStoreUploadJobSource130from lp.snappy.interfaces.snapbuildjob import ISnapStoreUploadJobSource
130from lp.snappy.interfaces.snapjob import ISnapRequestBuildsJobSource131from lp.snappy.interfaces.snapjob import ISnapRequestBuildsJobSource
@@ -137,6 +138,10 @@ from lp.snappy.model.snap import (
137from lp.snappy.model.snapbuild import SnapFile138from lp.snappy.model.snapbuild import SnapFile
138from lp.snappy.model.snapbuildjob import SnapBuildJob139from lp.snappy.model.snapbuildjob import SnapBuildJob
139from lp.snappy.model.snapjob import SnapJob140from lp.snappy.model.snapjob import SnapJob
141from lp.snappy.tests.test_snapbuildjob import (
142 FakeSnapStoreClient,
143 run_isolated_jobs,
144 )
140from lp.testing import (145from lp.testing import (
141 admin_logged_in,146 admin_logged_in,
142 ANONYMOUS,147 ANONYMOUS,
@@ -1079,6 +1084,50 @@ class TestSnap(TestCaseWithFactory):
1079 snap.destroySelf()1084 snap.destroySelf()
1080 self.assertFalse(getUtility(ISnapSet).exists(owner, "condemned"))1085 self.assertFalse(getUtility(ISnapSet).exists(owner, "condemned"))
10811086
1087 def test_getBuildByStoreRevision(self):
1088 snap1 = self.factory.makeSnap()
1089 build = self.factory.makeSnapBuild(
1090 snap=snap1,
1091 status=BuildStatus.FULLYBUILT)
1092
1093 # There is no build with revision 5 for snap1
1094 self.assertIsNone(snap1.getBuildByStoreRevision(5))
1095
1096 # Upload build1 and check we return it by version 1
1097 job = getUtility(ISnapStoreUploadJobSource).create(build)
1098 client = FakeSnapStoreClient()
1099 client.upload.result = (
1100 "http://sca.example/dev/api/snaps/1/builds/1/status")
1101 client.checkStatus.result = (
1102 "http://sca.example/dev/click-apps/1/rev/1/", 1)
1103 self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient))
1104 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
1105 run_isolated_jobs([job])
1106 self.assertEqual(
1107 SnapBuildStoreUploadStatus.UPLOADED, build.store_upload_status)
1108 self.assertEqual(build.store_upload_revision, 1)
1109 self.assertEqual(snap1.getBuildByStoreRevision(1), build)
1110
1111 # build & upload again, check revision
1112 # and that we return the second build for revision 2
1113 build2 = self.factory.makeSnapBuild(
1114 snap=snap1,
1115 status=BuildStatus.FULLYBUILT)
1116 job = getUtility(ISnapStoreUploadJobSource).create(build2)
1117 client = FakeSnapStoreClient()
1118 client.upload.result = (
1119 "http://sca.example/dev/api/snaps/1/builds/2/status")
1120 client.checkStatus.result = (
1121 "http://sca.example/dev/click-apps/1/rev/2/", 2)
1122 self.useFixture(ZopeUtilityFixture(client, ISnapStoreClient))
1123 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
1124 run_isolated_jobs([job])
1125 self.assertEqual(
1126 SnapBuildStoreUploadStatus.UPLOADED, build2.store_upload_status)
1127 self.assertEqual(build2.store_upload_revision, 2)
1128 self.assertEqual(snap1.getBuildByStoreRevision(2), build2)
1129 self.assertEqual(snap1.getBuildByStoreRevision(1), build)
1130
1082 def test_getBuildSummariesForSnapBuildIds(self):1131 def test_getBuildSummariesForSnapBuildIds(self):
1083 snap1 = self.factory.makeSnap()1132 snap1 = self.factory.makeSnap()
1084 snap2 = self.factory.makeSnap()1133 snap2 = self.factory.makeSnap()
diff --git a/lib/lp/snappy/tests/test_snapbuildjob.py b/lib/lp/snappy/tests/test_snapbuildjob.py
index 3acefa2..5b56264 100644
--- a/lib/lp/snappy/tests/test_snapbuildjob.py
+++ b/lib/lp/snappy/tests/test_snapbuildjob.py
@@ -178,6 +178,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
178 self.assertContentEqual([job], snapbuild.store_upload_jobs)178 self.assertContentEqual([job], snapbuild.store_upload_jobs)
179 self.assertEqual(self.store_url, job.store_url)179 self.assertEqual(self.store_url, job.store_url)
180 self.assertEqual(1, job.store_revision)180 self.assertEqual(1, job.store_revision)
181 self.assertEqual(1,
182 removeSecurityProxy(snapbuild)._store_upload_revision)
181 self.assertIsNone(job.error_message)183 self.assertIsNone(job.error_message)
182 self.assertEqual([], pop_notifications())184 self.assertEqual([], pop_notifications())
183 self.assertWebhookDeliveries(185 self.assertWebhookDeliveries(
@@ -199,6 +201,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
199 self.assertContentEqual([job], snapbuild.store_upload_jobs)201 self.assertContentEqual([job], snapbuild.store_upload_jobs)
200 self.assertIsNone(job.store_url)202 self.assertIsNone(job.store_url)
201 self.assertIsNone(job.store_revision)203 self.assertIsNone(job.store_revision)
204 self.assertIsNone(
205 removeSecurityProxy(snapbuild)._store_upload_revision)
202 self.assertEqual("An upload failure", job.error_message)206 self.assertEqual("An upload failure", job.error_message)
203 self.assertEqual([], pop_notifications())207 self.assertEqual([], pop_notifications())
204 self.assertWebhookDeliveries(208 self.assertWebhookDeliveries(
@@ -225,6 +229,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
225 self.assertContentEqual([job], snapbuild.store_upload_jobs)229 self.assertContentEqual([job], snapbuild.store_upload_jobs)
226 self.assertIsNone(job.store_url)230 self.assertIsNone(job.store_url)
227 self.assertIsNone(job.store_revision)231 self.assertIsNone(job.store_revision)
232 self.assertIsNone(
233 removeSecurityProxy(snapbuild)._store_upload_revision)
228 self.assertEqual("Authorization failed.", job.error_message)234 self.assertEqual("Authorization failed.", job.error_message)
229 [notification] = pop_notifications()235 [notification] = pop_notifications()
230 self.assertEqual(236 self.assertEqual(
@@ -272,6 +278,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
272 self.assertContentEqual([job], snapbuild.store_upload_jobs)278 self.assertContentEqual([job], snapbuild.store_upload_jobs)
273 self.assertIsNone(job.store_url)279 self.assertIsNone(job.store_url)
274 self.assertIsNone(job.store_revision)280 self.assertIsNone(job.store_revision)
281 self.assertIsNone(
282 removeSecurityProxy(snapbuild)._store_upload_revision)
275 self.assertIsNone(job.error_message)283 self.assertIsNone(job.error_message)
276 self.assertEqual([], pop_notifications())284 self.assertEqual([], pop_notifications())
277 self.assertEqual(JobStatus.WAITING, job.job.status)285 self.assertEqual(JobStatus.WAITING, job.job.status)
@@ -290,6 +298,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
290 self.assertContentEqual([job], snapbuild.store_upload_jobs)298 self.assertContentEqual([job], snapbuild.store_upload_jobs)
291 self.assertEqual(self.store_url, job.store_url)299 self.assertEqual(self.store_url, job.store_url)
292 self.assertEqual(1, job.store_revision)300 self.assertEqual(1, job.store_revision)
301 self.assertEqual(1,
302 removeSecurityProxy(snapbuild)._store_upload_revision)
293 self.assertIsNone(job.error_message)303 self.assertIsNone(job.error_message)
294 self.assertEqual([], pop_notifications())304 self.assertEqual([], pop_notifications())
295 self.assertEqual(JobStatus.COMPLETED, job.job.status)305 self.assertEqual(JobStatus.COMPLETED, job.job.status)
@@ -317,6 +327,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
317 self.assertContentEqual([job], snapbuild.store_upload_jobs)327 self.assertContentEqual([job], snapbuild.store_upload_jobs)
318 self.assertIsNone(job.store_url)328 self.assertIsNone(job.store_url)
319 self.assertIsNone(job.store_revision)329 self.assertIsNone(job.store_revision)
330 self.assertIsNone(
331 removeSecurityProxy(snapbuild)._store_upload_revision)
320 self.assertEqual("SSO melted.", job.error_message)332 self.assertEqual("SSO melted.", job.error_message)
321 [notification] = pop_notifications()333 [notification] = pop_notifications()
322 self.assertEqual(334 self.assertEqual(
@@ -369,6 +381,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
369 self.assertContentEqual([job], snapbuild.store_upload_jobs)381 self.assertContentEqual([job], snapbuild.store_upload_jobs)
370 self.assertIsNone(job.store_url)382 self.assertIsNone(job.store_url)
371 self.assertIsNone(job.store_revision)383 self.assertIsNone(job.store_revision)
384 self.assertIsNone(
385 removeSecurityProxy(snapbuild)._store_upload_revision)
372 self.assertEqual("Failed to upload", job.error_message)386 self.assertEqual("Failed to upload", job.error_message)
373 [notification] = pop_notifications()387 [notification] = pop_notifications()
374 self.assertEqual(388 self.assertEqual(
@@ -419,6 +433,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
419 self.assertContentEqual([job], snapbuild.store_upload_jobs)433 self.assertContentEqual([job], snapbuild.store_upload_jobs)
420 self.assertIsNone(job.store_url)434 self.assertIsNone(job.store_url)
421 self.assertIsNone(job.store_revision)435 self.assertIsNone(job.store_revision)
436 self.assertIsNone(
437 removeSecurityProxy(snapbuild)._store_upload_revision)
422 self.assertIsNone(job.error_message)438 self.assertIsNone(job.error_message)
423 self.assertEqual([], pop_notifications())439 self.assertEqual([], pop_notifications())
424 self.assertEqual(JobStatus.WAITING, job.job.status)440 self.assertEqual(JobStatus.WAITING, job.job.status)
@@ -437,6 +453,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
437 self.assertContentEqual([job], snapbuild.store_upload_jobs)453 self.assertContentEqual([job], snapbuild.store_upload_jobs)
438 self.assertEqual(self.store_url, job.store_url)454 self.assertEqual(self.store_url, job.store_url)
439 self.assertEqual(1, job.store_revision)455 self.assertEqual(1, job.store_revision)
456 self.assertEqual(1,
457 removeSecurityProxy(snapbuild)._store_upload_revision)
440 self.assertIsNone(job.error_message)458 self.assertIsNone(job.error_message)
441 self.assertEqual([], pop_notifications())459 self.assertEqual([], pop_notifications())
442 self.assertEqual(JobStatus.COMPLETED, job.job.status)460 self.assertEqual(JobStatus.COMPLETED, job.job.status)
@@ -468,6 +486,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
468 self.assertContentEqual([job], snapbuild.store_upload_jobs)486 self.assertContentEqual([job], snapbuild.store_upload_jobs)
469 self.assertIsNone(job.store_url)487 self.assertIsNone(job.store_url)
470 self.assertIsNone(job.store_revision)488 self.assertIsNone(job.store_revision)
489 self.assertIsNone(
490 removeSecurityProxy(snapbuild)._store_upload_revision)
471 self.assertEqual(491 self.assertEqual(
472 "Scan failed.\nConfinement not allowed.", job.error_message)492 "Scan failed.\nConfinement not allowed.", job.error_message)
473 self.assertEqual([493 self.assertEqual([
@@ -519,6 +539,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
519 self.assertContentEqual([job], snapbuild.store_upload_jobs)539 self.assertContentEqual([job], snapbuild.store_upload_jobs)
520 self.assertIsNone(job.store_url)540 self.assertIsNone(job.store_url)
521 self.assertIsNone(job.store_revision)541 self.assertIsNone(job.store_revision)
542 self.assertIsNone(
543 removeSecurityProxy(snapbuild)._store_upload_revision)
522 self.assertIsNone(job.error_message)544 self.assertIsNone(job.error_message)
523 self.assertEqual([], pop_notifications())545 self.assertEqual([], pop_notifications())
524 self.assertWebhookDeliveries(546 self.assertWebhookDeliveries(
@@ -542,6 +564,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
542 self.assertContentEqual([job], snapbuild.store_upload_jobs)564 self.assertContentEqual([job], snapbuild.store_upload_jobs)
543 self.assertEqual(self.store_url, job.store_url)565 self.assertEqual(self.store_url, job.store_url)
544 self.assertEqual(1, job.store_revision)566 self.assertEqual(1, job.store_revision)
567 self.assertEqual(1,
568 removeSecurityProxy(snapbuild)._store_upload_revision)
545 self.assertIsNone(job.error_message)569 self.assertIsNone(job.error_message)
546 self.assertEqual([], pop_notifications())570 self.assertEqual([], pop_notifications())
547 self.assertWebhookDeliveries(571 self.assertWebhookDeliveries(
@@ -603,6 +627,8 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
603 # Check we uploaded as expected627 # Check we uploaded as expected
604 self.assertEqual(self.store_url, job.store_url)628 self.assertEqual(self.store_url, job.store_url)
605 self.assertEqual(1, job.store_revision)629 self.assertEqual(1, job.store_revision)
630 self.assertEqual(1,
631 removeSecurityProxy(snapbuild)._store_upload_revision)
606 self.assertEqual(timedelta(seconds=60), job.retry_delay)632 self.assertEqual(timedelta(seconds=60), job.retry_delay)
607 self.assertEqual(1, len(client.upload.calls))633 self.assertEqual(1, len(client.upload.calls))
608 self.assertIsNone(job.error_message)634 self.assertIsNone(job.error_message)

Subscribers

People subscribed via source and target branches

to status/vote changes: