Merge lp:~cjwatson/launchpad/proposed-as-staging-pocket into lp:launchpad

Proposed by Colin Watson on 2012-03-29
Status: Merged
Approved by: William Grant on 2012-03-29
Approved revision: 15043
Merged at revision: 15040
Proposed branch: lp:~cjwatson/launchpad/proposed-as-staging-pocket
Merge into: lp:launchpad
Diff against target: 1314 lines (+280/-378) 11 files modified
To merge this branch: bzr merge lp:~cjwatson/launchpad/proposed-as-staging-pocket
Reviewer Review Type Date Requested Status
William Grant code 2012-03-29 Approve on 2012-03-29
Review via email: mp+99911@code.launchpad.net

Commit Message

Allow uploads to PROPOSED pocket of development distroseries.

Description of the Change

== Summary ==

As bug 930217 reports, we would like to use the PROPOSED pocket as a general staging area to reduce problems with inter-architecture build skew, permit installability and other automatic testing before promotion to the RELEASE pocket, and suchlike, in pursuit of a general goal to make the development release of Ubuntu more continuously usable. This is hampered by the fact that it is not currently possible to upload to the PROPOSED pocket pre-release, except when the distroseries is frozen.

== Proposed fix ==

Make it possible to upload to the PROPOSED pocket pre-release, and auto-approve such uploads in the same situations that we would auto-approve uploads to the RELEASE pocket.

== Implementation details ==

The meat of the implementation is in DistroSeries.canUploadToPocket (to enable uploads at all) and InsecureUploadPolicy.autoApprove and BasicCopyPolicy.autoApprove (to deal with auto-approval). The only real nit here is that we need an extra distroseries.isUnstable() check in the autoApprove methods, since the addition of auto-approval for PROPOSED means that it's no longer enough to rely upon canUploadToPocket denying RELEASE pocket uploads post-release. The tests in this area were already pretty good, but of course I added a few more.

I faffed around for ages trying to get this branch down to non-net-positive LoC, and did a certain amount of refactoring of tests: particularly, I think lib/lp/soyuz/adapters/tests/test_copypolicy.py is considerably more readable now, and I cleaned up the use of assert* in lib/lp/soyuz/tests/test_archive.py. Eventually I noticed that there were some test data files in archiveuploader that AFAICS are no longer used, and deleting those was enough to get me comfortably into negative LoC.

== Tests ==

bin/test -vvct archiveuploader -t distroseries -t soyuz

== Demo and Q/A ==

Upload packages to DEVELOPMENT, FROZEN, and CURRENT distroseries on dogfood; they should be respectively auto-approved, held for approval, and held for approval.

== lint ==

I fixed some pre-existing lint. There are still some long lines in doctests that I didn't feel comfortable cleaning up:

./lib/lp/archiveuploader/tests/nascentupload-announcements.txt
     186: want exceeds 78 characters.
     187: want exceeds 78 characters.
     655: want exceeds 78 characters.
     722: want exceeds 78 characters.
     724: want exceeds 78 characters.
     770: want exceeds 78 characters.
     772: want exceeds 78 characters.
./lib/lp/registry/doc/distroseries.txt
     520: source exceeds 78 characters.
     521: source exceeds 78 characters.
     725: source exceeds 78 characters.

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)

Preview Diff

