Merge lp:~al-maisan/launchpad/partner-expiry-535030 into lp:launchpad
- partner-expiry-535030
- Merge into devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | code | Approve | |
Review via email: mp+20990@code.launchpad.net |
Commit message
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_
No "make lint" issues.
To post a comment you must log in.
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__) |
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