Merge lp:~wgrant/launchpad/rework-dominator-tests into lp:launchpad
- rework-dominator-tests
- Merge into devel
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 |
Related bugs: |
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
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
1 | === modified file 'lib/lp/archivepublisher/tests/test_dominator.py' |
2 | --- lib/lp/archivepublisher/tests/test_dominator.py 2010-07-21 09:41:48 +0000 |
3 | +++ lib/lp/archivepublisher/tests/test_dominator.py 2010-07-22 12:03:10 +0000 |
4 | @@ -6,17 +6,11 @@ |
5 | __metaclass__ = type |
6 | |
7 | import datetime |
8 | -import pytz |
9 | - |
10 | -from zope.component import getUtility |
11 | |
12 | from lp.archivepublisher.domination import Dominator |
13 | from lp.archivepublisher.publishing import Publisher |
14 | from canonical.database.sqlbase import flush_database_updates |
15 | from lp.registry.interfaces.series import SeriesStatus |
16 | -from lp.soyuz.interfaces.component import IComponentSet |
17 | -from lp.registry.interfaces.person import IPersonSet |
18 | -from lp.registry.interfaces.pocket import PackagePublishingPocket |
19 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
20 | from lp.soyuz.tests.test_publishing import TestNativePublishingBase |
21 | |
22 | @@ -24,6 +18,16 @@ |
23 | class TestDominator(TestNativePublishingBase): |
24 | """Test Dominator class.""" |
25 | |
26 | + def createSourceAndBinaries(self, version): |
27 | + """Create a source and binaries with the given version.""" |
28 | + source = self.getPubSource( |
29 | + version=version, |
30 | + status=PackagePublishingStatus.PUBLISHED) |
31 | + binaries = self.getPubBinaries( |
32 | + pub_source=source, |
33 | + status=PackagePublishingStatus.PUBLISHED) |
34 | + return (source, binaries) |
35 | + |
36 | def createSimpleDominationContext(self): |
37 | """Create simple domination context. |
38 | |
39 | @@ -39,308 +43,78 @@ |
40 | |
41 | Note that as an optimization the binaries list is already unpacked. |
42 | """ |
43 | - foo_10_source = self.getPubSource( |
44 | - version='1.0', architecturehintlist='i386', |
45 | - status=PackagePublishingStatus.PUBLISHED) |
46 | - foo_10_binaries = self.getPubBinaries( |
47 | - pub_source=foo_10_source, |
48 | - status=PackagePublishingStatus.PUBLISHED) |
49 | - |
50 | - foo_11_source = self.getPubSource( |
51 | - version='1.1', architecturehintlist='i386', |
52 | - status=PackagePublishingStatus.PUBLISHED) |
53 | - foo_11_binaries = self.getPubBinaries( |
54 | - pub_source=foo_11_source, |
55 | - status=PackagePublishingStatus.PUBLISHED) |
56 | - |
57 | - dominant_source = foo_11_source |
58 | - dominant_binaries = [pub for pub in foo_11_binaries] |
59 | - |
60 | - dominated_source = foo_10_source |
61 | - dominated_binaries = [pub for pub in foo_10_binaries] |
62 | - |
63 | - return (dominant_source, dominant_binaries[0], |
64 | - dominated_source, dominated_binaries[0]) |
65 | - |
66 | - def testSourceDomination(self): |
67 | - """Test source domination procedure.""" |
68 | + foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0') |
69 | + foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1') |
70 | + return (foo_11_source, foo_11_binaries[0], |
71 | + foo_10_source, foo_10_binaries[0]) |
72 | + |
73 | + def dominateAndCheck(self, dominant, dominated, supersededby): |
74 | dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
75 | |
76 | - [dominant_source, dominant_binary, dominated_source, |
77 | - dominated_binary] = self.createSimpleDominationContext() |
78 | - |
79 | - # The _dominate* test methods require a dictionary where the source |
80 | + # The _dominate* test methods require a dictionary where the |
81 | # package name is the key. The key's value is a list of |
82 | # source or binary packages representing dominant, the first element |
83 | # and dominated, the subsequents. |
84 | - source_input = {'foo': [dominant_source, dominated_source]} |
85 | + pubs = {'foo': [dominant, dominated]} |
86 | |
87 | - dominator._dominatePublications(source_input) |
88 | + dominator._dominatePublications(pubs) |
89 | flush_database_updates() |
90 | |
91 | # The dominant version remains correctly published. |
92 | - dominant = self.checkSourcePublication( |
93 | - dominant_source, PackagePublishingStatus.PUBLISHED) |
94 | + self.checkPublication(dominant, PackagePublishingStatus.PUBLISHED) |
95 | self.assertTrue(dominant.supersededby is None) |
96 | self.assertTrue(dominant.datesuperseded is None) |
97 | |
98 | # The dominated version is correctly dominated. |
99 | - dominated = self.checkSourcePublication( |
100 | - dominated_source, PackagePublishingStatus.SUPERSEDED) |
101 | - self.assertEqual( |
102 | - dominated.supersededby, dominant.sourcepackagerelease) |
103 | - self.checkPastDate(dominated.datesuperseded) |
104 | - |
105 | - def testEmptySourceDomination(self): |
106 | - """Source domination asserts for not empty input list.""" |
107 | - dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
108 | - source_input = {'foo': []} |
109 | - self.assertRaises( |
110 | - AssertionError, dominator._dominatePublications, source_input) |
111 | - |
112 | - def testBinariesDomination(self): |
113 | - """Test overall binary domination procedure.""" |
114 | - dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
115 | - |
116 | - [dominant_source, dominant, dominated_source, |
117 | - dominated] = self.createSimpleDominationContext() |
118 | - |
119 | - # See comment about domination input format and ordering above. |
120 | - binary_input = {'foo-bin': [dominant, dominated]} |
121 | - |
122 | - dominator._dominatePublications(binary_input) |
123 | - flush_database_updates() |
124 | - |
125 | - # Dominant version remains correctly published. |
126 | - dominant = self.checkBinaryPublication( |
127 | - dominant, PackagePublishingStatus.PUBLISHED) |
128 | - self.assertTrue(dominant.supersededby is None) |
129 | - self.assertTrue(dominant.datesuperseded is None) |
130 | - |
131 | - # Dominated version is correctly dominated. |
132 | - dominated = self.checkBinaryPublication( |
133 | - dominated, PackagePublishingStatus.SUPERSEDED) |
134 | - self.assertEqual( |
135 | - dominated.supersededby, dominant.binarypackagerelease.build) |
136 | - self.checkPastDate(dominated.datesuperseded) |
137 | - |
138 | - def testEmptyBinaryDomination(self): |
139 | - """Binaries domination asserts not empty input list.""" |
140 | - dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
141 | - binary_input = {'foo-bin': []} |
142 | - self.assertRaises( |
143 | - AssertionError, dominator._dominatePublications, binary_input) |
144 | - |
145 | - def testBinaryDomination(self): |
146 | - """Test binary domination unit procedure.""" |
147 | - dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
148 | - |
149 | - [dominant_source, dominant, dominated_source, |
150 | - dominated] = self.createSimpleDominationContext() |
151 | - |
152 | - dominated.supersede(dominant) |
153 | - flush_database_updates() |
154 | - |
155 | - dominated = self.checkBinaryPublication( |
156 | - dominated, PackagePublishingStatus.SUPERSEDED) |
157 | - self.assertEqual( |
158 | - dominated.supersededby, dominant.binarypackagerelease.build) |
159 | - self.checkPastDate(dominated.datesuperseded) |
160 | - |
161 | - def testBinaryDominationAssertsPendingOrPublished(self): |
162 | - """Test binary domination asserts coherent dominated status. |
163 | - |
164 | - Normally supersede() only accepts domination candidates in |
165 | - PUBLISHED or PENDING status, a exception is opened for architecture |
166 | - independent binaries because during the iteration they might have |
167 | - been already SUPERSEDED with its first publication, when it happens |
168 | - the candidate is skipped, i.e. it's not dominated again. |
169 | - |
170 | - (remembering the architecture independent binaries get superseded |
171 | - atomically) |
172 | - """ |
173 | - dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
174 | - |
175 | - [dominant_source, dominant, dominated_source, |
176 | - dominated] = self.createSimpleDominationContext() |
177 | - |
178 | - # Let's modify the domination candidate, so it will look wrong to |
179 | - # supersede() which will raise because it's a architecture |
180 | - # specific binary publication not in PENDING or PUBLISHED state. |
181 | - dominated.status = PackagePublishingStatus.SUPERSEDED |
182 | - manual_domination_date = datetime.datetime( |
183 | - 2006, 12, 25, tzinfo=pytz.timezone("UTC")) |
184 | - dominated.datesuperseded = manual_domination_date |
185 | - flush_database_updates() |
186 | - |
187 | - # An error like that in production clearly indicates that something |
188 | - # is wrong in the Dominator look-up methods. |
189 | - self.assertRaises( |
190 | - AssertionError, dominated.supersede, dominant) |
191 | - |
192 | - # The refused publishing record remains the same. |
193 | - dominated = self.checkBinaryPublication( |
194 | - dominated, PackagePublishingStatus.SUPERSEDED) |
195 | - self.assertEqual(dominated.datesuperseded, manual_domination_date) |
196 | - |
197 | - # Let's make it a architecture independent binary, so the domination |
198 | - # can be executed, but the record will be skipped. |
199 | - dominated.binarypackagerelease.architecturespecific = False |
200 | - flush_database_updates() |
201 | - |
202 | - dominated.supersede(dominant) |
203 | - flush_database_updates() |
204 | - dominated = self.checkBinaryPublication( |
205 | - dominated, PackagePublishingStatus.SUPERSEDED) |
206 | - self.assertEqual(dominated.datesuperseded, manual_domination_date) |
207 | - |
208 | - def testOtherBinaryPublications(self): |
209 | - """Check the basis of architecture independent binary domination. |
210 | - |
211 | - We use _getOtherPublications to identify other publications of the |
212 | - same binarypackagerelease in other architectures (architecture |
213 | - independent binaries), they will be dominated during a single step. |
214 | - |
215 | - See overall details in `testDominationOfOldArchIndepBinaries`. |
216 | - """ |
217 | - # Create architecture independent publications for foo-bin_1.0 |
218 | - # in i386 & hppa. |
219 | - pub_source_archindep = self.getPubSource( |
220 | - version='1.0', status=PackagePublishingStatus.PUBLISHED, |
221 | - architecturehintlist='all') |
222 | - pub_binaries_archindep = self.getPubBinaries( |
223 | - pub_source=pub_source_archindep, |
224 | - status=PackagePublishingStatus.PUBLISHED) |
225 | - [hppa_pub, i386_pub] = pub_binaries_archindep |
226 | - |
227 | - # We will also copy the binary publications to a PPA archive |
228 | - # to check if the lookup is indeed restricted to the dominated |
229 | - # archive. See bug #237845 for further information. |
230 | - cprov = getUtility(IPersonSet).getByName('cprov') |
231 | - i386_pub.copyTo( |
232 | - self.breezy_autotest, |
233 | - PackagePublishingPocket.RELEASE, |
234 | - cprov.archive) |
235 | - cprov_foo_binaries = cprov.archive.getAllPublishedBinaries(name='foo') |
236 | - self.assertEqual(cprov_foo_binaries.count(), 2) |
237 | - |
238 | - # Manually supersede the hppa binary. |
239 | - hppa_pub.status = PackagePublishingStatus.SUPERSEDED |
240 | - flush_database_updates() |
241 | - |
242 | - # Check if we can reach the i386 publication using |
243 | - # _getOtherBinaryPublications over the hppa binary. |
244 | - [found] = list(hppa_pub._getOtherPublications()) |
245 | - self.assertEqual(i386_pub, found) |
246 | - |
247 | - # Create architecture specific publications for foo-bin_1.1 in |
248 | - # i386 & hppa. |
249 | - pub_source_archdep = self.getPubSource( |
250 | - version='1.1', status=PackagePublishingStatus.PUBLISHED, |
251 | - architecturehintlist='any') |
252 | - pub_binaries_archdep = self.getPubBinaries( |
253 | - pub_source=pub_source_archdep) |
254 | - [hppa_pub, i386_pub] = pub_binaries_archdep |
255 | - |
256 | - # Manually supersede the hppa publication. |
257 | - hppa_pub.status = PackagePublishingStatus.SUPERSEDED |
258 | - flush_database_updates() |
259 | - |
260 | - # Check if there is no other publication of the hppa binary package |
261 | - # release. |
262 | - self.assertEqual( |
263 | - hppa_pub._getOtherPublications().count(), |
264 | - 0) |
265 | - |
266 | - def testDominationOfOldArchIndepBinaries(self): |
267 | - """Check domination of architecture independent binaries. |
268 | - |
269 | - When a architecture independent binary is dominated it should also |
270 | - 'carry' the same publications in other architectures independently |
271 | - of whether or not the new binary was successfully built to a specific |
272 | - architecture. |
273 | - |
274 | - See bug #48760 for further information about this aspect. |
275 | - """ |
276 | - publisher = Publisher( |
277 | - self.logger, self.config, self.disk_pool, |
278 | - self.ubuntutest.main_archive) |
279 | - |
280 | - # Create published archindep context. |
281 | - pub_source_archindep = self.getPubSource( |
282 | - version='1.0', status=PackagePublishingStatus.PUBLISHED, |
283 | - architecturehintlist='all') |
284 | - pub_binaries_archindep = self.getPubBinaries( |
285 | - pub_source=pub_source_archindep, |
286 | - status=PackagePublishingStatus.PUBLISHED) |
287 | - |
288 | - # Emulated new publication of a archdep binary only on i386. |
289 | - pub_source_archdep = self.getPubSource( |
290 | - version='1.1', architecturehintlist='i386') |
291 | - pub_binaries_archdep = self.getPubBinaries( |
292 | - pub_source=pub_source_archdep) |
293 | - |
294 | - publisher.A_publish(False) |
295 | - publisher.B_dominate(False) |
296 | - |
297 | - # The latest architecture specific source and binary pair is |
298 | - # PUBLISHED. |
299 | + self.checkPublication(dominated, PackagePublishingStatus.SUPERSEDED) |
300 | + self.assertEqual(dominated.supersededby, supersededby) |
301 | + self.checkPastDate(dominated.datesuperseded) |
302 | + |
303 | + def testManualSourceDomination(self): |
304 | + """Test source domination procedure.""" |
305 | + [dominant_source, dominant_binary, dominated_source, |
306 | + dominated_binary] = self.createSimpleDominationContext() |
307 | + |
308 | + self.dominateAndCheck( |
309 | + dominant_source, dominated_source, |
310 | + dominant_source.sourcepackagerelease) |
311 | + |
312 | + def testManualBinaryDomination(self): |
313 | + """Test binary domination procedure.""" |
314 | + [dominant_source, dominant, dominated_source, |
315 | + dominated] = self.createSimpleDominationContext() |
316 | + |
317 | + self.dominateAndCheck( |
318 | + dominant, dominated, dominant.binarypackagerelease.build) |
319 | + |
320 | + def testJudgeAndDominate(self): |
321 | + """Verify that judgeAndDominate correctly dominates everything.""" |
322 | + foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0') |
323 | + foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1') |
324 | + foo_12_source, foo_12_binaries = self.createSourceAndBinaries('1.2') |
325 | + |
326 | + dominator = Dominator(self.logger, foo_10_source.archive) |
327 | + dominator.judgeAndDominate( |
328 | + foo_10_source.distroseries, foo_10_source.pocket, self.config) |
329 | + |
330 | self.checkPublications( |
331 | - pub_source_archdep, pub_binaries_archdep, |
332 | + [foo_12_source] + foo_12_binaries, |
333 | PackagePublishingStatus.PUBLISHED) |
334 | - |
335 | - # The oldest architecture independent source & binaries should |
336 | - # be SUPERSEDED, i.e., the fact that new source version wasn't |
337 | - # built for hppa should not hold the condemned architecture |
338 | - # independent binary. |
339 | - self.checkPublications( |
340 | - pub_source_archindep, pub_binaries_archindep, |
341 | - PackagePublishingStatus.SUPERSEDED) |
342 | - |
343 | - def testDominationOnArchIndependentBinaryOverrides(self): |
344 | - """Check domination of architecture-independent overridden binaries. |
345 | - |
346 | - Due to the mechanism for performing atomic domination of arch-indep |
347 | - binaries (bug #48760) we were erroneously dominating binary override |
348 | - attempts (new pending publications of the same binary in different |
349 | - component/section). See bug #178102 for further information. |
350 | - """ |
351 | - publisher = Publisher( |
352 | - self.logger, self.config, self.disk_pool, |
353 | - self.ubuntutest.main_archive) |
354 | - |
355 | - # Create published archindep context. |
356 | - pub_source = self.getPubSource( |
357 | - version='1.0', status=PackagePublishingStatus.PUBLISHED, |
358 | - architecturehintlist='all') |
359 | - overridden_binaries = self.getPubBinaries( |
360 | - pub_source=pub_source, status=PackagePublishingStatus.PUBLISHED) |
361 | - |
362 | - # Committing the transaction here is required to guarantee sane |
363 | - # order in publisher queries. |
364 | - self.layer.commit() |
365 | - |
366 | - # Perform the binary override. |
367 | - universe = getUtility(IComponentSet)['universe'] |
368 | - pub_binaries = [] |
369 | - for pub in overridden_binaries: |
370 | - pub_binaries.append(pub.changeOverride(new_component=universe)) |
371 | - |
372 | - # Overrides are in DB. |
373 | - self.checkBinaryPublications( |
374 | - pub_binaries, PackagePublishingStatus.PENDING) |
375 | - |
376 | - # Publish and dominate them. |
377 | - publisher.A_publish(False) |
378 | - publisher.B_dominate(False) |
379 | - |
380 | - # The original binary publications are marked as SUPERSEDED and |
381 | - # the just-create overrides as preserved as PUBLISHED. |
382 | - self.checkBinaryPublications( |
383 | - overridden_binaries, PackagePublishingStatus.SUPERSEDED) |
384 | - |
385 | - self.checkBinaryPublications( |
386 | - pub_binaries, PackagePublishingStatus.PUBLISHED) |
387 | + self.checkPublications( |
388 | + [foo_11_source] + foo_11_binaries, |
389 | + PackagePublishingStatus.SUPERSEDED) |
390 | + self.checkPublications( |
391 | + [foo_10_source] + foo_10_binaries, |
392 | + PackagePublishingStatus.SUPERSEDED) |
393 | + |
394 | + def testEmptyDomination(self): |
395 | + """Domination asserts for not empty input list.""" |
396 | + dominator = Dominator(self.logger, self.ubuntutest.main_archive) |
397 | + pubs = {'foo': []} |
398 | + # This isn't a really good exception. It should probably be |
399 | + # something more indicative of bad input. |
400 | + self.assertRaises( |
401 | + AssertionError, dominator._dominatePublications, pubs) |
402 | |
403 | |
404 | class TestDomination(TestNativePublishingBase): |
405 | @@ -377,15 +151,15 @@ |
406 | # DELETED and OBSOLETED publications are set to be deleted |
407 | # immediately, whereas SUPERSEDED ones get a stay of execution |
408 | # according to the configuration. |
409 | - deleted_source = self.checkSourcePublication( |
410 | + self.checkPublication( |
411 | deleted_source, PackagePublishingStatus.DELETED) |
412 | self.checkPastDate(deleted_source.scheduleddeletiondate) |
413 | |
414 | - obsoleted_source = self.checkSourcePublication( |
415 | + self.checkPublication( |
416 | obsoleted_source, PackagePublishingStatus.OBSOLETE) |
417 | self.checkPastDate(deleted_source.scheduleddeletiondate) |
418 | |
419 | - superseded_source = self.checkSourcePublication( |
420 | + self.checkPublication( |
421 | superseded_source, PackagePublishingStatus.SUPERSEDED) |
422 | self.checkPastDate( |
423 | superseded_source.scheduleddeletiondate, |
424 | |
425 | === modified file 'lib/lp/archivepublisher/tests/test_publisher.py' |
426 | --- lib/lp/archivepublisher/tests/test_publisher.py 2010-07-21 14:14:54 +0000 |
427 | +++ lib/lp/archivepublisher/tests/test_publisher.py 2010-07-22 12:03:10 +0000 |
428 | @@ -1113,6 +1113,7 @@ |
429 | |
430 | def tearDown(self): |
431 | """Purge the archive root location. """ |
432 | + super(TestPublisherRepositorySignatures, self).tearDown() |
433 | if self.archive_publisher is not None: |
434 | shutil.rmtree(self.archive_publisher._config.distsroot) |
435 | |
436 | |
437 | === modified file 'lib/lp/soyuz/tests/test_publishing.py' |
438 | --- lib/lp/soyuz/tests/test_publishing.py 2010-07-21 14:14:54 +0000 |
439 | +++ lib/lp/soyuz/tests/test_publishing.py 2010-07-22 12:03:10 +0000 |
440 | @@ -9,7 +9,6 @@ |
441 | import shutil |
442 | from StringIO import StringIO |
443 | import tempfile |
444 | -import unittest |
445 | |
446 | import pytz |
447 | from zope.component import getUtility |
448 | @@ -457,16 +456,17 @@ |
449 | return source |
450 | |
451 | |
452 | -class TestNativePublishingBase(unittest.TestCase, SoyuzTestPublisher): |
453 | +class TestNativePublishingBase(TestCaseWithFactory, SoyuzTestPublisher): |
454 | layer = LaunchpadZopelessLayer |
455 | dbuser = config.archivepublisher.dbuser |
456 | |
457 | def __init__(self, methodName='runTest'): |
458 | - unittest.TestCase.__init__(self, methodName=methodName) |
459 | + super(TestNativePublishingBase, self).__init__(methodName=methodName) |
460 | SoyuzTestPublisher.__init__(self) |
461 | |
462 | def setUp(self): |
463 | """Setup a pool dir, the librarian, and instantiate the DiskPool.""" |
464 | + super(TestNativePublishingBase, self).setUp() |
465 | self.layer.switchDbUser(config.archivepublisher.dbuser) |
466 | self.prepareBreezyAutotest() |
467 | self.config = Config(self.ubuntutest) |
468 | @@ -480,6 +480,7 @@ |
469 | |
470 | def tearDown(self): |
471 | """Tear down blows the pool dir away.""" |
472 | + super(TestNativePublishingBase, self).tearDown() |
473 | shutil.rmtree(self.config.distroroot) |
474 | |
475 | def getPubSource(self, *args, **kwargs): |
476 | @@ -502,48 +503,19 @@ |
477 | self.layer.commit() |
478 | return binaries |
479 | |
480 | - def checkSourcePublication(self, source, status): |
481 | - """Assert the source publications has the given status. |
482 | - |
483 | - Retrieve an up-to-date record corresponding to the given publication, |
484 | - check and return it. |
485 | - """ |
486 | - fresh_source = SourcePackagePublishingHistory.get(source.id) |
487 | - self.assertEqual( |
488 | - fresh_source.status, status, "%s is not %s (%s)" % ( |
489 | - fresh_source.displayname, status.name, source.status.name)) |
490 | - return fresh_source |
491 | - |
492 | - def checkBinaryPublication(self, binary, status): |
493 | - """Assert the binary publication has the given status. |
494 | - |
495 | - Retrieve an up-to-date record corresponding to the given publication, |
496 | - check and return it. |
497 | - """ |
498 | - fresh_binary = BinaryPackagePublishingHistory.get(binary.id) |
499 | - self.assertEqual( |
500 | - fresh_binary.status, status, "%s is not %s (%s)" % ( |
501 | - fresh_binary.displayname, status.name, fresh_binary.status.name)) |
502 | - return fresh_binary |
503 | - |
504 | - def checkBinaryPublications(self, binaries, status): |
505 | - """Assert the binary publications have the given status. |
506 | - |
507 | - See `checkBinaryPublication`. |
508 | - """ |
509 | - fresh_binaries = [] |
510 | - for bin in binaries: |
511 | - bin = self.checkBinaryPublication(bin, status) |
512 | - fresh_binaries.append(bin) |
513 | - return fresh_binaries |
514 | - |
515 | - def checkPublications(self, source, binaries, status): |
516 | - """Assert source and binary publications have in the given status. |
517 | - |
518 | - See `checkSourcePublication` and `checkBinaryPublications`. |
519 | - """ |
520 | - self.checkSourcePublication(source, status) |
521 | - self.checkBinaryPublications(binaries, status) |
522 | + def checkPublication(self, pub, status): |
523 | + """Assert the publication has the given status.""" |
524 | + self.assertEqual( |
525 | + pub.status, status, "%s is not %s (%s)" % ( |
526 | + pub.displayname, status.name, pub.status.name)) |
527 | + |
528 | + def checkPublications(self, pubs, status): |
529 | + """Assert the given publications have the given status. |
530 | + |
531 | + See `checkPublication`. |
532 | + """ |
533 | + for pub in pubs: |
534 | + self.checkPublication(pub, status) |
535 | |
536 | def checkPastDate(self, date, lag=None): |
537 | """Assert given date is older than 'now'. |
538 | @@ -557,6 +529,19 @@ |
539 | limit = limit + lag |
540 | self.assertTrue(date < limit, "%s >= %s" % (date, limit)) |
541 | |
542 | + def checkSuperseded(self, pubs, supersededby=None): |
543 | + self.checkPublications(pubs, PackagePublishingStatus.SUPERSEDED) |
544 | + for pub in pubs: |
545 | + self.checkPastDate(pub.datesuperseded) |
546 | + if supersededby is not None: |
547 | + if isinstance(pub, BinaryPackagePublishingHistory): |
548 | + dominant = supersededby.binarypackagerelease.build |
549 | + else: |
550 | + dominant = supersededby.sourcepackagerelease |
551 | + self.assertEquals(dominant, pub.supersededby) |
552 | + else: |
553 | + self.assertIs(None, pub.supersededby) |
554 | + |
555 | |
556 | class TestNativePublishing(TestNativePublishingBase): |
557 | |
558 | @@ -815,7 +800,6 @@ |
559 | |
560 | # Adjust the binary package release original component. |
561 | universe = getUtility(IComponentSet)['universe'] |
562 | - from zope.security.proxy import removeSecurityProxy |
563 | removeSecurityProxy(binary.binarypackagerelease).component = universe |
564 | |
565 | self.copyAndCheck( |
566 | @@ -1025,3 +1009,174 @@ |
567 | record = self.publishing_set.getByIdAndArchive( |
568 | binary_publishing.id, wrong_archive, source=False) |
569 | self.assertEqual(None, record) |
570 | + |
571 | + |
572 | +class TestSourceDomination(TestNativePublishingBase): |
573 | + """Test SourcePackagePublishingHistory.supersede() operates correctly.""" |
574 | + |
575 | + def testSupersede(self): |
576 | + """Check that supersede() without arguments works.""" |
577 | + source = self.getPubSource() |
578 | + source.supersede() |
579 | + self.checkSuperseded([source]) |
580 | + |
581 | + def testSupersedeWithDominant(self): |
582 | + """Check that supersede() with a dominant publication works.""" |
583 | + source = self.getPubSource() |
584 | + super_source = self.getPubSource() |
585 | + source.supersede(super_source) |
586 | + self.checkSuperseded([source], super_source) |
587 | + |
588 | + def testSupersedingSupersededSourceFails(self): |
589 | + """Check that supersede() fails with a superseded source. |
590 | + |
591 | + Sources should not be superseded twice. If a second attempt is made, |
592 | + the Dominator's lookups are buggy. |
593 | + """ |
594 | + source = self.getPubSource() |
595 | + super_source = self.getPubSource() |
596 | + source.supersede(super_source) |
597 | + self.checkSuperseded([source], super_source) |
598 | + |
599 | + # Manually set a date in the past, so we can confirm that |
600 | + # the second supersede() fails properly. |
601 | + source.datesuperseded = datetime.datetime( |
602 | + 2006, 12, 25, tzinfo=pytz.timezone("UTC")) |
603 | + super_date = source.datesuperseded |
604 | + |
605 | + self.assertRaises(AssertionError, source.supersede, super_source) |
606 | + self.checkSuperseded([source], super_source) |
607 | + self.assertEquals(super_date, source.datesuperseded) |
608 | + |
609 | + |
610 | +class TestBinaryDomination(TestNativePublishingBase): |
611 | + """Test BinaryPackagePublishingHistory.supersede() operates correctly.""" |
612 | + |
613 | + def testSupersede(self): |
614 | + """Check that supersede() without arguments works.""" |
615 | + bins = self.getPubBinaries(architecturespecific=True) |
616 | + bins[0].supersede() |
617 | + self.checkSuperseded([bins[0]]) |
618 | + self.checkPublication(bins[1], PackagePublishingStatus.PENDING) |
619 | + |
620 | + def testSupersedeWithDominant(self): |
621 | + """Check that supersede() with a dominant publication works.""" |
622 | + bins = self.getPubBinaries(architecturespecific=True) |
623 | + super_bins = self.getPubBinaries(architecturespecific=True) |
624 | + bins[0].supersede(super_bins[0]) |
625 | + self.checkSuperseded([bins[0]], super_bins[0]) |
626 | + self.checkPublication(bins[1], PackagePublishingStatus.PENDING) |
627 | + |
628 | + def testSupersedesArchIndepBinariesAtomically(self): |
629 | + """Check that supersede() supersedes arch-indep binaries atomically. |
630 | + |
631 | + Architecture-independent binaries should be removed from all |
632 | + architectures when they are superseded on at least one (bug #48760). |
633 | + """ |
634 | + bins = self.getPubBinaries(architecturespecific=False) |
635 | + super_bins = self.getPubBinaries(architecturespecific=False) |
636 | + bins[0].supersede(super_bins[0]) |
637 | + self.checkSuperseded(bins, super_bins[0]) |
638 | + |
639 | + def testAtomicDominationRespectsOverrides(self): |
640 | + """Check that atomic domination only covers identical overrides. |
641 | + |
642 | + This is important, as otherwise newly-overridden arch-indep binaries |
643 | + will supersede themselves, and vanish entirely (bug #178102). |
644 | + """ |
645 | + bins = self.getPubBinaries(architecturespecific=False) |
646 | + |
647 | + universe = getUtility(IComponentSet)['universe'] |
648 | + super_bins = [] |
649 | + for bin in bins: |
650 | + super_bins.append(bin.changeOverride(new_component=universe)) |
651 | + |
652 | + bins[0].supersede(super_bins[0]) |
653 | + self.checkSuperseded(bins, super_bins[0]) |
654 | + self.checkPublications(super_bins, PackagePublishingStatus.PENDING) |
655 | + |
656 | + def testSupersedingSupersededArchSpecificBinaryFails(self): |
657 | + """Check that supersede() fails with a superseded arch-dep binary. |
658 | + |
659 | + Architecture-specific binaries should not normally be superseded |
660 | + twice. If a second attempt is made, the Dominator's lookups are buggy. |
661 | + """ |
662 | + bin = self.getPubBinaries(architecturespecific=True)[0] |
663 | + super_bin = self.getPubBinaries(architecturespecific=True)[0] |
664 | + bin.supersede(super_bin) |
665 | + |
666 | + # Manually set a date in the past, so we can confirm that |
667 | + # the second supersede() fails properly. |
668 | + bin.datesuperseded = datetime.datetime( |
669 | + 2006, 12, 25, tzinfo=pytz.timezone("UTC")) |
670 | + super_date = bin.datesuperseded |
671 | + |
672 | + self.assertRaises(AssertionError, bin.supersede, super_bin) |
673 | + self.checkSuperseded([bin], super_bin) |
674 | + self.assertEquals(super_date, bin.datesuperseded) |
675 | + |
676 | + def testSkipsSupersededArchIndependentBinary(self): |
677 | + """Check that supersede() skips a superseded arch-indep binary. |
678 | + |
679 | + Since all publications of an architecture-independent binary are |
680 | + superseded atomically, they may be superseded again later. In that |
681 | + case, we skip the domination, leaving the old date unchanged. |
682 | + """ |
683 | + bin = self.getPubBinaries(architecturespecific=False)[0] |
684 | + super_bin = self.getPubBinaries(architecturespecific=False)[0] |
685 | + bin.supersede(super_bin) |
686 | + self.checkSuperseded([bin], super_bin) |
687 | + |
688 | + # Manually set a date in the past, so we can confirm that |
689 | + # the second supersede() skips properly. |
690 | + bin.datesuperseded = datetime.datetime( |
691 | + 2006, 12, 25, tzinfo=pytz.timezone("UTC")) |
692 | + super_date = bin.datesuperseded |
693 | + |
694 | + bin.supersede(super_bin) |
695 | + self.checkSuperseded([bin], super_bin) |
696 | + self.assertEquals(super_date, bin.datesuperseded) |
697 | + |
698 | + |
699 | +class TestBinaryGetOtherPublications(TestNativePublishingBase): |
700 | + """Test BinaryPackagePublishingHistory._getOtherPublications() works.""" |
701 | + |
702 | + def checkOtherPublications(self, this, others): |
703 | + self.assertEquals( |
704 | + set(removeSecurityProxy(this)._getOtherPublications()), |
705 | + set(others)) |
706 | + |
707 | + def testFindsOtherArchIndepPublications(self): |
708 | + """Arch-indep publications with the same overrides should be found.""" |
709 | + bins = self.getPubBinaries(architecturespecific=False) |
710 | + self.checkOtherPublications(bins[0], bins) |
711 | + |
712 | + def testDoesntFindArchSpecificPublications(self): |
713 | + """Arch-dep publications shouldn't be found.""" |
714 | + bins = self.getPubBinaries(architecturespecific=True) |
715 | + self.checkOtherPublications(bins[0], [bins[0]]) |
716 | + |
717 | + def testDoesntFindPublicationsInOtherArchives(self): |
718 | + """Publications in other archives shouldn't be found.""" |
719 | + bins = self.getPubBinaries(architecturespecific=False) |
720 | + foreign_bins = bins[0].copyTo( |
721 | + bins[0].distroarchseries.distroseries, bins[0].pocket, |
722 | + self.factory.makeArchive()) |
723 | + self.checkOtherPublications(bins[0], bins) |
724 | + self.checkOtherPublications(foreign_bins[0], foreign_bins) |
725 | + |
726 | + def testDoesntFindPublicationsWithDifferentOverrides(self): |
727 | + """Publications with different overrides shouldn't be found.""" |
728 | + bins = self.getPubBinaries(architecturespecific=False) |
729 | + universe = getUtility(IComponentSet)['universe'] |
730 | + foreign_bin = bins[0].changeOverride(new_component=universe) |
731 | + self.checkOtherPublications(bins[0], bins) |
732 | + self.checkOtherPublications(foreign_bin, [foreign_bin]) |
733 | + |
734 | + def testDoesntFindSupersededPublications(self): |
735 | + """Superseded publications shouldn't be found.""" |
736 | + bins = self.getPubBinaries(architecturespecific=False) |
737 | + self.checkOtherPublications(bins[0], bins) |
738 | + # This will supersede both atomically. |
739 | + bins[0].supersede() |
740 | + self.checkOtherPublications(bins[0], []) |
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/.