Merge lp:~al-maisan/launchpad/partner-expiry-535030 into lp:launchpad

Proposed by Muharem Hrnjadovic
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~al-maisan/launchpad/partner-expiry-535030
Merge into: lp:launchpad
Diff against target: 432 lines (+127/-106)
3 files modified
cronscripts/expire-archive-files.py (+3/-3)
lib/lp/soyuz/scripts/expire_archive_files.py (+21/-15)
lib/lp/soyuz/scripts/tests/test_expire_archive_files.py (+103/-88)
To merge this branch: bzr merge lp:~al-maisan/launchpad/partner-expiry-535030
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) code Approve
Review via email: mp+20990@code.launchpad.net

Description of the change

Hello there!

This branch revises the former PPA source/binary expiration script to include
partner archives as well.

Most of the changes are due to the refactoring of the test code making it
possible to "reuse" the majority of the original tests.

Tests to run:

    bin/test -vv test_expire_archive_files

No "make lint" issues.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Looks good.

We discussed a few minor changes in IRC:

 * Use a dict for parameter substitution in those big queries; less brittle as the code continues to evolve.

 * Use the "common tests" class as a mixin rather than a fully-functional base class. That way you don't need to tell the test loader not to run it on its own.

Jeroen

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'cronscripts/expire-ppa-files.py' => 'cronscripts/expire-archive-files.py'
2--- cronscripts/expire-ppa-files.py 2010-01-20 10:32:32 +0000
3+++ cronscripts/expire-archive-files.py 2010-03-10 12:10:46 +0000
4@@ -12,11 +12,11 @@
5 import _pythonpath
6
7 from canonical.config import config
8-from lp.soyuz.scripts.expire_ppa_binaries import PPABinaryExpirer
9+from lp.soyuz.scripts.expire_archive_files import ArchiveExpirer
10
11
12 if __name__ == '__main__':
13- script = PPABinaryExpirer(
14- 'expire-ppa-files', dbuser=config.binaryfile_expire.dbuser)
15+ script = ArchiveExpirer(
16+ 'expire-archive-files', dbuser=config.binaryfile_expire.dbuser)
17 script.lock_and_run()
18
19
20=== renamed file 'lib/lp/soyuz/scripts/expire_ppa_binaries.py' => 'lib/lp/soyuz/scripts/expire_archive_files.py'
21--- lib/lp/soyuz/scripts/expire_ppa_binaries.py 2010-01-31 19:36:27 +0000
22+++ lib/lp/soyuz/scripts/expire_archive_files.py 2010-03-10 12:10:46 +0000
23@@ -34,7 +34,7 @@
24 """.split()
25
26
27-class PPABinaryExpirer(LaunchpadCronScript):
28+class ArchiveExpirer(LaunchpadCronScript):
29 """Helper class for expiring old PPA binaries.
30
31 Any PPA binary older than 30 days that is superseded or deleted
32@@ -60,6 +60,7 @@
33 from lp.soyuz.interfaces.archive import ArchivePurpose
34
35 stay_of_execution = '%d days' % num_days
36+ archive_types = (ArchivePurpose.PPA, ArchivePurpose.PARTNER)
37
38 # The subquery here has to repeat the checks for privacy and
39 # blacklisting on *other* publications that are also done in
40@@ -79,7 +80,7 @@
41 AND spph.dateremoved < (
42 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s)
43 AND spph.archive = archive.id
44- AND archive.purpose = %s
45+ AND archive.purpose IN %s
46 AND lfa.expires IS NULL
47 EXCEPT
48 SELECT sprf.libraryfile
49@@ -95,15 +96,15 @@
50 AND spph.archive = a.id
51 AND p.id = a.owner
52 AND (
53- p.name IN %s
54+ (p.name IN %s AND a.purpose = %s)
55 OR a.private IS TRUE
56- OR a.purpose != %s
57+ OR a.purpose NOT IN %s
58 OR dateremoved >
59 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s
60 OR dateremoved IS NULL);
61 """ % sqlvalues(
62- stay_of_execution, ArchivePurpose.PPA, self.blacklist,
63- ArchivePurpose.PPA, stay_of_execution))
64+ stay_of_execution, archive_types, self.blacklist,
65+ ArchivePurpose.PPA, archive_types, stay_of_execution))
66
67 lfa_ids = results.get_all()
68 return lfa_ids
69@@ -114,6 +115,7 @@
70 from lp.soyuz.interfaces.archive import ArchivePurpose
71
72 stay_of_execution = '%d days' % num_days
73+ archive_types = (ArchivePurpose.PPA, ArchivePurpose.PARTNER)
74
75 # The subquery here has to repeat the checks for privacy and
76 # blacklisting on *other* publications that are also done in
77@@ -131,9 +133,10 @@
78 AND bpr.id = bpf.binarypackagerelease
79 AND bpph.binarypackagerelease = bpr.id
80 AND bpph.dateremoved < (
81- CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s)
82+ CURRENT_TIMESTAMP AT TIME ZONE 'UTC' -
83+ interval %(stay_of_execution)s)
84 AND bpph.archive = archive.id
85- AND archive.purpose = %s
86+ AND archive.purpose IN %(archive_types)s
87 AND lfa.expires IS NULL
88 EXCEPT
89 SELECT bpf.libraryfile
90@@ -149,15 +152,18 @@
91 AND bpph.archive = a.id
92 AND p.id = a.owner
93 AND (
94- p.name IN %s
95+ (p.name IN %(blacklist)s AND a.purpose = %(ppa)s)
96 OR a.private IS TRUE
97- OR a.purpose != %s
98- OR dateremoved >
99- CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s
100- OR dateremoved IS NULL);
101+ OR a.purpose NOT IN %(archive_types)s
102+ OR dateremoved > (
103+ CURRENT_TIMESTAMP AT TIME ZONE 'UTC' -
104+ interval %(stay_of_execution)s)
105+ OR dateremoved IS NULL)
106 """ % sqlvalues(
107- stay_of_execution, ArchivePurpose.PPA, self.blacklist,
108- ArchivePurpose.PPA, stay_of_execution))
109+ stay_of_execution=stay_of_execution,
110+ archive_types=archive_types,
111+ blacklist=self.blacklist,
112+ ppa=ArchivePurpose.PPA))
113
114 lfa_ids = results.get_all()
115 return lfa_ids
116
117=== renamed file 'lib/lp/soyuz/scripts/tests/test_expire_ppa_bins.py' => 'lib/lp/soyuz/scripts/tests/test_expire_archive_files.py'
118--- lib/lp/soyuz/scripts/tests/test_expire_ppa_bins.py 2010-02-27 20:20:03 +0000
119+++ lib/lp/soyuz/scripts/tests/test_expire_archive_files.py 2010-03-10 12:10:46 +0000
120@@ -1,12 +1,10 @@
121 # Copyright 2009 Canonical Ltd. This software is licensed under the
122 # GNU Affero General Public License version 3 (see the file LICENSE).
123
124-"""Test the expire-ppa-binaries.py script. """
125+"""Test the expire-archive-files.py script. """
126
127+from datetime import datetime, timedelta
128 import pytz
129-
130-from datetime import datetime, timedelta
131-
132 import unittest
133
134 from zope.component import getUtility
135@@ -15,35 +13,20 @@
136 from canonical.launchpad.scripts import QuietFakeLogger
137 from canonical.testing.layers import LaunchpadZopelessLayer
138 from lp.registry.interfaces.distribution import IDistributionSet
139-from lp.registry.interfaces.person import IPersonSet
140-from lp.soyuz.scripts.expire_ppa_binaries import PPABinaryExpirer
141+from lp.soyuz.interfaces.archive import ArchivePurpose
142+from lp.soyuz.scripts.expire_archive_files import ArchiveExpirer
143 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
144 from lp.testing import TestCaseWithFactory
145
146
147-class TestPPABinaryExpiry(TestCaseWithFactory):
148- """Test the expire-ppa-binaries.py script."""
149-
150+class ArchiveExpiryTestBase(TestCaseWithFactory):
151+ """base class for the expire-archive-files.py script tests."""
152 layer = LaunchpadZopelessLayer
153 dbuser = config.binaryfile_expire.dbuser
154
155- # We need to test several cases are handled properly:
156- # - publications with no "dateremoved" are not expired
157- # - publications with dateremoved <= 30 days ago are not expired
158- # - publications with dateremoved > 30 days ago are expired
159- # - publications with dateremoved > 30 days ago but refer to a
160- # binary published elsewhere with no dateremoved are not
161- # expired
162- # - publications with dateremoved > 30 days ago but refer to a
163- # binary published elsewhere with dateremoved <= 30 days ago
164- # are not expired
165- # - publications with dateremoved > 30 days ago but refer to a
166- # binary published elsewhere with dateremoved > 30 days ago
167- # are expired.
168-
169 def setUp(self):
170 """Set up some test publications."""
171- super(TestPPABinaryExpiry, self).setUp()
172+ super(ArchiveExpiryTestBase, self).setUp()
173 # Configure the test publisher.
174 self.layer.switchDbUser("launchpad")
175 self.stp = SoyuzTestPublisher()
176@@ -54,16 +37,12 @@
177 self.under_threshold_date = self.now - timedelta(days=29)
178 self.over_threshold_date = self.now - timedelta(days=31)
179
180- # Prepare two PPAs for the tests to use.
181- self.ppa = self.factory.makeArchive()
182- self.ppa2 = self.factory.makeArchive()
183-
184 def getScript(self, test_args=None):
185- """Return a PPABinaryExpirer instance."""
186+ """Return a ArchiveExpirer instance."""
187 if test_args is None:
188 test_args = []
189 test_args.extend(['--expire-after', '30'])
190- script = PPABinaryExpirer("test expirer", test_args=test_args)
191+ script = ArchiveExpirer("test expirer", test_args=test_args)
192 script.logger = QuietFakeLogger()
193 script.txn = self.layer.txn
194 return script
195@@ -75,6 +54,24 @@
196 self.layer.switchDbUser(self.dbuser)
197 script.main()
198
199+ def _setUpExpirablePublications(self, archive=None):
200+ """Helper to set up two publications that are both expirable."""
201+ if archive is None:
202+ archive = self.archive
203+ pkg5 = self.stp.getPubSource(
204+ sourcename="pkg5", architecturehintlist="i386", archive=archive,
205+ dateremoved=self.over_threshold_date)
206+ other_source = pkg5.copyTo(
207+ pkg5.distroseries, pkg5.pocket, self.archive2)
208+ other_source.dateremoved = self.over_threshold_date
209+ [pub] = self.stp.getPubBinaries(
210+ pub_source=pkg5, dateremoved=self.over_threshold_date,
211+ archive=archive)
212+ [other_binary] = pub.copyTo(
213+ pub.distroarchseries.distroseries, pub.pocket, self.archive2)
214+ other_binary.dateremoved = self.over_threshold_date
215+ return pkg5, pub
216+
217 def assertBinaryExpired(self, publication):
218 self.assertNotEqual(
219 publication.binarypackagerelease.files[0].libraryfile.expires,
220@@ -99,13 +96,19 @@
221 None,
222 "lfa.expires should be None, but it's not.")
223
224+
225+class ArchiveExpiryCommonTests(object):
226+ """Common source/binary expiration test cases.
227+
228+ These will be shared irrespective of archive type (ppa/partner).
229+ """
230 def testNoExpirationWithNoDateremoved(self):
231 """Test that no expiring happens if no dateremoved set."""
232 pkg1 = self.stp.getPubSource(
233- sourcename="pkg1", architecturehintlist="i386", archive=self.ppa,
234- dateremoved=None)
235+ sourcename="pkg1", architecturehintlist="i386",
236+ archive=self.archive, dateremoved=None)
237 [pub] = self.stp.getPubBinaries(
238- pub_source=pkg1, dateremoved=None, archive=self.ppa)
239+ pub_source=pkg1, dateremoved=None, archive=self.archive)
240
241 self.runScript()
242 self.assertSourceNotExpired(pkg1)
243@@ -114,11 +117,11 @@
244 def testNoExpirationWithDateUnderThreshold(self):
245 """Test no expiring if dateremoved too recent."""
246 pkg2 = self.stp.getPubSource(
247- sourcename="pkg2", architecturehintlist="i386", archive=self.ppa,
248- dateremoved=self.under_threshold_date)
249+ sourcename="pkg2", architecturehintlist="i386",
250+ archive=self.archive, dateremoved=self.under_threshold_date)
251 [pub] = self.stp.getPubBinaries(
252 pub_source=pkg2, dateremoved=self.under_threshold_date,
253- archive=self.ppa)
254+ archive=self.archive)
255
256 self.runScript()
257 self.assertSourceNotExpired(pkg2)
258@@ -127,11 +130,11 @@
259 def testExpirationWithDateOverThreshold(self):
260 """Test expiring works if dateremoved old enough."""
261 pkg3 = self.stp.getPubSource(
262- sourcename="pkg3", architecturehintlist="i386", archive=self.ppa,
263- dateremoved=self.over_threshold_date)
264+ sourcename="pkg3", architecturehintlist="i386",
265+ archive=self.archive, dateremoved=self.over_threshold_date)
266 [pub] = self.stp.getPubBinaries(
267 pub_source=pkg3, dateremoved=self.over_threshold_date,
268- archive=self.ppa)
269+ archive=self.archive)
270
271 self.runScript()
272 self.assertSourceExpired(pkg3)
273@@ -140,16 +143,16 @@
274 def testNoExpirationWithDateOverThresholdAndOtherValidPublication(self):
275 """Test no expiry if dateremoved old enough but other publication."""
276 pkg4 = self.stp.getPubSource(
277- sourcename="pkg4", architecturehintlist="i386", archive=self.ppa,
278- dateremoved=self.over_threshold_date)
279+ sourcename="pkg4", architecturehintlist="i386",
280+ archive=self.archive, dateremoved=self.over_threshold_date)
281 other_source = pkg4.copyTo(
282- pkg4.distroseries, pkg4.pocket, self.ppa2)
283+ pkg4.distroseries, pkg4.pocket, self.archive2)
284 other_source.dateremoved = None
285 [pub] = self.stp.getPubBinaries(
286 pub_source=pkg4, dateremoved=self.over_threshold_date,
287- archive=self.ppa)
288+ archive=self.archive)
289 [other_binary] = pub.copyTo(
290- pub.distroarchseries.distroseries, pub.pocket, self.ppa2)
291+ pub.distroarchseries.distroseries, pub.pocket, self.archive2)
292 other_binary.dateremoved = None
293
294 self.runScript()
295@@ -163,40 +166,22 @@
296 not over date threshold.
297 """
298 pkg5 = self.stp.getPubSource(
299- sourcename="pkg5", architecturehintlist="i386", archive=self.ppa,
300- dateremoved=self.over_threshold_date)
301+ sourcename="pkg5", architecturehintlist="i386",
302+ archive=self.archive, dateremoved=self.over_threshold_date)
303 other_source = pkg5.copyTo(
304- pkg5.distroseries, pkg5.pocket, self.ppa2)
305+ pkg5.distroseries, pkg5.pocket, self.archive2)
306 other_source.dateremoved = self.under_threshold_date
307 [pub] = self.stp.getPubBinaries(
308 pub_source=pkg5, dateremoved=self.over_threshold_date,
309- archive=self.ppa)
310+ archive=self.archive)
311 [other_binary] = pub.copyTo(
312- pub.distroarchseries.distroseries, pub.pocket, self.ppa2)
313+ pub.distroarchseries.distroseries, pub.pocket, self.archive2)
314 other_binary.dateremoved = self.under_threshold_date
315
316 self.runScript()
317 self.assertSourceNotExpired(pkg5)
318 self.assertBinaryNotExpired(pub)
319
320- def _setUpExpirablePublications(self, archive=None):
321- """Helper to set up two publications that are both expirable."""
322- if archive is None:
323- archive = self.ppa
324- pkg5 = self.stp.getPubSource(
325- sourcename="pkg5", architecturehintlist="i386", archive=archive,
326- dateremoved=self.over_threshold_date)
327- other_source = pkg5.copyTo(
328- pkg5.distroseries, pkg5.pocket, self.ppa2)
329- other_source.dateremoved = self.over_threshold_date
330- [pub] = self.stp.getPubBinaries(
331- pub_source=pkg5, dateremoved=self.over_threshold_date,
332- archive=archive)
333- [other_binary] = pub.copyTo(
334- pub.distroarchseries.distroseries, pub.pocket, self.ppa2)
335- other_binary.dateremoved = self.over_threshold_date
336- return pkg5, pub
337-
338 def testNoExpirationWithDateOverThresholdAndOtherPubOverThreshold(self):
339 """Test expiring works.
340
341@@ -208,26 +193,6 @@
342 self.assertSourceExpired(source)
343 self.assertBinaryExpired(binary)
344
345- def testBlacklistingWorks(self):
346- """Test that blacklisted PPAs are not expired."""
347- source, binary = self._setUpExpirablePublications(archive=self.ppa)
348- script = self.getScript()
349- script.blacklist = [self.ppa.owner.name, ]
350- self.layer.txn.commit()
351- self.layer.switchDbUser(self.dbuser)
352- script.main()
353- self.assertSourceNotExpired(source)
354- self.assertBinaryNotExpired(binary)
355-
356- def testPrivatePPAsNotExpired(self):
357- """Test that private PPAs are not expired."""
358- self.ppa.private = True
359- self.ppa.buildd_secret = "foo"
360- source, binary = self._setUpExpirablePublications()
361- self.runScript()
362- self.assertSourceNotExpired(source)
363- self.assertBinaryNotExpired(binary)
364-
365 def testDryRun(self):
366 """Test that when dryrun is specified, nothing is expired."""
367 source, binary = self._setUpExpirablePublications()
368@@ -240,7 +205,7 @@
369 self.assertSourceNotExpired(source)
370 self.assertBinaryNotExpired(binary)
371
372- def testDoesNotAffectNonPPA(self):
373+ def testDoesNotAffectPrimary(self):
374 """Test that expiry does not happen for non-PPA publications."""
375 ubuntu_archive = getUtility(IDistributionSet)['ubuntu'].main_archive
376 source, binary = self._setUpExpirablePublications(ubuntu_archive)
377@@ -249,5 +214,55 @@
378 self.assertBinaryNotExpired(binary)
379
380
381+class TestPPAExpiry(ArchiveExpiryTestBase, ArchiveExpiryCommonTests):
382+ """Test the expire-archive-files.py script.
383+
384+ Here we make use of the common test cases defined in the base class but
385+ also add tests specific to PPAs (excluding particular PPAs from expiry
386+ based on a "black list" or on the fact that PPA is private).
387+ """
388+
389+ def setUp(self):
390+ """Set up some test publications."""
391+ super(TestPPAExpiry, self).setUp()
392+ # Prepare two PPAs for the tests to use.
393+ self.archive = self.factory.makeArchive()
394+ self.archive2 = self.factory.makeArchive()
395+
396+ def testBlacklistingWorks(self):
397+ """Test that blacklisted PPAs are not expired."""
398+ source, binary = self._setUpExpirablePublications(
399+ archive=self.archive)
400+ script = self.getScript()
401+ script.blacklist = [self.archive.owner.name, ]
402+ self.layer.txn.commit()
403+ self.layer.switchDbUser(self.dbuser)
404+ script.main()
405+ self.assertSourceNotExpired(source)
406+ self.assertBinaryNotExpired(binary)
407+
408+ def testPrivatePPAsNotExpired(self):
409+ """Test that private PPAs are not expired."""
410+ self.archive.private = True
411+ self.archive.buildd_secret = "foo"
412+ source, binary = self._setUpExpirablePublications()
413+ self.runScript()
414+ self.assertSourceNotExpired(source)
415+ self.assertBinaryNotExpired(binary)
416+
417+
418+class TestPartnerExpiry(ArchiveExpiryTestBase, ArchiveExpiryCommonTests):
419+ """Test the expire-archive-files.py script on partner archives."""
420+
421+ def setUp(self):
422+ """Set up the partner archives under test."""
423+ super(TestPartnerExpiry, self).setUp()
424+ # Prepare two partner archives for the tests to use.
425+ self.archive = self.factory.makeArchive(
426+ purpose=ArchivePurpose.PARTNER)
427+ self.archive2 = self.factory.makeArchive(
428+ purpose=ArchivePurpose.PARTNER)
429+
430+
431 def test_suite():
432 return unittest.TestLoader().loadTestsFromName(__name__)