1=== removed file 'lib/lp/archiveuploader/tests/data/badformat-changes'
2--- lib/lp/archiveuploader/tests/data/badformat-changes 2007-05-04 17:48:03 +0000
3+++ lib/lp/archiveuploader/tests/data/badformat-changes 1970-01-01 00:00:00 +0000
4@@ -1,40 +0,0 @@
5------BEGIN PGP SIGNED MESSAGE-----
6-Hash: SHA1
7-
8-Format: 1.7
9-Date: Sun, 29 Aug 2004 03:47:46 +0200
10-Source: abiword
11-Binary: abiword-plugins-gnome abiword-gnome abiword-doc xfonts-abi abiword-help abiword abiword-plugins abiword-common
12-Architecture: mips
13-Version: 2.0.10-1.2
14-Distribution: unstable
15-Urgency: high
16-Maintainer: buildd mips user account <buildd@pepe.buildd.net>
17-Changed-By: Jordi Mallach <jordi@debian.org>
18-Description:
19- abiword - WYSIWYG word processor based on GTK2
20- abiword-common - WYSIWYG word processor based on GTK2
21- abiword-gnome - WYSIWYG word processor based on GTK2/GNOME2
22- abiword-plugins - Plugins for AbiWord
23- abiword-plugins-gnome - Plugins for AbiWord (with GNOME dependency)
24-Closes: 267199
25-Changes:
26- abiword (2.0.10-1.2) unstable; urgency=high
27- .
28- * Non-Maintainer Upload.
29- * debian/patches/01_relibtoolise.dpatch: damn, I missed the *other*
30- configure script. Abiword's source tarball sucks in many ways...
31- (really closes: #267199).
32-Files:
33- 2a0175f42ebcf4c42312ba5837108fc2 1504956 editors optional abiword-common_2.0.10-1.2_mips.deb
34- dc5fe0eeb1b233cf656f46665f150488 2014536 editors optional abiword_2.0.10-1.2_mips.deb
35- b418b9cc47f3d891a6fecb40cd5524db 2012956 gnome optional abiword-gnome_2.0.10-1.2_mips.deb
36- 965cc5212d45154a2bf517f0b081282f 352262 editors optional abiword-plugins_2.0.10-1.2_mips.deb
37- 1c1e1380e3b3848745ce9b51f1a29493 33312 gnome optional abiword-plugins-gnome_2.0.10-1.2_mips.deb
38------BEGIN PGP SIGNATURE-----
39-Version: GnuPG v1.2.4 (GNU/Linux)
40-
41-iD8DBQFBYnONOtPfPvLSwCgRAq4aAKCXhvAENBbvt4mAlXGPJoIPik5c9QCeIvbs
42-EYumagv6d7dl8FfcKRuuQWg=
43-=2IzM
44------END PGP SIGNATURE-----
45
46=== removed file 'lib/lp/archiveuploader/tests/data/multiple-stanzas'
47--- lib/lp/archiveuploader/tests/data/multiple-stanzas 2007-05-04 17:48:03 +0000
48+++ lib/lp/archiveuploader/tests/data/multiple-stanzas 1970-01-01 00:00:00 +0000
49@@ -1,60 +0,0 @@
50-Format: 1.7
51-Date: Sun, 29 Aug 2004 03:47:46 +0200
52-Source: abiword
53-Binary: abiword-plugins-gnome abiword-gnome abiword-doc xfonts-abi abiword-help abiword abiword-plugins abiword-common
54-Architecture: mips
55-Version: 2.0.10-1.2
56-Distribution: unstable
57-Urgency: high
58-Maintainer: buildd mips user account <buildd@pepe.buildd.net>
59-Changed-By: Jordi Mallach <jordi@debian.org>
60-Description:
61- abiword - WYSIWYG word processor based on GTK2
62- abiword-common - WYSIWYG word processor based on GTK2
63- abiword-gnome - WYSIWYG word processor based on GTK2/GNOME2
64- abiword-plugins - Plugins for AbiWord
65- abiword-plugins-gnome - Plugins for AbiWord (with GNOME dependency)
66-Closes: 267199
67-Changes:
68- abiword (2.0.10-1.2) unstable; urgency=high
69- .
70- * Non-Maintainer Upload.
71- * debian/patches/01_relibtoolise.dpatch: damn, I missed the *other*
72- configure script. Abiword's source tarball sucks in many ways...
73- (really closes: #267199).
74-Files:
75- 2a0175f42ebcf4c42312ba5837108fc2 1504956 editors optional abiword-common_2.0.10-1.2_mips.deb
76- dc5fe0eeb1b233cf656f46665f150488 2014536 editors optional abiword_2.0.10-1.2_mips.deb
77- b418b9cc47f3d891a6fecb40cd5524db 2012956 gnome optional abiword-gnome_2.0.10-1.2_mips.deb
78- 965cc5212d45154a2bf517f0b081282f 352262 editors optional abiword-plugins_2.0.10-1.2_mips.deb
79- 1c1e1380e3b3848745ce9b51f1a29493 33312 gnome optional abiword-plugins-gnome_2.0.10-1.2_mips.deb
80-
81-Format: 1.7
82-Date: Sun, 29 Aug 2004 03:47:46 +0200
83-Source: abiword
84-Binary: abiword-plugins-gnome abiword-gnome abiword-doc xfonts-abi abiword-help abiword abiword-plugins abiword-common
85-Architecture: mips
86-Version: 2.0.10-1.3
87-Distribution: unstable
88-Urgency: high
89-Maintainer: Daniel Silverstone <dsilvers@debian.org>
90-Changed-By: Jordi Mallach <jordi@debian.org>
91-Description:
92- abiword - WYSIWYG word processor based on GTK2
93- abiword-common - WYSIWYG word processor based on GTK2
94- abiword-gnome - WYSIWYG word processor based on GTK2/GNOME2
95- abiword-plugins - Plugins for AbiWord
96- abiword-plugins-gnome - Plugins for AbiWord (with GNOME dependency)
97-Closes: 267199
98-Changes:
99- abiword (2.0.10-1.3) unstable; urgency=high
100- .
101- * Non-Maintainer Upload.
102- * Ate some cake
103-Files:
104- 2a0175f42ebcf4c42312ba5837108fc2 1504956 editors optional abiword-common_2.0.10-1.2_mips.deb
105- dc5fe0eeb1b233cf656f46665f150488 2014536 editors optional abiword_2.0.10-1.2_mips.deb
106- b418b9cc47f3d891a6fecb40cd5524db 2012956 gnome optional abiword-gnome_2.0.10-1.2_mips.deb
107- 965cc5212d45154a2bf517f0b081282f 352262 editors optional abiword-plugins_2.0.10-1.2_mips.deb
108- 1c1e1380e3b3848745ce9b51f1a29493 33312 gnome optional abiword-plugins-gnome_2.0.10-1.2_mips.deb
109-
110
111=== removed file 'lib/lp/archiveuploader/tests/data/singular-stanza'
112--- lib/lp/archiveuploader/tests/data/singular-stanza 2007-05-04 17:48:03 +0000
113+++ lib/lp/archiveuploader/tests/data/singular-stanza 1970-01-01 00:00:00 +0000
114@@ -1,31 +0,0 @@
115-Format: 1.7
116-Date: Sun, 29 Aug 2004 03:47:46 +0200
117-Source: abiword
118-Binary: abiword-plugins-gnome abiword-gnome abiword-doc xfonts-abi abiword-help abiword abiword-plugins abiword-common
119-Architecture: mips
120-Version: 2.0.10-1.2
121-Distribution: unstable
122-Urgency: high
123-Maintainer: buildd mips user account <buildd@pepe.buildd.net>
124-Changed-By: Jordi Mallach <jordi@debian.org>
125-Description:
126- abiword - WYSIWYG word processor based on GTK2
127- abiword-common - WYSIWYG word processor based on GTK2
128- abiword-gnome - WYSIWYG word processor based on GTK2/GNOME2
129- abiword-plugins - Plugins for AbiWord
130- abiword-plugins-gnome - Plugins for AbiWord (with GNOME dependency)
131-Closes: 267199
132-Changes:
133- abiword (2.0.10-1.2) unstable; urgency=high
134- .
135- * Non-Maintainer Upload.
136- * debian/patches/01_relibtoolise.dpatch: damn, I missed the *other*
137- configure script. Abiword's source tarball sucks in many ways...
138- (really closes: #267199).
139-Files:
140- 2a0175f42ebcf4c42312ba5837108fc2 1504956 editors optional abiword-common_2.0.10-1.2_mips.deb
141- dc5fe0eeb1b233cf656f46665f150488 2014536 editors optional abiword_2.0.10-1.2_mips.deb
142- b418b9cc47f3d891a6fecb40cd5524db 2012956 gnome optional abiword-gnome_2.0.10-1.2_mips.deb
143- 965cc5212d45154a2bf517f0b081282f 352262 editors optional abiword-plugins_2.0.10-1.2_mips.deb
144- 1c1e1380e3b3848745ce9b51f1a29493 33312 gnome optional abiword-plugins-gnome_2.0.10-1.2_mips.deb
145-
146
147=== modified file 'lib/lp/archiveuploader/tests/nascentupload-announcements.txt'
148--- lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2012-01-20 15:42:44 +0000
149+++ lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2012-03-29 11:22:21 +0000
150@@ -4,16 +4,16 @@
151 NascentUpload announces uploads according its final status (NEW,
152 AUTO-APPROVED, UNAPPROVED) and its destination pocket:
153
154- * NEW to RELEASE (via insecure): submitter set (changes signer,
155+ * NEW to RELEASE/PROPOSED (via insecure): submitter set (changes signer,
156 Changed-by and maintainer) receives an 'new' warning message.
157
158 * UNAPPROVED to frozen-RELEASE/UPDATES/BACKPORTS/PROPOSED (via insecure):
159 submitter set receives an 'unapproved' warning (announcement is
160 sent after the upload gets reviewed by archive-admin at queue time).
161
162- * AUTO-APPROVED to RELEASE (via insecure): submitter set receives an
163- 'acceptance' warning and the target distroseries changeslist
164- address receives an 'announcement' message.
165+ * AUTO-APPROVED to RELEASE/PROPOSED (via insecure): submitter set receives
166+ an 'acceptance' warning and the target distroseries changeslist address
167+ receives an 'announcement' message.
168
169 * AUTO-APPROVED to BACKPORTS (via sync): submitter set receives an
170 'acceptance' warning ('announcement' is skipped).
171@@ -255,7 +255,6 @@
172
173 A PPA upload will contain the X-Launchpad-PPA header.
174
175- >>> from lp.registry.interfaces.distribution import IDistributionSet
176 >>> from lp.registry.interfaces.person import IPersonSet
177 >>> from lp.soyuz.enums import ArchivePurpose
178 >>> from lp.soyuz.interfaces.archive import IArchiveSet
179@@ -265,8 +264,7 @@
180 >>> name16_ppa = getUtility(IArchiveSet).new(
181 ... owner=name16, distribution=ubuntu, purpose=ArchivePurpose.PPA)
182
183- >>> ppa_policy = getPolicy(
184- ... name='insecure', distro='ubuntu', distroseries=None)
185+ >>> ppa_policy = getPolicy(name='insecure', distro='ubuntu')
186 >>> ppa_policy.archive = name16_ppa
187 >>> ppa_policy.setDistroSeriesAndPocket('hoary')
188
189@@ -397,8 +395,7 @@
190
191 UNAPPROVED source uploads for 'translations' section via insecure:
192
193- >>> insecure_policy = getPolicy(
194- ... name='insecure', distro='ubuntu', distroseries=None)
195+ >>> insecure_policy = getPolicy(name='insecure', distro='ubuntu')
196 >>> insecure_policy.setDistroSeriesAndPocket('hoary-updates')
197
198 >>> lang_pack = NascentUpload.from_changesfile_path(
199@@ -487,8 +484,7 @@
200
201 AUTO-APPROVED upload to BACKPORTS pocket via 'sync' policy:
202
203- >>> modified_sync_policy = getPolicy(
204- ... name='sync', distro='ubuntu', distroseries=None)
205+ >>> modified_sync_policy = getPolicy(name='sync', distro='ubuntu')
206 >>> modified_sync_policy.setDistroSeriesAndPocket('hoary-backports')
207
208 >>> bar_src = NascentUpload.from_changesfile_path(
209@@ -805,7 +801,7 @@
210
211 We first create a misnamed copy of the changes file.
212
213- >>> import os, shutil
214+ >>> import shutil
215 >>> originalp = datadir('suite/bar_1.0-1/bar_1.0-1_source.changes')
216 >>> copyp = datadir('suite/bar_1.0-1/z-z_0.4.12-2~ppa2.changes')
217 >>> shutil.copyfile(originalp, copyp)
218
219=== modified file 'lib/lp/archiveuploader/tests/uploadpolicy.txt'
220--- lib/lp/archiveuploader/tests/uploadpolicy.txt 2011-12-30 06:14:56 +0000
221+++ lib/lp/archiveuploader/tests/uploadpolicy.txt 2012-03-29 11:22:21 +0000
222@@ -1,4 +1,5 @@
223-== The uploader policies ==
224+The uploader policies
225+---------------------
226
227 When the uploader is invoked, it is given a policy to work in. This governs
228 such things as what tests get run at what stages of the upload, and whether or
229@@ -10,122 +11,139 @@
230 means a call to getUtility(IArchiveUploadPolicy, name) will return the class
231 itself rather than an instance of it.
232
233- >>> from lp.archiveuploader.uploadpolicy import (
234- ... IArchiveUploadPolicy, findPolicyByName)
235- >>> policy_cls = getUtility(IArchiveUploadPolicy, 'insecure')
236- >>> policy_cls
237- <class '...InsecureUploadPolicy'>
238+ >>> from lp.archiveuploader.uploadpolicy import (
239+ ... IArchiveUploadPolicy, findPolicyByName)
240+ >>> policy_cls = getUtility(IArchiveUploadPolicy, 'insecure')
241+ >>> policy_cls
242+ <class '...InsecureUploadPolicy'>
243
244 There's a helper function which returns an instance of the policy with the
245 given name, though, and it's preferred over using getUtility() directly.
246
247- >>> insecure_policy = findPolicyByName('insecure')
248- >>> insecure_policy
249- <lp...InsecureUploadPolicy object...
250+ >>> insecure_policy = findPolicyByName('insecure')
251+ >>> insecure_policy
252+ <lp...InsecureUploadPolicy object...
253
254 Two of the policies defined so far are the insecure and buildd policies.
255
256- >>> insecure_policy.name
257- 'insecure'
258- >>> buildd_policy = findPolicyByName('buildd')
259- >>> buildd_policy.name
260- 'buildd'
261- >>> abstract_policy = findPolicyByName('abstract')
262- Traceback (most recent call last):
263- ...
264- ComponentLookupError:...
265+ >>> insecure_policy.name
266+ 'insecure'
267+ >>> buildd_policy = findPolicyByName('buildd')
268+ >>> buildd_policy.name
269+ 'buildd'
270+ >>> abstract_policy = findPolicyByName('abstract')
271+ Traceback (most recent call last):
272+ ...
273+ ComponentLookupError:...
274
275 There is a bunch of attributes which we expect to have and which can vary
276 from policy to policy.
277
278- >>> insecure_policy.unsigned_changes_ok
279- False
280- >>> buildd_policy.unsigned_changes_ok
281- True
282- >>> insecure_policy.unsigned_dsc_ok
283- False
284- >>> buildd_policy.unsigned_dsc_ok
285- True
286+ >>> insecure_policy.unsigned_changes_ok
287+ False
288+ >>> buildd_policy.unsigned_changes_ok
289+ True
290+ >>> insecure_policy.unsigned_dsc_ok
291+ False
292+ >>> buildd_policy.unsigned_dsc_ok
293+ True
294
295 The policies require certain values to be present in the options at times...
296
297- >>> class MockAbstractOptions:
298- ... distro = 'ubuntu'
299- ... distroseries = None
300- >>> class MockOptions(MockAbstractOptions):
301- ... builds = True
302-
303- >>> ab_opts = MockAbstractOptions()
304- >>> bd_opts = MockOptions()
305-
306- >>> insecure_policy.setOptions(ab_opts)
307- >>> insecure_policy.distro.name
308- u'ubuntu'
309- >>> buildd_policy.setOptions(ab_opts)
310- >>> buildd_policy.setOptions(bd_opts)
311- >>> buildd_policy.distro.name
312- u'ubuntu'
313+ >>> class MockAbstractOptions:
314+ ... distro = 'ubuntu'
315+ ... distroseries = None
316+ >>> class MockOptions(MockAbstractOptions):
317+ ... builds = True
318+
319+ >>> ab_opts = MockAbstractOptions()
320+ >>> bd_opts = MockOptions()
321+
322+ >>> insecure_policy.setOptions(ab_opts)
323+ >>> insecure_policy.distro.name
324+ u'ubuntu'
325+ >>> buildd_policy.setOptions(ab_opts)
326+ >>> buildd_policy.setOptions(bd_opts)
327+ >>> buildd_policy.distro.name
328+ u'ubuntu'
329
330 Policies can think about distroseriess...
331
332- >>> buildd_policy.setDistroSeriesAndPocket("hoary")
333- >>> print buildd_policy.distroseries.name
334- hoary
335+ >>> buildd_policy.setDistroSeriesAndPocket("hoary")
336+ >>> print buildd_policy.distroseries.name
337+ hoary
338
339 Policies can make decisions based on whether or not they want to
340 approve an upload automatically (I.E. move it straight to ACCEPTED
341 instead of UNAPPROVED)
342
343- >>> from lp.registry.interfaces.distribution import IDistributionSet
344- >>> from lp.registry.interfaces.series import SeriesStatus
345- >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
346- >>> hoary = ubuntu['hoary']
347-
348- >>> class FakeUpload:
349- ... def __init__(self, ppa=False):
350- ... self.is_ppa = ppa
351-
352- >>> print hoary.status.name
353- DEVELOPMENT
354+ >>> from lp.registry.interfaces.distribution import IDistributionSet
355+ >>> from lp.registry.interfaces.series import SeriesStatus
356+ >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
357+ >>> hoary = ubuntu['hoary']
358+
359+ >>> class FakeUpload:
360+ ... def __init__(self, ppa=False):
361+ ... self.is_ppa = ppa
362+
363+ >>> print hoary.status.name
364+ DEVELOPMENT
365
366 Uploads to the RELEASE pocket of not FROZEN distroseries are approved
367 by the insecure policy:
368
369- >>> insecure_policy.setDistroSeriesAndPocket('hoary')
370- >>> insecure_policy.autoApprove(FakeUpload())
371- True
372-
373- >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
374- True
375+ >>> insecure_policy.setDistroSeriesAndPocket('hoary')
376+ >>> insecure_policy.autoApprove(FakeUpload())
377+ True
378+
379+ >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
380+ True
381+
382+So are uploads to the PROPOSED pocket:
383+
384+ >>> insecure_policy.setDistroSeriesAndPocket('hoary-proposed')
385+ >>> insecure_policy.autoApprove(FakeUpload())
386+ True
387
388 When the distroseries is FROZEN the uploads should wait in UNAPPROVED queue:
389
390- >>> login('foo.bar@canonical.com')
391- >>> hoary.status = SeriesStatus.FROZEN
392- >>> from lp.services.database.sqlbase import flush_database_updates
393- >>> flush_database_updates()
394+ >>> login('foo.bar@canonical.com')
395+ >>> hoary.status = SeriesStatus.FROZEN
396+ >>> from lp.services.database.sqlbase import flush_database_updates
397+ >>> flush_database_updates()
398
399- >>> insecure_policy.autoApprove(FakeUpload())
400- False
401+ >>> insecure_policy.autoApprove(FakeUpload())
402+ False
403
404 PPA uploads continue to be auto-approved:
405
406- >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
407- True
408+ >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
409+ True
410
411 Reset the policy so that we can try again...
412
413- >>> insecure_policy.policy = None
414- >>> insecure_policy.distroseries = None
415+ >>> insecure_policy.policy = None
416+ >>> insecure_policy.distroseries = None
417
418 Uploads to the UPDATES pocket are not auto-approved by the insecure policy
419
420- >>> insecure_policy.setDistroSeriesAndPocket('hoary-updates')
421- >>> insecure_policy.autoApprove(FakeUpload())
422- False
423+ >>> insecure_policy.setDistroSeriesAndPocket('hoary-updates')
424+ >>> insecure_policy.autoApprove(FakeUpload())
425+ False
426
427 Despite of not being allowed yet (see UploadPolicy.checkUpload) PPA
428 uploads to post-release pockets would also be auto-approved:
429
430- >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
431- True
432+ >>> insecure_policy.autoApprove(FakeUpload(ppa=True))
433+ True
434+
435+Uploads to the PROPOSED pocket are also not auto-approved by the insecure
436+policy, either before or after release:
437+
438+ >>> insecure_policy.setDistroSeriesAndPocket('hoary-proposed')
439+ >>> insecure_policy.autoApprove(FakeUpload())
440+ False
441+ >>> hoary.status = SeriesStatus.CURRENT
442+ >>> flush_database_updates()
443+ >>> insecure_policy.autoApprove(FakeUpload())
444+ False
445
446=== modified file 'lib/lp/archiveuploader/uploadpolicy.py'
447--- lib/lp/archiveuploader/uploadpolicy.py 2011-06-01 05:45:53 +0000
448+++ lib/lp/archiveuploader/uploadpolicy.py 2012-03-29 11:22:21 +0000
449@@ -1,4 +1,4 @@
450-# Copyright 2009 Canonical Ltd. This software is licensed under the
451+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
452 # GNU Affero General Public License version 3 (see the file LICENSE).
453
454 """Policy management for the upload handler."""
455@@ -29,7 +29,6 @@
456 Interface,
457 )
458
459-from lp.app.interfaces.launchpad import ILaunchpadCelebrities
460 from lp.registry.interfaces.distribution import IDistributionSet
461 from lp.registry.interfaces.pocket import PackagePublishingPocket
462 from lp.registry.interfaces.series import SeriesStatus
463@@ -76,7 +75,7 @@
464
465 name = 'abstract'
466 options = None
467- accepted_type = None # Must be defined in subclasses.
468+ accepted_type = None # Must be defined in subclasses.
469
470 def __init__(self):
471 """Prepare a policy..."""
472@@ -259,19 +258,26 @@
473 "This upload queue does not permit SECURITY uploads.")
474
475 def autoApprove(self, upload):
476- """The insecure policy only auto-approves RELEASE pocket stuff.
477+ """The insecure policy auto-approves RELEASE/PROPOSED pocket stuff.
478
479 PPA uploads are always auto-approved.
480- Other uploads (to main archives) are only auto-approved if the
481- distroseries is not FROZEN (note that we already performed the
482- IDistroSeries.canUploadToPocket check in the checkUpload base method).
483+ RELEASE and PROPOSED pocket uploads (to main archives) are only
484+ auto-approved if the distroseries is in a non-FROZEN state
485+ pre-release. (We already performed the
486+ IDistroSeries.canUploadToPocket check in the checkUpload base
487+ method, which will deny RELEASE uploads post-release, but it doesn't
488+ hurt to repeat this for that case.)
489 """
490 if upload.is_ppa:
491 return True
492
493- if self.pocket == PackagePublishingPocket.RELEASE:
494- if (self.distroseries.status !=
495- SeriesStatus.FROZEN):
496+ auto_approve_pockets = (
497+ PackagePublishingPocket.RELEASE,
498+ PackagePublishingPocket.PROPOSED,
499+ )
500+ if self.pocket in auto_approve_pockets:
501+ if (self.distroseries.isUnstable() and
502+ self.distroseries.status != SeriesStatus.FROZEN):
503 return True
504 return False
505
506
507=== modified file 'lib/lp/registry/doc/distroseries.txt'
508--- lib/lp/registry/doc/distroseries.txt 2012-02-21 22:46:28 +0000
509+++ lib/lp/registry/doc/distroseries.txt 2012-03-29 11:22:21 +0000
510@@ -169,7 +169,6 @@
511 canUploadToPocket method helps us to decide if an upload is allowed or
512 not, according to the distroseries status and the upload target pocket.
513
514- >>> from lp.registry.interfaces.distribution import IDistributionSet
515 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
516 >>> breezy_autotest = ubuntu['breezy-autotest']
517 >>> hoary = ubuntu['hoary']
518@@ -204,6 +203,16 @@
519 >>> hoary.canUploadToPocket(PackagePublishingPocket.SECURITY)
520 True
521
522+The PROPOSED pocket is also special. Pre-release, it may be used for
523+staging uploads on their way into the RELEASE pocket; post-release, it may
524+be used for staging uploads on their way into the UPDATES pocket.
525+
526+ >>> warty.canUploadToPocket(PackagePublishingPocket.PROPOSED)
527+ True
528+ >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.PROPOSED)
529+ True
530+ >>> hoary.canUploadToPocket(PackagePublishingPocket.PROPOSED)
531+ True
532
533 Package searching
534 -----------------
535
536=== modified file 'lib/lp/registry/model/distroseries.py'
537--- lib/lp/registry/model/distroseries.py 2012-02-14 23:50:16 +0000
538+++ lib/lp/registry/model/distroseries.py 2012-03-29 11:22:21 +0000
539@@ -724,8 +724,12 @@
540 self.status in stable_states):
541 return False
542
543- # Deny uploads for post-release pockets in unstable states.
544- if (pocket != PackagePublishingPocket.RELEASE and
545+ # Deny uploads for post-release-only pockets in unstable states.
546+ pre_release_pockets = (
547+ PackagePublishingPocket.RELEASE,
548+ PackagePublishingPocket.PROPOSED,
549+ )
550+ if (pocket not in pre_release_pockets and
551 self.status not in stable_states):
552 return False
553
554
555=== modified file 'lib/lp/soyuz/adapters/copypolicy.py'
556--- lib/lp/soyuz/adapters/copypolicy.py 2011-06-10 11:17:39 +0000
557+++ lib/lp/soyuz/adapters/copypolicy.py 2012-03-29 11:22:21 +0000
558@@ -1,4 +1,4 @@
559-# Copyright 2011 Canonical Ltd. This software is licensed under the
560+# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
561 # GNU Affero General Public License version 3 (see the file LICENSE).
562
563 """Copy Policy Classes.
564@@ -42,12 +42,17 @@
565 if archive.is_ppa:
566 return True
567
568- # If the pocket is RELEASE and we're not frozen then you can
569- # upload to it. Any other states mean the upload is unapproved.
570+ # If the pocket is RELEASE or PROPOSED and we're not frozen then you
571+ # can upload to it. Any other states mean the upload is unapproved.
572 #
573 # This check is orthogonal to the
574 # IDistroSeries.canUploadToPocket check.
575- if (pocket == PackagePublishingPocket.RELEASE and
576+ auto_approve_pockets = (
577+ PackagePublishingPocket.RELEASE,
578+ PackagePublishingPocket.PROPOSED,
579+ )
580+ if (pocket in auto_approve_pockets and
581+ distroseries.isUnstable() and
582 distroseries.status != SeriesStatus.FROZEN):
583 return True
584
585@@ -63,7 +68,7 @@
586 def send_email(self, archive):
587 if archive.is_ppa:
588 return False
589-
590+
591 return True
592
593
594
595=== modified file 'lib/lp/soyuz/adapters/tests/test_copypolicy.py'
596--- lib/lp/soyuz/adapters/tests/test_copypolicy.py 2012-01-01 02:58:52 +0000
597+++ lib/lp/soyuz/adapters/tests/test_copypolicy.py 2012-03-29 11:22:21 +0000
598@@ -1,4 +1,4 @@
599-# Copyright 2011 Canonical Ltd. This software is licensed under the
600+# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
601 # GNU Affero General Public License version 3 (see the file LICENSE).
602
603 from lp.registry.interfaces.pocket import PackagePublishingPocket
604@@ -21,23 +21,26 @@
605
606 layer = ZopelessDatabaseLayer
607
608- def _getUploadCriteria(self, archive_purpose):
609+ def _getUploadCriteria(self, archive_purpose, status=None, pocket=None):
610 archive = self.factory.makeArchive(purpose=archive_purpose)
611 distroseries = self.factory.makeDistroSeries()
612- pocket = self.factory.getAnyPocket()
613+ if status is not None:
614+ distroseries.status = status
615+ if pocket is None:
616+ pocket = self.factory.getAnyPocket()
617 return archive, distroseries, pocket
618
619- def assertApproved(self, archive_purpose, method):
620+ def assertApproved(self, archive_purpose, method,
621+ status=None, pocket=None):
622 archive, distroseries, pocket = self._getUploadCriteria(
623- archive_purpose)
624- approved = method(archive, distroseries, pocket)
625- self.assertTrue(approved)
626+ archive_purpose, status=status, pocket=pocket)
627+ self.assertTrue(method(archive, distroseries, pocket))
628
629- def assertUnapproved(self, archive_purpose, method):
630+ def assertUnapproved(self, archive_purpose, method,
631+ status=None, pocket=None):
632 archive, distroseries, pocket = self._getUploadCriteria(
633- archive_purpose)
634- approved = method(archive, distroseries, pocket)
635- self.assertFalse(approved)
636+ archive_purpose, status=status, pocket=pocket)
637+ self.assertFalse(method(archive, distroseries, pocket))
638
639 def test_insecure_holds_new_distro_package(self):
640 cp = InsecureCopyPolicy()
641@@ -48,30 +51,41 @@
642 self.assertApproved(ArchivePurpose.PPA, cp.autoApproveNew)
643
644 def test_insecure_approves_known_distro_package_to_unfrozen_release(self):
645- archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
646- distroseries = self.factory.makeDistroSeries()
647- pocket = PackagePublishingPocket.RELEASE
648 cp = InsecureCopyPolicy()
649- approve = cp.autoApprove(archive, distroseries, pocket)
650- self.assertTrue(approve)
651+ self.assertApproved(
652+ ArchivePurpose.PRIMARY, cp.autoApprove,
653+ pocket=PackagePublishingPocket.RELEASE)
654
655 def test_insecure_holds_copy_to_updates_pocket_in_frozen_series(self):
656- archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
657- distroseries = self.factory.makeDistroSeries()
658- distroseries.status = SeriesStatus.FROZEN
659- pocket = PackagePublishingPocket.UPDATES
660 cp = InsecureCopyPolicy()
661- approve = cp.autoApprove(archive, distroseries, pocket)
662- self.assertFalse(approve)
663+ self.assertUnapproved(
664+ ArchivePurpose.PRIMARY, cp.autoApprove, status=SeriesStatus.FROZEN,
665+ pocket=PackagePublishingPocket.UPDATES)
666
667 def test_insecure_holds_copy_to_release_pocket_in_frozen_series(self):
668- archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
669- distroseries = self.factory.makeDistroSeries()
670- pocket = PackagePublishingPocket.RELEASE
671- distroseries.status = SeriesStatus.FROZEN
672- cp = InsecureCopyPolicy()
673- approve = cp.autoApprove(archive, distroseries, pocket)
674- self.assertFalse(approve)
675+ cp = InsecureCopyPolicy()
676+ self.assertUnapproved(
677+ ArchivePurpose.PRIMARY, cp.autoApprove, status=SeriesStatus.FROZEN,
678+ pocket=PackagePublishingPocket.RELEASE)
679+
680+ def test_insecure_approves_copy_to_proposed_in_unfrozen_series(self):
681+ cp = InsecureCopyPolicy()
682+ self.assertApproved(
683+ ArchivePurpose.PRIMARY, cp.autoApprove,
684+ pocket=PackagePublishingPocket.PROPOSED)
685+
686+ def test_insecure_holds_copy_to_proposed_in_frozen_series(self):
687+ cp = InsecureCopyPolicy()
688+ self.assertUnapproved(
689+ ArchivePurpose.PRIMARY, cp.autoApprove, status=SeriesStatus.FROZEN,
690+ pocket=PackagePublishingPocket.PROPOSED)
691+
692+ def test_insecure_holds_copy_to_proposed_in_current_series(self):
693+ cp = InsecureCopyPolicy()
694+ self.assertUnapproved(
695+ ArchivePurpose.PRIMARY, cp.autoApprove,
696+ status=SeriesStatus.CURRENT,
697+ pocket=PackagePublishingPocket.PROPOSED)
698
699 def test_insecure_approves_existing_ppa_package(self):
700 cp = InsecureCopyPolicy()
701
702=== modified file 'lib/lp/soyuz/tests/test_archive.py'
703--- lib/lp/soyuz/tests/test_archive.py 2012-02-28 11:14:44 +0000
704+++ lib/lp/soyuz/tests/test_archive.py 2012-03-29 11:22:21 +0000
705@@ -128,8 +128,7 @@
706 archives, sourcepackagename = self.makeArchivesWithPublications()
707 results = self.getPublications(
708 sourcepackagename, archives, archives[0].distribution)
709- num_results = results.count()
710- self.assertEquals(3, num_results)
711+ self.assertEqual(3, results.count())
712
713 def test_getPublications_empty_list_of_archives(self):
714 # Passing an empty list of archives will result in an empty
715@@ -137,12 +136,12 @@
716 archives, sourcepackagename = self.makeArchivesWithPublications()
717 results = self.getPublications(
718 sourcepackagename, [], archives[0].distribution)
719- self.assertEquals([], list(results))
720+ self.assertEqual([], list(results))
721
722 def assertPublicationsFromArchives(self, publications, archives):
723- self.assertEquals(len(archives), publications.count())
724+ self.assertEqual(len(archives), publications.count())
725 for publication, archive in zip(publications, archives):
726- self.assertEquals(archive, publication.archive)
727+ self.assertEqual(archive, publication.archive)
728
729 def test_getPublications_returns_only_for_given_archives(self):
730 # Returns only publications for the specified archives
731@@ -160,7 +159,7 @@
732 status=PackagePublishingStatus.PENDING)
733 results = self.getPublications(
734 sourcepackagename, [archive], archive.distribution)
735- self.assertEquals([], list(results))
736+ self.assertEqual([], list(results))
737
738 def publishSourceInNewArchive(self, sourcepackagename):
739 distribution = self.factory.makeDistribution()
740@@ -192,12 +191,12 @@
741 def test_empty_ppa_has_zero_binaries_size(self):
742 # An empty PPA has no binaries so has zero binaries_size.
743 ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
744- self.assertEquals(0, ppa.binaries_size)
745+ self.assertEqual(0, ppa.binaries_size)
746
747 def test_sources_size_on_empty_archive(self):
748 # Zero is returned for an archive without sources.
749 archive = self.factory.makeArchive()
750- self.assertEquals(0, archive.sources_size)
751+ self.assertEqual(0, archive.sources_size)
752
753 def publishSourceFile(self, archive, library_file):
754 """Publish a source package with the given content to the archive.
755@@ -220,12 +219,10 @@
756 archive = self.factory.makeArchive()
757 library_file = self.factory.makeLibraryFileAlias()
758 self.publishSourceFile(archive, library_file)
759- self.assertEquals(
760- library_file.content.filesize, archive.sources_size)
761+ self.assertEqual(library_file.content.filesize, archive.sources_size)
762
763 self.publishSourceFile(archive, library_file)
764- self.assertEquals(
765- library_file.content.filesize, archive.sources_size)
766+ self.assertEqual(library_file.content.filesize, archive.sources_size)
767
768
769 class TestSeriesWithSources(TestCaseWithFactory):
770@@ -326,23 +323,23 @@
771 distribution=distribution, purpose=ArchivePurpose.PRIMARY)
772 debug = self.factory.makeArchive(
773 distribution=distribution, purpose=ArchivePurpose.DEBUG)
774- self.assertEquals(primary.debug_archive, debug)
775+ self.assertEqual(primary.debug_archive, debug)
776
777 def testPartnerDebugArchiveIsSelf(self):
778 partner = self.factory.makeArchive(purpose=ArchivePurpose.PARTNER)
779- self.assertEquals(partner.debug_archive, partner)
780+ self.assertEqual(partner.debug_archive, partner)
781
782 def testCopyDebugArchiveIsSelf(self):
783 copy = self.factory.makeArchive(purpose=ArchivePurpose.COPY)
784- self.assertEquals(copy.debug_archive, copy)
785+ self.assertEqual(copy.debug_archive, copy)
786
787 def testDebugDebugArchiveIsSelf(self):
788 debug = self.factory.makeArchive(purpose=ArchivePurpose.DEBUG)
789- self.assertEquals(debug.debug_archive, debug)
790+ self.assertEqual(debug.debug_archive, debug)
791
792 def testPPADebugArchiveIsSelf(self):
793 ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
794- self.assertEquals(ppa.debug_archive, ppa)
795+ self.assertEqual(ppa.debug_archive, ppa)
796
797 def testMissingPrimaryDebugArchiveIsNone(self):
798 primary = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
799@@ -419,8 +416,7 @@
800 # Disabling an already disabled Archive should raise an
801 # AssertionError.
802 archive = self.factory.makeArchive(enabled=False)
803- self.assertRaises(
804- AssertionError, removeSecurityProxy(archive).disable)
805+ self.assertRaises(AssertionError, removeSecurityProxy(archive).disable)
806
807
808 class TestCollectLatestPublishedSources(TestCaseWithFactory):
809@@ -497,10 +493,9 @@
810 # Uploading to a PPA should be allowed for a user that is the owner
811 owner = self.factory.makePerson(name="somebody")
812 archive = self.factory.makeArchive(owner=owner)
813- self.assertEquals(True, archive.checkArchivePermission(owner))
814+ self.assertTrue(archive.checkArchivePermission(owner))
815 someone_unrelated = self.factory.makePerson(name="somebody-unrelated")
816- self.assertEquals(False,
817- archive.checkArchivePermission(someone_unrelated))
818+ self.assertFalse(archive.checkArchivePermission(someone_unrelated))
819
820 def test_checkArchivePermission_distro_archive(self):
821 # Regular users can not upload to ubuntu
822@@ -511,13 +506,12 @@
823 main = getUtility(IComponentSet)["main"]
824 # A regular user doesn't have access
825 somebody = self.factory.makePerson()
826- self.assertEquals(False,
827- archive.checkArchivePermission(somebody, main))
828+ self.assertFalse(archive.checkArchivePermission(somebody, main))
829 # An ubuntu core developer does have access
830 coredev = self.factory.makePerson()
831 with person_logged_in(archive.distribution.owner):
832 archive.newComponentUploader(coredev, main.name)
833- self.assertEquals(True, archive.checkArchivePermission(coredev, main))
834+ self.assertTrue(archive.checkArchivePermission(coredev, main))
835
836 def test_checkArchivePermission_ppa(self):
837 owner = self.factory.makePerson()
838@@ -525,13 +519,11 @@
839 owner=owner)
840 somebody = self.factory.makePerson()
841 # The owner has access
842- self.assertEquals(True, archive.checkArchivePermission(owner))
843+ self.assertTrue(archive.checkArchivePermission(owner))
844 # Somebody unrelated does not
845- self.assertEquals(False, archive.checkArchivePermission(somebody))
846+ self.assertFalse(archive.checkArchivePermission(somebody))
847
848- def makeArchiveAndActiveDistroSeries(self, purpose=None):
849- if purpose is None:
850- purpose = ArchivePurpose.PRIMARY
851+ def makeArchiveAndActiveDistroSeries(self, purpose=ArchivePurpose.PRIMARY):
852 archive = self.factory.makeArchive(purpose=purpose)
853 distroseries = self.factory.makeDistroSeries(
854 distribution=archive.distribution,
855@@ -562,8 +554,7 @@
856 distroseries=None, component=None,
857 pocket=None, strict_component=False):
858 """Assert an upload to 'archive' will be accepted."""
859- self.assertIs(
860- None,
861+ self.assertIsNone(
862 self.checkUpload(
863 archive, person, sourcepackagename,
864 distroseries=distroseries, component=component,
865@@ -610,6 +601,20 @@
866 self.assertCannotUpload(
867 CannotUploadToPocket, archive,
868 self.factory.makePerson(), self.factory.makeSourcePackageName(),
869+ pocket=PackagePublishingPocket.UPDATES,
870+ distroseries=distroseries)
871+
872+ def test_checkUpload_primary_proposed_development(self):
873+ # It should be possible to upload to the PROPOSED pocket while the
874+ # distroseries is in the DEVELOPMENT status.
875+ archive, distroseries = self.makeArchiveAndActiveDistroSeries(
876+ purpose=ArchivePurpose.PRIMARY)
877+ sourcepackagename = self.factory.makeSourcePackageName()
878+ person = self.factory.makePerson()
879+ removeSecurityProxy(archive).newPackageUploader(
880+ person, sourcepackagename)
881+ self.assertCanUpload(
882+ archive, person, sourcepackagename,
883 pocket=PackagePublishingPocket.PROPOSED,
884 distroseries=distroseries)
885
886@@ -665,8 +670,7 @@
887 spn = self.factory.makeSourcePackageName()
888 distroseries = self.factory.makeDistroSeries(
889 status=SeriesStatus.CURRENT)
890- self.assertCanUpload(
891- archive, person, spn, distroseries=distroseries)
892+ self.assertCanUpload(archive, person, spn, distroseries=distroseries)
893
894 def test_checkUpload_copy_archive_no_permission(self):
895 archive, distroseries = self.makeArchiveAndActiveDistroSeries(
896@@ -688,8 +692,7 @@
897 distroseries = self.factory.makeDistroSeries(
898 distribution=archive.distribution,
899 status=SeriesStatus.CURRENT)
900- self.assertIs(
901- None,
902+ self.assertIsNone(
903 archive.checkUploadToPocket(
904 distroseries, PackagePublishingPocket.RELEASE))
905
906@@ -812,8 +815,7 @@
907 purpose=ArchivePurpose.PPA, owner=person)
908 suitesourcepackage = self.factory.makeSuiteSourcePackage(
909 pocket=PackagePublishingPocket.PROPOSED)
910- self.assertEqual(
911- False,
912+ self.assertFalse(
913 archive.canUploadSuiteSourcePackage(person, suitesourcepackage))
914
915 def test_canUploadSuiteSourcePackage_no_permission(self):
916@@ -823,8 +825,7 @@
917 suitesourcepackage = self.factory.makeSuiteSourcePackage(
918 pocket=PackagePublishingPocket.RELEASE)
919 person = self.factory.makePerson()
920- self.assertEqual(
921- False,
922+ self.assertFalse(
923 archive.canUploadSuiteSourcePackage(person, suitesourcepackage))
924
925 def test_canUploadSuiteSourcePackage_package_permission(self):
926@@ -835,8 +836,7 @@
927 person = self.factory.makePerson()
928 removeSecurityProxy(archive).newPackageUploader(
929 person, suitesourcepackage.sourcepackagename)
930- self.assertEqual(
931- True,
932+ self.assertTrue(
933 archive.canUploadSuiteSourcePackage(person, suitesourcepackage))
934
935 def test_canUploadSuiteSourcePackage_component_permission(self):
936@@ -846,8 +846,7 @@
937 suitesourcepackage = self.makePackageToUpload(distroseries)
938 person = self.factory.makePerson()
939 removeSecurityProxy(archive).newComponentUploader(person, "universe")
940- self.assertEqual(
941- True,
942+ self.assertTrue(
943 archive.canUploadSuiteSourcePackage(person, suitesourcepackage))
944
945 def test_canUploadSuiteSourcePackage_strict_component(self):
946@@ -867,8 +866,7 @@
947 # This time the user can't upload as there has been a
948 # publication and they don't have permission for the component
949 # the package is published in.
950- self.assertEqual(
951- False,
952+ self.assertFalse(
953 archive.canUploadSuiteSourcePackage(person, suitesourcepackage))
954
955 def test_hasAnyPermission(self):
956@@ -922,7 +920,7 @@
957 # country will create a new BinaryPackageReleaseDownloadCount
958 # entry.
959 day = date(2010, 2, 20)
960- self.assertIs(None, self.store.find(
961+ self.assertIsNone(self.store.find(
962 BinaryPackageReleaseDownloadCount,
963 archive=self.archive, binary_package_release=self.bpr_1,
964 day=day, country=self.australia).one())
965@@ -1035,7 +1033,7 @@
966
967 def test_default(self):
968 """By default, ARM builds are not allowed as ARM is restricted."""
969- self.assertEquals(0,
970+ self.assertEqual(0,
971 self.archive_arch_set.getByArchive(
972 self.archive, self.arm).count())
973 self.assertContentEqual([], self.archive.enabled_restricted_families)
974@@ -1045,7 +1043,7 @@
975 enable enabled_restricted_families for arm for that archive."""
976 self.assertContentEqual([], self.archive.enabled_restricted_families)
977 self.archive_arch_set.new(self.archive, self.arm)
978- self.assertEquals([self.arm],
979+ self.assertEqual([self.arm],
980 list(self.archive.enabled_restricted_families))
981
982 def test_get_returns_restricted_only(self):
983@@ -1062,13 +1060,12 @@
984 self.archive.enabled_restricted_families = [self.arm]
985 allowed_restricted_families = self.archive_arch_set.getByArchive(
986 self.archive, self.arm)
987- self.assertEquals(1, allowed_restricted_families.count())
988- self.assertEquals(self.arm,
989- allowed_restricted_families[0].processorfamily)
990- self.assertEquals(
991- [self.arm], self.archive.enabled_restricted_families)
992+ self.assertEqual(1, allowed_restricted_families.count())
993+ self.assertEqual(
994+ self.arm, allowed_restricted_families[0].processorfamily)
995+ self.assertEqual([self.arm], self.archive.enabled_restricted_families)
996 self.archive.enabled_restricted_families = []
997- self.assertEquals(0,
998+ self.assertEqual(0,
999 self.archive_arch_set.getByArchive(
1000 self.archive, self.arm).count())
1001 self.assertContentEqual([], self.archive.enabled_restricted_families)
1002@@ -1152,8 +1149,7 @@
1003
1004 def test_returns_none_for_nonexistent_binary(self):
1005 # Non-existent files return None.
1006- self.assertIs(
1007- None,
1008+ self.assertIsNone(
1009 self.archive.getBinaryPackageRelease(
1010 self.bpns['cdrkit'], '1.2.3-4', 'i386'))
1011
1012@@ -1168,15 +1164,13 @@
1013 status=PackagePublishingStatus.PUBLISHED,
1014 architecturespecific=True)
1015
1016- self.assertIs(
1017- None,
1018+ self.assertIsNone(
1019 self.archive.getBinaryPackageRelease(
1020 self.bpns['foo-bin'], '1.2.3-4', 'i386'))
1021
1022 def test_returns_none_from_another_archive(self):
1023 # Cross-archive searches are not performed.
1024- self.assertIs(
1025- None,
1026+ self.assertIsNone(
1027 self.factory.makeArchive().getBinaryPackageRelease(
1028 self.bpns['foo-bin'], '1.2.3-4', 'i386'))
1029
1030@@ -1229,15 +1223,13 @@
1031
1032 def test_returns_none_for_source_file(self):
1033 # None is returned if the file is a source component instead.
1034- self.assertIs(
1035- None,
1036+ self.assertIsNone(
1037 self.archive.getBinaryPackageReleaseByFileName(
1038 "foo_1.2.3-4.dsc"))
1039
1040 def test_returns_none_for_nonexistent_file(self):
1041 # Non-existent files return None.
1042- self.assertIs(
1043- None,
1044+ self.assertIsNone(
1045 self.archive.getBinaryPackageReleaseByFileName(
1046 "this-is-not-real_1.2.3-4_all.deb"))
1047
1048@@ -1252,15 +1244,14 @@
1049 status=PackagePublishingStatus.PUBLISHED,
1050 architecturespecific=True)
1051
1052- self.assertEquals(
1053+ self.assertEqual(
1054 new_pubs[0].binarypackagerelease,
1055 self.archive.getBinaryPackageReleaseByFileName(
1056 "foo-bin_1.2.3-4_i386.deb"))
1057
1058 def test_returns_none_from_another_archive(self):
1059 # Cross-archive searches are not performed.
1060- self.assertIs(
1061- None,
1062+ self.assertIsNone(
1063 self.factory.makeArchive().getBinaryPackageReleaseByFileName(
1064 "foo-bin_1.2.3-4_i386.deb"))
1065
1066@@ -1282,13 +1273,13 @@
1067 def test_delete(self):
1068 # Sanity check for the unit-test.
1069 self.archive.delete(deleted_by=self.archive.owner)
1070- self.failUnlessEqual(ArchiveStatus.DELETING, self.archive.status)
1071+ self.assertEqual(ArchiveStatus.DELETING, self.archive.status)
1072
1073 def test_delete_when_disabled(self):
1074 # A disabled archive can also be deleted (bug 574246).
1075 self.archive.disable()
1076 self.archive.delete(deleted_by=self.archive.owner)
1077- self.failUnlessEqual(ArchiveStatus.DELETING, self.archive.status)
1078+ self.assertEqual(ArchiveStatus.DELETING, self.archive.status)
1079
1080
1081 class TestCommercialArchive(TestCaseWithFactory):
1082@@ -1311,8 +1302,7 @@
1083 self.assertFalse(self.archive.commercial)
1084
1085 # The archive owner can't change the value.
1086- self.assertRaises(
1087- Unauthorized, self.setCommercial, self.archive, True)
1088+ self.assertRaises(Unauthorized, self.setCommercial, self.archive, True)
1089
1090 # Commercial admins can change it.
1091 login(COMMERCIAL_ADMIN_EMAIL)
1092@@ -1384,8 +1374,7 @@
1093 with person_logged_in(archive.owner):
1094 archive_dependency = archive.addArchiveDependency(dependency,
1095 PackagePublishingPocket.RELEASE)
1096- self.assertContentEqual(
1097- archive.dependencies, [archive_dependency])
1098+ self.assertContentEqual(archive.dependencies, [archive_dependency])
1099
1100
1101 class TestArchiveDependencies(TestCaseWithFactory):
1102@@ -1443,12 +1432,11 @@
1103 if archive is None:
1104 archive = self.archive
1105
1106- self.assertEquals(
1107- list(
1108- archive.findDepCandidates(
1109- self.publisher.distroseries[arch_tag], pocket, component,
1110- source_package_name, name)),
1111- expected)
1112+ self.assertEqual(
1113+ expected,
1114+ list(archive.findDepCandidates(
1115+ self.publisher.distroseries[arch_tag], pocket, component,
1116+ source_package_name, name)))
1117
1118 def test_finds_candidate_in_same_archive(self):
1119 # A published candidate in the same archive should be found.
1120@@ -1466,7 +1454,7 @@
1121
1122 def test_ppa_searches_primary_archive(self):
1123 # PPA searches implicitly look in the primary archive too.
1124- self.assertEquals(self.archive.purpose, ArchivePurpose.PPA)
1125+ self.assertEqual(self.archive.purpose, ArchivePurpose.PPA)
1126 self.assertDep('i386', 'foo', [])
1127
1128 bins = self.publisher.getPubBinaries(
1129@@ -1690,15 +1678,13 @@
1130 with celebrity_logged_in('admin'):
1131 comm = getUtility(ILaunchpadCelebrities).commercial_admin
1132 comm.addMember(ppa_owner, comm.teamowner)
1133- self.assertIs(
1134- None,
1135+ self.assertIsNone(
1136 Archive.validatePPA(ppa_owner, self.factory.getUniqueString(),
1137 private=True))
1138
1139 def test_private_ppa_admin(self):
1140 ppa_owner = self.factory.makeAdministrator()
1141- self.assertIs(
1142- None,
1143+ self.assertIsNone(
1144 Archive.validatePPA(ppa_owner, self.factory.getUniqueString(),
1145 private=True))
1146
1147@@ -1716,7 +1702,7 @@
1148
1149 def test_valid_ppa(self):
1150 ppa_owner = self.factory.makePerson()
1151- self.assertEqual(None, Archive.validatePPA(ppa_owner, None))
1152+ self.assertIsNone(Archive.validatePPA(ppa_owner, None))
1153
1154
1155 class TestGetComponentsForSeries(TestCaseWithFactory):
1156@@ -1733,14 +1719,13 @@
1157 def test_series_components_for_primary_archive(self):
1158 # The primary archive uses the series' defined components.
1159 archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
1160- self.assertEquals(
1161- 0, len(archive.getComponentsForSeries(self.series)))
1162+ self.assertEqual(0, len(archive.getComponentsForSeries(self.series)))
1163
1164 ComponentSelection(distroseries=self.series, component=self.comp1)
1165 ComponentSelection(distroseries=self.series, component=self.comp2)
1166 clear_property_cache(self.series)
1167
1168- self.assertEquals(
1169+ self.assertEqual(
1170 set((self.comp1, self.comp2)),
1171 set(archive.getComponentsForSeries(self.series)))
1172
1173@@ -1749,7 +1734,7 @@
1174 archive = self.factory.makeArchive(purpose=ArchivePurpose.PARTNER)
1175 ComponentSelection(distroseries=self.series, component=self.comp1)
1176 partner_comp = getUtility(IComponentSet)['partner']
1177- self.assertEquals(
1178+ self.assertEqual(
1179 [partner_comp],
1180 list(archive.getComponentsForSeries(self.series)))
1181
1182@@ -1758,7 +1743,7 @@
1183 archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
1184 ComponentSelection(distroseries=self.series, component=self.comp1)
1185 main_comp = getUtility(IComponentSet)['main']
1186- self.assertEquals(
1187+ self.assertEqual(
1188 [main_comp], list(archive.getComponentsForSeries(self.series)))
1189
1190
1191@@ -1769,16 +1754,16 @@
1192
1193 def test_default_component_for_other_archives(self):
1194 archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
1195- self.assertIs(None, archive.default_component)
1196+ self.assertIsNone(archive.default_component)
1197
1198 def test_default_component_for_partner(self):
1199 archive = self.factory.makeArchive(purpose=ArchivePurpose.PARTNER)
1200- self.assertEquals(
1201+ self.assertEqual(
1202 getUtility(IComponentSet)['partner'], archive.default_component)
1203
1204 def test_default_component_for_ppas(self):
1205 archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
1206- self.assertEquals(
1207+ self.assertEqual(
1208 getUtility(IComponentSet)['main'], archive.default_component)
1209
1210
1211@@ -1818,7 +1803,7 @@
1212 self.assertRaises(
1213 NotFoundError, self.archive.getFileByName, dsc.filename)
1214 pub.sourcepackagerelease.addFile(dsc)
1215- self.assertEquals(dsc, self.archive.getFileByName(dsc.filename))
1216+ self.assertEqual(dsc, self.archive.getFileByName(dsc.filename))
1217
1218 def test_nonexistent_source_file_is_not_found(self):
1219 # Something that looks like a source file but isn't is not
1220@@ -1834,7 +1819,7 @@
1221 self.assertRaises(
1222 NotFoundError, self.archive.getFileByName, deb.filename)
1223 pub.binarypackagerelease.addFile(deb)
1224- self.assertEquals(deb, self.archive.getFileByName(deb.filename))
1225+ self.assertEqual(deb, self.archive.getFileByName(deb.filename))
1226
1227 def test_nonexistent_binary_file_is_not_found(self):
1228 # Something that looks like a binary file but isn't is not
1229@@ -1850,10 +1835,9 @@
1230 changes_filename='foo_1.0_source.changes')
1231 pu.setDone()
1232 self.assertRaises(
1233- NotFoundError, self.archive.getFileByName,
1234- pu.changesfile.filename)
1235+ NotFoundError, self.archive.getFileByName, pu.changesfile.filename)
1236 pu.addSource(pub.sourcepackagerelease)
1237- self.assertEquals(
1238+ self.assertEqual(
1239 pu.changesfile,
1240 self.archive.getFileByName(pu.changesfile.filename))
1241
1242@@ -1871,7 +1855,7 @@
1243 diff = self.factory.makePackageDiff(
1244 to_source=pub.sourcepackagerelease,
1245 diff_filename='foo_1.0.diff.gz')
1246- self.assertEquals(
1247+ self.assertEqual(
1248 diff.diff_content,
1249 self.archive.getFileByName(diff.diff_content.filename))
1250
1251@@ -1883,7 +1867,7 @@
1252 pub.sourcepackagerelease.addFile(dsc)
1253
1254 # The file is initially found without trouble.
1255- self.assertEquals(dsc, self.archive.getFileByName(dsc.filename))
1256+ self.assertEqual(dsc, self.archive.getFileByName(dsc.filename))
1257
1258 # But after expiry it is not.
1259 removeSecurityProxy(dsc).content = None
1260@@ -1893,7 +1877,7 @@
1261 # It reappears if we create a new one.
1262 new_dsc = self.factory.makeLibraryFileAlias(filename=dsc.filename)
1263 pub.sourcepackagerelease.addFile(new_dsc)
1264- self.assertEquals(new_dsc, self.archive.getFileByName(dsc.filename))
1265+ self.assertEqual(new_dsc, self.archive.getFileByName(dsc.filename))
1266
1267
1268 class TestGetPublishedSources(TestCaseWithFactory):
1269@@ -1992,11 +1976,8 @@
1270 name=['package1', 'package2'])
1271
1272 self.assertEqual(
1273- 3,
1274- distroseries.main_archive.getPublishedSources().count())
1275- self.assertEqual(
1276- 2,
1277- filtered_sources.count())
1278+ 3, distroseries.main_archive.getPublishedSources().count())
1279+ self.assertEqual(2, filtered_sources.count())
1280 self.assertContentEqual(
1281 ['package1', 'package2'],
1282 [filtered_source.sourcepackagerelease.name for filtered_source in
1283@@ -2155,7 +2136,7 @@
1284 # The source should not be published yet in the target_archive.
1285 published = target_archive.getPublishedSources(
1286 name=source.source_package_name).any()
1287- self.assertIs(None, published)
1288+ self.assertIsNone(published)
1289
1290 # There should be one copy job.
1291 job_source = getUtility(IPlainPackageCopyJobSource)
1292@@ -2241,7 +2222,7 @@
1293 # The source should not be published yet in the target_archive.
1294 published = target_archive.getPublishedSources(
1295 name=source.source_package_name).any()
1296- self.assertIs(None, published)
1297+ self.assertIsNone(published)
1298
1299 # There should be one copy job.
1300 job_source = getUtility(IPlainPackageCopyJobSource)
1301@@ -2475,11 +2456,11 @@
1302
1303 source = getUtility(IPlainPackageCopyJobSource)
1304 found_jobs = source.getIncompleteJobsForArchive(archive2)
1305- self.assertEqual(None, found_jobs.any())
1306+ self.assertIsNone(found_jobs.any())
1307
1308 def test_removeCopyNotification_raises_for_not_failed(self):
1309 distroseries, archive1, archive2, requester, job = self.makeJob()
1310-
1311+
1312 self.assertNotEqual(JobStatus.FAILED, job.status)
1313 with person_logged_in(archive2.owner):
1314 self.assertRaises(