Merge lp:~wgrant/launchpad/rework-dominator-tests into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11205
Proposed branch: lp:~wgrant/launchpad/rework-dominator-tests
Merge into: lp:launchpad
Prerequisite: lp:~wgrant/launchpad/refactor-_dominateBinary
Diff against target: 740 lines (+272/-342)
3 files modified
lib/lp/archivepublisher/tests/test_dominator.py (+70/-296)
lib/lp/archivepublisher/tests/test_publisher.py (+1/-0)
lib/lp/soyuz/tests/test_publishing.py (+201/-46)
To merge this branch: bzr merge lp:~wgrant/launchpad/rework-dominator-tests
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+29668@code.launchpad.net

Commit message

Replace most of the domination tests with more thorough model unit tests.

Description of the change

The prerequisite branch moved most of Dominator's logic into the model. This branch is a follow-up, replacing the coarse tests with smaller, more thorough unit tests over the model.

There is no lint.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

Nice.

raising AssertionError in production code sucks, but I realise you're just defining the contract. Please consider adding a 'this is a bad contract' comment there and in the place raising it - otherwise future programmers may believe that the current behaviour is your /intent/.

review: Approve
Revision history for this message
William Grant (wgrant) wrote :

What's wrong with raising it? It's not valid to call the method with an empty list -- there's no dominant publication.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archivepublisher/tests/test_dominator.py'
--- lib/lp/archivepublisher/tests/test_dominator.py 2010-07-21 09:41:48 +0000
+++ lib/lp/archivepublisher/tests/test_dominator.py 2010-07-22 12:03:10 +0000
@@ -6,17 +6,11 @@
6__metaclass__ = type6__metaclass__ = type
77
8import datetime8import datetime
9import pytz
10
11from zope.component import getUtility
129
13from lp.archivepublisher.domination import Dominator10from lp.archivepublisher.domination import Dominator
14from lp.archivepublisher.publishing import Publisher11from lp.archivepublisher.publishing import Publisher
15from canonical.database.sqlbase import flush_database_updates12from canonical.database.sqlbase import flush_database_updates
16from lp.registry.interfaces.series import SeriesStatus13from lp.registry.interfaces.series import SeriesStatus
17from lp.soyuz.interfaces.component import IComponentSet
18from lp.registry.interfaces.person import IPersonSet
19from lp.registry.interfaces.pocket import PackagePublishingPocket
20from lp.soyuz.interfaces.publishing import PackagePublishingStatus14from lp.soyuz.interfaces.publishing import PackagePublishingStatus
21from lp.soyuz.tests.test_publishing import TestNativePublishingBase15from lp.soyuz.tests.test_publishing import TestNativePublishingBase
2216
@@ -24,6 +18,16 @@
24class TestDominator(TestNativePublishingBase):18class TestDominator(TestNativePublishingBase):
25 """Test Dominator class."""19 """Test Dominator class."""
2620
21 def createSourceAndBinaries(self, version):
22 """Create a source and binaries with the given version."""
23 source = self.getPubSource(
24 version=version,
25 status=PackagePublishingStatus.PUBLISHED)
26 binaries = self.getPubBinaries(
27 pub_source=source,
28 status=PackagePublishingStatus.PUBLISHED)
29 return (source, binaries)
30
27 def createSimpleDominationContext(self):31 def createSimpleDominationContext(self):
28 """Create simple domination context.32 """Create simple domination context.
2933
@@ -39,308 +43,78 @@
3943
40 Note that as an optimization the binaries list is already unpacked.44 Note that as an optimization the binaries list is already unpacked.
41 """45 """
42 foo_10_source = self.getPubSource(46 foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0')
43 version='1.0', architecturehintlist='i386',47 foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1')
44 status=PackagePublishingStatus.PUBLISHED)48 return (foo_11_source, foo_11_binaries[0],
45 foo_10_binaries = self.getPubBinaries(49 foo_10_source, foo_10_binaries[0])
46 pub_source=foo_10_source,50
47 status=PackagePublishingStatus.PUBLISHED)51 def dominateAndCheck(self, dominant, dominated, supersededby):
48
49 foo_11_source = self.getPubSource(
50 version='1.1', architecturehintlist='i386',
51 status=PackagePublishingStatus.PUBLISHED)
52 foo_11_binaries = self.getPubBinaries(
53 pub_source=foo_11_source,
54 status=PackagePublishingStatus.PUBLISHED)
55
56 dominant_source = foo_11_source
57 dominant_binaries = [pub for pub in foo_11_binaries]
58
59 dominated_source = foo_10_source
60 dominated_binaries = [pub for pub in foo_10_binaries]
61
62 return (dominant_source, dominant_binaries[0],
63 dominated_source, dominated_binaries[0])
64
65 def testSourceDomination(self):
66 """Test source domination procedure."""
67 dominator = Dominator(self.logger, self.ubuntutest.main_archive)52 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
6853
69 [dominant_source, dominant_binary, dominated_source,54 # The _dominate* test methods require a dictionary where the
70 dominated_binary] = self.createSimpleDominationContext()
71
72 # The _dominate* test methods require a dictionary where the source
73 # package name is the key. The key's value is a list of55 # package name is the key. The key's value is a list of
74 # source or binary packages representing dominant, the first element56 # source or binary packages representing dominant, the first element
75 # and dominated, the subsequents.57 # and dominated, the subsequents.
76 source_input = {'foo': [dominant_source, dominated_source]}58 pubs = {'foo': [dominant, dominated]}
7759
78 dominator._dominatePublications(source_input)60 dominator._dominatePublications(pubs)
79 flush_database_updates()61 flush_database_updates()
8062
81 # The dominant version remains correctly published.63 # The dominant version remains correctly published.
82 dominant = self.checkSourcePublication(64 self.checkPublication(dominant, PackagePublishingStatus.PUBLISHED)
83 dominant_source, PackagePublishingStatus.PUBLISHED)
84 self.assertTrue(dominant.supersededby is None)65 self.assertTrue(dominant.supersededby is None)
85 self.assertTrue(dominant.datesuperseded is None)66 self.assertTrue(dominant.datesuperseded is None)
8667
87 # The dominated version is correctly dominated.68 # The dominated version is correctly dominated.
88 dominated = self.checkSourcePublication(69 self.checkPublication(dominated, PackagePublishingStatus.SUPERSEDED)
89 dominated_source, PackagePublishingStatus.SUPERSEDED)70 self.assertEqual(dominated.supersededby, supersededby)
90 self.assertEqual(71 self.checkPastDate(dominated.datesuperseded)
91 dominated.supersededby, dominant.sourcepackagerelease)72
92 self.checkPastDate(dominated.datesuperseded)73 def testManualSourceDomination(self):
9374 """Test source domination procedure."""
94 def testEmptySourceDomination(self):75 [dominant_source, dominant_binary, dominated_source,
95 """Source domination asserts for not empty input list."""76 dominated_binary] = self.createSimpleDominationContext()
96 dominator = Dominator(self.logger, self.ubuntutest.main_archive)77
97 source_input = {'foo': []}78 self.dominateAndCheck(
98 self.assertRaises(79 dominant_source, dominated_source,
99 AssertionError, dominator._dominatePublications, source_input)80 dominant_source.sourcepackagerelease)
10081
101 def testBinariesDomination(self):82 def testManualBinaryDomination(self):
102 """Test overall binary domination procedure."""83 """Test binary domination procedure."""
103 dominator = Dominator(self.logger, self.ubuntutest.main_archive)84 [dominant_source, dominant, dominated_source,
10485 dominated] = self.createSimpleDominationContext()
105 [dominant_source, dominant, dominated_source,86
106 dominated] = self.createSimpleDominationContext()87 self.dominateAndCheck(
10788 dominant, dominated, dominant.binarypackagerelease.build)
108 # See comment about domination input format and ordering above.89
109 binary_input = {'foo-bin': [dominant, dominated]}90 def testJudgeAndDominate(self):
11091 """Verify that judgeAndDominate correctly dominates everything."""
111 dominator._dominatePublications(binary_input)92 foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0')
112 flush_database_updates()93 foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1')
11394 foo_12_source, foo_12_binaries = self.createSourceAndBinaries('1.2')
114 # Dominant version remains correctly published.95
115 dominant = self.checkBinaryPublication(96 dominator = Dominator(self.logger, foo_10_source.archive)
116 dominant, PackagePublishingStatus.PUBLISHED)97 dominator.judgeAndDominate(
117 self.assertTrue(dominant.supersededby is None)98 foo_10_source.distroseries, foo_10_source.pocket, self.config)
118 self.assertTrue(dominant.datesuperseded is None)99
119
120 # Dominated version is correctly dominated.
121 dominated = self.checkBinaryPublication(
122 dominated, PackagePublishingStatus.SUPERSEDED)
123 self.assertEqual(
124 dominated.supersededby, dominant.binarypackagerelease.build)
125 self.checkPastDate(dominated.datesuperseded)
126
127 def testEmptyBinaryDomination(self):
128 """Binaries domination asserts not empty input list."""
129 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
130 binary_input = {'foo-bin': []}
131 self.assertRaises(
132 AssertionError, dominator._dominatePublications, binary_input)
133
134 def testBinaryDomination(self):
135 """Test binary domination unit procedure."""
136 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
137
138 [dominant_source, dominant, dominated_source,
139 dominated] = self.createSimpleDominationContext()
140
141 dominated.supersede(dominant)
142 flush_database_updates()
143
144 dominated = self.checkBinaryPublication(
145 dominated, PackagePublishingStatus.SUPERSEDED)
146 self.assertEqual(
147 dominated.supersededby, dominant.binarypackagerelease.build)
148 self.checkPastDate(dominated.datesuperseded)
149
150 def testBinaryDominationAssertsPendingOrPublished(self):
151 """Test binary domination asserts coherent dominated status.
152
153 Normally supersede() only accepts domination candidates in
154 PUBLISHED or PENDING status, a exception is opened for architecture
155 independent binaries because during the iteration they might have
156 been already SUPERSEDED with its first publication, when it happens
157 the candidate is skipped, i.e. it's not dominated again.
158
159 (remembering the architecture independent binaries get superseded
160 atomically)
161 """
162 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
163
164 [dominant_source, dominant, dominated_source,
165 dominated] = self.createSimpleDominationContext()
166
167 # Let's modify the domination candidate, so it will look wrong to
168 # supersede() which will raise because it's a architecture
169 # specific binary publication not in PENDING or PUBLISHED state.
170 dominated.status = PackagePublishingStatus.SUPERSEDED
171 manual_domination_date = datetime.datetime(
172 2006, 12, 25, tzinfo=pytz.timezone("UTC"))
173 dominated.datesuperseded = manual_domination_date
174 flush_database_updates()
175
176 # An error like that in production clearly indicates that something
177 # is wrong in the Dominator look-up methods.
178 self.assertRaises(
179 AssertionError, dominated.supersede, dominant)
180
181 # The refused publishing record remains the same.
182 dominated = self.checkBinaryPublication(
183 dominated, PackagePublishingStatus.SUPERSEDED)
184 self.assertEqual(dominated.datesuperseded, manual_domination_date)
185
186 # Let's make it a architecture independent binary, so the domination
187 # can be executed, but the record will be skipped.
188 dominated.binarypackagerelease.architecturespecific = False
189 flush_database_updates()
190
191 dominated.supersede(dominant)
192 flush_database_updates()
193 dominated = self.checkBinaryPublication(
194 dominated, PackagePublishingStatus.SUPERSEDED)
195 self.assertEqual(dominated.datesuperseded, manual_domination_date)
196
197 def testOtherBinaryPublications(self):
198 """Check the basis of architecture independent binary domination.
199
200 We use _getOtherPublications to identify other publications of the
201 same binarypackagerelease in other architectures (architecture
202 independent binaries), they will be dominated during a single step.
203
204 See overall details in `testDominationOfOldArchIndepBinaries`.
205 """
206 # Create architecture independent publications for foo-bin_1.0
207 # in i386 & hppa.
208 pub_source_archindep = self.getPubSource(
209 version='1.0', status=PackagePublishingStatus.PUBLISHED,
210 architecturehintlist='all')
211 pub_binaries_archindep = self.getPubBinaries(
212 pub_source=pub_source_archindep,
213 status=PackagePublishingStatus.PUBLISHED)
214 [hppa_pub, i386_pub] = pub_binaries_archindep
215
216 # We will also copy the binary publications to a PPA archive
217 # to check if the lookup is indeed restricted to the dominated
218 # archive. See bug #237845 for further information.
219 cprov = getUtility(IPersonSet).getByName('cprov')
220 i386_pub.copyTo(
221 self.breezy_autotest,
222 PackagePublishingPocket.RELEASE,
223 cprov.archive)
224 cprov_foo_binaries = cprov.archive.getAllPublishedBinaries(name='foo')
225 self.assertEqual(cprov_foo_binaries.count(), 2)
226
227 # Manually supersede the hppa binary.
228 hppa_pub.status = PackagePublishingStatus.SUPERSEDED
229 flush_database_updates()
230
231 # Check if we can reach the i386 publication using
232 # _getOtherBinaryPublications over the hppa binary.
233 [found] = list(hppa_pub._getOtherPublications())
234 self.assertEqual(i386_pub, found)
235
236 # Create architecture specific publications for foo-bin_1.1 in
237 # i386 & hppa.
238 pub_source_archdep = self.getPubSource(
239 version='1.1', status=PackagePublishingStatus.PUBLISHED,
240 architecturehintlist='any')
241 pub_binaries_archdep = self.getPubBinaries(
242 pub_source=pub_source_archdep)
243 [hppa_pub, i386_pub] = pub_binaries_archdep
244
245 # Manually supersede the hppa publication.
246 hppa_pub.status = PackagePublishingStatus.SUPERSEDED
247 flush_database_updates()
248
249 # Check if there is no other publication of the hppa binary package
250 # release.
251 self.assertEqual(
252 hppa_pub._getOtherPublications().count(),
253 0)
254
255 def testDominationOfOldArchIndepBinaries(self):
256 """Check domination of architecture independent binaries.
257
258 When a architecture independent binary is dominated it should also
259 'carry' the same publications in other architectures independently
260 of whether or not the new binary was successfully built to a specific
261 architecture.
262
263 See bug #48760 for further information about this aspect.
264 """
265 publisher = Publisher(
266 self.logger, self.config, self.disk_pool,
267 self.ubuntutest.main_archive)
268
269 # Create published archindep context.
270 pub_source_archindep = self.getPubSource(
271 version='1.0', status=PackagePublishingStatus.PUBLISHED,
272 architecturehintlist='all')
273 pub_binaries_archindep = self.getPubBinaries(
274 pub_source=pub_source_archindep,
275 status=PackagePublishingStatus.PUBLISHED)
276
277 # Emulated new publication of a archdep binary only on i386.
278 pub_source_archdep = self.getPubSource(
279 version='1.1', architecturehintlist='i386')
280 pub_binaries_archdep = self.getPubBinaries(
281 pub_source=pub_source_archdep)
282
283 publisher.A_publish(False)
284 publisher.B_dominate(False)
285
286 # The latest architecture specific source and binary pair is
287 # PUBLISHED.
288 self.checkPublications(100 self.checkPublications(
289 pub_source_archdep, pub_binaries_archdep,101 [foo_12_source] + foo_12_binaries,
290 PackagePublishingStatus.PUBLISHED)102 PackagePublishingStatus.PUBLISHED)
291103 self.checkPublications(
292 # The oldest architecture independent source & binaries should104 [foo_11_source] + foo_11_binaries,
293 # be SUPERSEDED, i.e., the fact that new source version wasn't105 PackagePublishingStatus.SUPERSEDED)
294 # built for hppa should not hold the condemned architecture106 self.checkPublications(
295 # independent binary.107 [foo_10_source] + foo_10_binaries,
296 self.checkPublications(108 PackagePublishingStatus.SUPERSEDED)
297 pub_source_archindep, pub_binaries_archindep,109
298 PackagePublishingStatus.SUPERSEDED)110 def testEmptyDomination(self):
299111 """Domination asserts for not empty input list."""
300 def testDominationOnArchIndependentBinaryOverrides(self):112 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
301 """Check domination of architecture-independent overridden binaries.113 pubs = {'foo': []}
302114 # This isn't a really good exception. It should probably be
303 Due to the mechanism for performing atomic domination of arch-indep115 # something more indicative of bad input.
304 binaries (bug #48760) we were erroneously dominating binary override116 self.assertRaises(
305 attempts (new pending publications of the same binary in different117 AssertionError, dominator._dominatePublications, pubs)
306 component/section). See bug #178102 for further information.
307 """
308 publisher = Publisher(
309 self.logger, self.config, self.disk_pool,
310 self.ubuntutest.main_archive)
311
312 # Create published archindep context.
313 pub_source = self.getPubSource(
314 version='1.0', status=PackagePublishingStatus.PUBLISHED,
315 architecturehintlist='all')
316 overridden_binaries = self.getPubBinaries(
317 pub_source=pub_source, status=PackagePublishingStatus.PUBLISHED)
318
319 # Committing the transaction here is required to guarantee sane
320 # order in publisher queries.
321 self.layer.commit()
322
323 # Perform the binary override.
324 universe = getUtility(IComponentSet)['universe']
325 pub_binaries = []
326 for pub in overridden_binaries:
327 pub_binaries.append(pub.changeOverride(new_component=universe))
328
329 # Overrides are in DB.
330 self.checkBinaryPublications(
331 pub_binaries, PackagePublishingStatus.PENDING)
332
333 # Publish and dominate them.
334 publisher.A_publish(False)
335 publisher.B_dominate(False)
336
337 # The original binary publications are marked as SUPERSEDED and
338 # the just-create overrides as preserved as PUBLISHED.
339 self.checkBinaryPublications(
340 overridden_binaries, PackagePublishingStatus.SUPERSEDED)
341
342 self.checkBinaryPublications(
343 pub_binaries, PackagePublishingStatus.PUBLISHED)
344118
345119
346class TestDomination(TestNativePublishingBase):120class TestDomination(TestNativePublishingBase):
@@ -377,15 +151,15 @@
377 # DELETED and OBSOLETED publications are set to be deleted151 # DELETED and OBSOLETED publications are set to be deleted
378 # immediately, whereas SUPERSEDED ones get a stay of execution152 # immediately, whereas SUPERSEDED ones get a stay of execution
379 # according to the configuration.153 # according to the configuration.
380 deleted_source = self.checkSourcePublication(154 self.checkPublication(
381 deleted_source, PackagePublishingStatus.DELETED)155 deleted_source, PackagePublishingStatus.DELETED)
382 self.checkPastDate(deleted_source.scheduleddeletiondate)156 self.checkPastDate(deleted_source.scheduleddeletiondate)
383157
384 obsoleted_source = self.checkSourcePublication(158 self.checkPublication(
385 obsoleted_source, PackagePublishingStatus.OBSOLETE)159 obsoleted_source, PackagePublishingStatus.OBSOLETE)
386 self.checkPastDate(deleted_source.scheduleddeletiondate)160 self.checkPastDate(deleted_source.scheduleddeletiondate)
387161
388 superseded_source = self.checkSourcePublication(162 self.checkPublication(
389 superseded_source, PackagePublishingStatus.SUPERSEDED)163 superseded_source, PackagePublishingStatus.SUPERSEDED)
390 self.checkPastDate(164 self.checkPastDate(
391 superseded_source.scheduleddeletiondate,165 superseded_source.scheduleddeletiondate,
392166
=== modified file 'lib/lp/archivepublisher/tests/test_publisher.py'
--- lib/lp/archivepublisher/tests/test_publisher.py 2010-07-21 14:14:54 +0000
+++ lib/lp/archivepublisher/tests/test_publisher.py 2010-07-22 12:03:10 +0000
@@ -1113,6 +1113,7 @@
11131113
1114 def tearDown(self):1114 def tearDown(self):
1115 """Purge the archive root location. """1115 """Purge the archive root location. """
1116 super(TestPublisherRepositorySignatures, self).tearDown()
1116 if self.archive_publisher is not None:1117 if self.archive_publisher is not None:
1117 shutil.rmtree(self.archive_publisher._config.distsroot)1118 shutil.rmtree(self.archive_publisher._config.distsroot)
11181119
11191120
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2010-07-21 14:14:54 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2010-07-22 12:03:10 +0000
@@ -9,7 +9,6 @@
9import shutil9import shutil
10from StringIO import StringIO10from StringIO import StringIO
11import tempfile11import tempfile
12import unittest
1312
14import pytz13import pytz
15from zope.component import getUtility14from zope.component import getUtility
@@ -457,16 +456,17 @@
457 return source456 return source
458457
459458
460class TestNativePublishingBase(unittest.TestCase, SoyuzTestPublisher):459class TestNativePublishingBase(TestCaseWithFactory, SoyuzTestPublisher):
461 layer = LaunchpadZopelessLayer460 layer = LaunchpadZopelessLayer
462 dbuser = config.archivepublisher.dbuser461 dbuser = config.archivepublisher.dbuser
463462
464 def __init__(self, methodName='runTest'):463 def __init__(self, methodName='runTest'):
465 unittest.TestCase.__init__(self, methodName=methodName)464 super(TestNativePublishingBase, self).__init__(methodName=methodName)
466 SoyuzTestPublisher.__init__(self)465 SoyuzTestPublisher.__init__(self)
467466
468 def setUp(self):467 def setUp(self):
469 """Setup a pool dir, the librarian, and instantiate the DiskPool."""468 """Setup a pool dir, the librarian, and instantiate the DiskPool."""
469 super(TestNativePublishingBase, self).setUp()
470 self.layer.switchDbUser(config.archivepublisher.dbuser)470 self.layer.switchDbUser(config.archivepublisher.dbuser)
471 self.prepareBreezyAutotest()471 self.prepareBreezyAutotest()
472 self.config = Config(self.ubuntutest)472 self.config = Config(self.ubuntutest)
@@ -480,6 +480,7 @@
480480
481 def tearDown(self):481 def tearDown(self):
482 """Tear down blows the pool dir away."""482 """Tear down blows the pool dir away."""
483 super(TestNativePublishingBase, self).tearDown()
483 shutil.rmtree(self.config.distroroot)484 shutil.rmtree(self.config.distroroot)
484485
485 def getPubSource(self, *args, **kwargs):486 def getPubSource(self, *args, **kwargs):
@@ -502,48 +503,19 @@
502 self.layer.commit()503 self.layer.commit()
503 return binaries504 return binaries
504505
505 def checkSourcePublication(self, source, status):506 def checkPublication(self, pub, status):
506 """Assert the source publications has the given status.507 """Assert the publication has the given status."""
507508 self.assertEqual(
508 Retrieve an up-to-date record corresponding to the given publication,509 pub.status, status, "%s is not %s (%s)" % (
509 check and return it.510 pub.displayname, status.name, pub.status.name))
510 """511
511 fresh_source = SourcePackagePublishingHistory.get(source.id)512 def checkPublications(self, pubs, status):
512 self.assertEqual(513 """Assert the given publications have the given status.
513 fresh_source.status, status, "%s is not %s (%s)" % (514
514 fresh_source.displayname, status.name, source.status.name))515 See `checkPublication`.
515 return fresh_source516 """
516517 for pub in pubs:
517 def checkBinaryPublication(self, binary, status):518 self.checkPublication(pub, status)
518 """Assert the binary publication has the given status.
519
520 Retrieve an up-to-date record corresponding to the given publication,
521 check and return it.
522 """
523 fresh_binary = BinaryPackagePublishingHistory.get(binary.id)
524 self.assertEqual(
525 fresh_binary.status, status, "%s is not %s (%s)" % (
526 fresh_binary.displayname, status.name, fresh_binary.status.name))
527 return fresh_binary
528
529 def checkBinaryPublications(self, binaries, status):
530 """Assert the binary publications have the given status.
531
532 See `checkBinaryPublication`.
533 """
534 fresh_binaries = []
535 for bin in binaries:
536 bin = self.checkBinaryPublication(bin, status)
537 fresh_binaries.append(bin)
538 return fresh_binaries
539
540 def checkPublications(self, source, binaries, status):
541 """Assert source and binary publications have in the given status.
542
543 See `checkSourcePublication` and `checkBinaryPublications`.
544 """
545 self.checkSourcePublication(source, status)
546 self.checkBinaryPublications(binaries, status)
547519
548 def checkPastDate(self, date, lag=None):520 def checkPastDate(self, date, lag=None):
549 """Assert given date is older than 'now'.521 """Assert given date is older than 'now'.
@@ -557,6 +529,19 @@
557 limit = limit + lag529 limit = limit + lag
558 self.assertTrue(date < limit, "%s >= %s" % (date, limit))530 self.assertTrue(date < limit, "%s >= %s" % (date, limit))
559531
532 def checkSuperseded(self, pubs, supersededby=None):
533 self.checkPublications(pubs, PackagePublishingStatus.SUPERSEDED)
534 for pub in pubs:
535 self.checkPastDate(pub.datesuperseded)
536 if supersededby is not None:
537 if isinstance(pub, BinaryPackagePublishingHistory):
538 dominant = supersededby.binarypackagerelease.build
539 else:
540 dominant = supersededby.sourcepackagerelease
541 self.assertEquals(dominant, pub.supersededby)
542 else:
543 self.assertIs(None, pub.supersededby)
544
560545
561class TestNativePublishing(TestNativePublishingBase):546class TestNativePublishing(TestNativePublishingBase):
562547
@@ -815,7 +800,6 @@
815800
816 # Adjust the binary package release original component.801 # Adjust the binary package release original component.
817 universe = getUtility(IComponentSet)['universe']802 universe = getUtility(IComponentSet)['universe']
818 from zope.security.proxy import removeSecurityProxy
819 removeSecurityProxy(binary.binarypackagerelease).component = universe803 removeSecurityProxy(binary.binarypackagerelease).component = universe
820804
821 self.copyAndCheck(805 self.copyAndCheck(
@@ -1025,3 +1009,174 @@
1025 record = self.publishing_set.getByIdAndArchive(1009 record = self.publishing_set.getByIdAndArchive(
1026 binary_publishing.id, wrong_archive, source=False)1010 binary_publishing.id, wrong_archive, source=False)
1027 self.assertEqual(None, record)1011 self.assertEqual(None, record)
1012
1013
1014class TestSourceDomination(TestNativePublishingBase):
1015 """Test SourcePackagePublishingHistory.supersede() operates correctly."""
1016
1017 def testSupersede(self):
1018 """Check that supersede() without arguments works."""
1019 source = self.getPubSource()
1020 source.supersede()
1021 self.checkSuperseded([source])
1022
1023 def testSupersedeWithDominant(self):
1024 """Check that supersede() with a dominant publication works."""
1025 source = self.getPubSource()
1026 super_source = self.getPubSource()
1027 source.supersede(super_source)
1028 self.checkSuperseded([source], super_source)
1029
1030 def testSupersedingSupersededSourceFails(self):
1031 """Check that supersede() fails with a superseded source.
1032
1033 Sources should not be superseded twice. If a second attempt is made,
1034 the Dominator's lookups are buggy.
1035 """
1036 source = self.getPubSource()
1037 super_source = self.getPubSource()
1038 source.supersede(super_source)
1039 self.checkSuperseded([source], super_source)
1040
1041 # Manually set a date in the past, so we can confirm that
1042 # the second supersede() fails properly.
1043 source.datesuperseded = datetime.datetime(
1044 2006, 12, 25, tzinfo=pytz.timezone("UTC"))
1045 super_date = source.datesuperseded
1046
1047 self.assertRaises(AssertionError, source.supersede, super_source)
1048 self.checkSuperseded([source], super_source)
1049 self.assertEquals(super_date, source.datesuperseded)
1050
1051
1052class TestBinaryDomination(TestNativePublishingBase):
1053 """Test BinaryPackagePublishingHistory.supersede() operates correctly."""
1054
1055 def testSupersede(self):
1056 """Check that supersede() without arguments works."""
1057 bins = self.getPubBinaries(architecturespecific=True)
1058 bins[0].supersede()
1059 self.checkSuperseded([bins[0]])
1060 self.checkPublication(bins[1], PackagePublishingStatus.PENDING)
1061
1062 def testSupersedeWithDominant(self):
1063 """Check that supersede() with a dominant publication works."""
1064 bins = self.getPubBinaries(architecturespecific=True)
1065 super_bins = self.getPubBinaries(architecturespecific=True)
1066 bins[0].supersede(super_bins[0])
1067 self.checkSuperseded([bins[0]], super_bins[0])
1068 self.checkPublication(bins[1], PackagePublishingStatus.PENDING)
1069
1070 def testSupersedesArchIndepBinariesAtomically(self):
1071 """Check that supersede() supersedes arch-indep binaries atomically.
1072
1073 Architecture-independent binaries should be removed from all
1074 architectures when they are superseded on at least one (bug #48760).
1075 """
1076 bins = self.getPubBinaries(architecturespecific=False)
1077 super_bins = self.getPubBinaries(architecturespecific=False)
1078 bins[0].supersede(super_bins[0])
1079 self.checkSuperseded(bins, super_bins[0])
1080
1081 def testAtomicDominationRespectsOverrides(self):
1082 """Check that atomic domination only covers identical overrides.
1083
1084 This is important, as otherwise newly-overridden arch-indep binaries
1085 will supersede themselves, and vanish entirely (bug #178102).
1086 """
1087 bins = self.getPubBinaries(architecturespecific=False)
1088
1089 universe = getUtility(IComponentSet)['universe']
1090 super_bins = []
1091 for bin in bins:
1092 super_bins.append(bin.changeOverride(new_component=universe))
1093
1094 bins[0].supersede(super_bins[0])
1095 self.checkSuperseded(bins, super_bins[0])
1096 self.checkPublications(super_bins, PackagePublishingStatus.PENDING)
1097
1098 def testSupersedingSupersededArchSpecificBinaryFails(self):
1099 """Check that supersede() fails with a superseded arch-dep binary.
1100
1101 Architecture-specific binaries should not normally be superseded
1102 twice. If a second attempt is made, the Dominator's lookups are buggy.
1103 """
1104 bin = self.getPubBinaries(architecturespecific=True)[0]
1105 super_bin = self.getPubBinaries(architecturespecific=True)[0]
1106 bin.supersede(super_bin)
1107
1108 # Manually set a date in the past, so we can confirm that
1109 # the second supersede() fails properly.
1110 bin.datesuperseded = datetime.datetime(
1111 2006, 12, 25, tzinfo=pytz.timezone("UTC"))
1112 super_date = bin.datesuperseded
1113
1114 self.assertRaises(AssertionError, bin.supersede, super_bin)
1115 self.checkSuperseded([bin], super_bin)
1116 self.assertEquals(super_date, bin.datesuperseded)
1117
1118 def testSkipsSupersededArchIndependentBinary(self):
1119 """Check that supersede() skips a superseded arch-indep binary.
1120
1121 Since all publications of an architecture-independent binary are
1122 superseded atomically, they may be superseded again later. In that
1123 case, we skip the domination, leaving the old date unchanged.
1124 """
1125 bin = self.getPubBinaries(architecturespecific=False)[0]
1126 super_bin = self.getPubBinaries(architecturespecific=False)[0]
1127 bin.supersede(super_bin)
1128 self.checkSuperseded([bin], super_bin)
1129
1130 # Manually set a date in the past, so we can confirm that
1131 # the second supersede() skips properly.
1132 bin.datesuperseded = datetime.datetime(
1133 2006, 12, 25, tzinfo=pytz.timezone("UTC"))
1134 super_date = bin.datesuperseded
1135
1136 bin.supersede(super_bin)
1137 self.checkSuperseded([bin], super_bin)
1138 self.assertEquals(super_date, bin.datesuperseded)
1139
1140
1141class TestBinaryGetOtherPublications(TestNativePublishingBase):
1142 """Test BinaryPackagePublishingHistory._getOtherPublications() works."""
1143
1144 def checkOtherPublications(self, this, others):
1145 self.assertEquals(
1146 set(removeSecurityProxy(this)._getOtherPublications()),
1147 set(others))
1148
1149 def testFindsOtherArchIndepPublications(self):
1150 """Arch-indep publications with the same overrides should be found."""
1151 bins = self.getPubBinaries(architecturespecific=False)
1152 self.checkOtherPublications(bins[0], bins)
1153
1154 def testDoesntFindArchSpecificPublications(self):
1155 """Arch-dep publications shouldn't be found."""
1156 bins = self.getPubBinaries(architecturespecific=True)
1157 self.checkOtherPublications(bins[0], [bins[0]])
1158
1159 def testDoesntFindPublicationsInOtherArchives(self):
1160 """Publications in other archives shouldn't be found."""
1161 bins = self.getPubBinaries(architecturespecific=False)
1162 foreign_bins = bins[0].copyTo(
1163 bins[0].distroarchseries.distroseries, bins[0].pocket,
1164 self.factory.makeArchive())
1165 self.checkOtherPublications(bins[0], bins)
1166 self.checkOtherPublications(foreign_bins[0], foreign_bins)
1167
1168 def testDoesntFindPublicationsWithDifferentOverrides(self):
1169 """Publications with different overrides shouldn't be found."""
1170 bins = self.getPubBinaries(architecturespecific=False)
1171 universe = getUtility(IComponentSet)['universe']
1172 foreign_bin = bins[0].changeOverride(new_component=universe)
1173 self.checkOtherPublications(bins[0], bins)
1174 self.checkOtherPublications(foreign_bin, [foreign_bin])
1175
1176 def testDoesntFindSupersededPublications(self):
1177 """Superseded publications shouldn't be found."""
1178 bins = self.getPubBinaries(architecturespecific=False)
1179 self.checkOtherPublications(bins[0], bins)
1180 # This will supersede both atomically.
1181 bins[0].supersede()
1182 self.checkOtherPublications(bins[0], [])