Merge lp:~cjwatson/launchpad/snap-delete-with-build-requests into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18815
Proposed branch: lp:~cjwatson/launchpad/snap-delete-with-build-requests
Merge into: lp:launchpad
Diff against target: 119 lines (+66/-4)
2 files modified
lib/lp/snappy/model/snap.py (+6/-4)
lib/lp/snappy/tests/test_snap.py (+60/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-delete-with-build-requests
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+358440@code.launchpad.net

Commit message

Delete associated build requests when deleting a snap.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/snappy/model/snap.py'
2--- lib/lp/snappy/model/snap.py 2018-10-09 09:25:19 +0000
3+++ lib/lp/snappy/model/snap.py 2018-11-07 15:02:24 +0000
4@@ -50,10 +50,7 @@
5 DateTimeFormatterAPI,
6 )
7 from lp.app.enums import PRIVATE_INFORMATION_TYPES
8-from lp.app.errors import (
9- IncompatibleArguments,
10- NotFoundError,
11- )
12+from lp.app.errors import IncompatibleArguments
13 from lp.app.interfaces.security import IAuthorization
14 from lp.buildmaster.enums import BuildStatus
15 from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
16@@ -117,6 +114,7 @@
17 )
18 from lp.services.features import getFeatureFlag
19 from lp.services.job.interfaces.job import JobStatus
20+from lp.services.job.model.job import Job
21 from lp.services.librarian.model import (
22 LibraryFileAlias,
23 LibraryFileContent,
24@@ -162,6 +160,7 @@
25 from lp.snappy.interfaces.snappyseries import ISnappyDistroSeriesSet
26 from lp.snappy.interfaces.snapstoreclient import ISnapStoreClient
27 from lp.snappy.model.snapbuild import SnapBuild
28+from lp.snappy.model.snapjob import SnapJob
29 from lp.soyuz.interfaces.archive import ArchiveDisabled
30 from lp.soyuz.model.archive import (
31 Archive,
32@@ -879,6 +878,9 @@
33 SnapBuild.snap = ?
34 """, (self.id,))
35 store.find(SnapBuild, SnapBuild.snap == self).remove()
36+ affected_jobs = Select(
37+ [SnapJob.job_id], And(SnapJob.job == Job.id, SnapJob.snap == self))
38+ store.find(Job, Job.id.is_in(affected_jobs)).remove()
39 getUtility(IWebhookSet).delete(self.webhooks)
40 store.remove(self)
41 store.find(
42
43=== modified file 'lib/lp/snappy/tests/test_snap.py'
44--- lib/lp/snappy/tests/test_snap.py 2018-10-09 09:25:19 +0000
45+++ lib/lp/snappy/tests/test_snap.py 2018-11-07 15:02:24 +0000
46@@ -111,6 +111,7 @@
47 from lp.snappy.model.snap import SnapSet
48 from lp.snappy.model.snapbuild import SnapFile
49 from lp.snappy.model.snapbuildjob import SnapBuildJob
50+from lp.snappy.model.snapjob import SnapJob
51 from lp.testing import (
52 admin_logged_in,
53 ANONYMOUS,
54@@ -961,6 +962,65 @@
55 other_build, getUtility(ISnapBuildSet).getByID(other_build.id))
56 self.assertIsNotNone(other_build.buildqueue_record)
57
58+ def test_delete_with_build_requests(self):
59+ # A snap package with build requests can be deleted.
60+ owner = self.factory.makePerson()
61+ distroseries = self.factory.makeDistroSeries()
62+ processor = self.factory.makeProcessor(supports_virtualized=True)
63+ das = self.factory.makeDistroArchSeries(
64+ distroseries=distroseries, architecturetag=processor.name,
65+ processor=processor)
66+ das.addOrUpdateChroot(
67+ self.factory.makeLibraryFileAlias(
68+ filename="fake_chroot.tar.gz", db_only=True))
69+ self.useFixture(GitHostingFixture(blob=dedent("""\
70+ architectures:
71+ - build-on: %s
72+ """ % processor.name)))
73+ [git_ref] = self.factory.makeGitRefs()
74+ condemned_snap = self.factory.makeSnap(
75+ registrant=owner, owner=owner, distroseries=distroseries,
76+ name="condemned", git_ref=git_ref)
77+ other_snap = self.factory.makeSnap(
78+ registrant=owner, owner=owner, distroseries=distroseries,
79+ git_ref=git_ref)
80+ self.assertTrue(getUtility(ISnapSet).exists(owner, "condemned"))
81+ with person_logged_in(owner):
82+ requests = []
83+ jobs = []
84+ for snap in (condemned_snap, other_snap):
85+ requests.append(snap.requestBuilds(
86+ owner, distroseries.main_archive,
87+ PackagePublishingPocket.UPDATES))
88+ jobs.append(removeSecurityProxy(requests[-1])._job)
89+ with dbuser(config.ISnapRequestBuildsJobSource.dbuser):
90+ JobRunner(jobs).runAll()
91+ for job in jobs:
92+ self.assertEqual(JobStatus.COMPLETED, job.job.status)
93+ for request in requests:
94+ self.assertNotEqual([], request.builds)
95+ store = Store.of(condemned_snap)
96+ store.flush()
97+ job_ids = [job.job_id for job in jobs]
98+ build_ids = [
99+ [build.id for build in request.builds] for request in requests]
100+ with person_logged_in(condemned_snap.owner):
101+ condemned_snap.destroySelf()
102+ flush_database_caches()
103+ # The deleted snap, its build requests, and its builds are gone.
104+ self.assertFalse(getUtility(ISnapSet).exists(owner, "condemned"))
105+ self.assertIsNone(store.get(SnapJob, job_ids[0]))
106+ for build_id in build_ids[0]:
107+ self.assertIsNone(getUtility(ISnapBuildSet).getByID(build_id))
108+ # Unrelated build requests and builds are still present.
109+ self.assertEqual(
110+ removeSecurityProxy(jobs[1]).context,
111+ store.get(SnapJob, job_ids[1]))
112+ other_builds = [
113+ getUtility(ISnapBuildSet).getByID(build_id)
114+ for build_id in build_ids[1]]
115+ self.assertEqual(list(requests[1].builds), other_builds)
116+
117 def test_related_webhooks_deleted(self):
118 owner = self.factory.makePerson()
119 snap = self.factory.makeSnap(registrant=owner, owner=owner)