~launchpad-pqm/launchpad/devel

13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.12 by Karl Fogel
Add the copyright header block to files under lib/lp/archivepublisher/
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
4
"""Tests for domination.py."""
3673.6.16 by Malcolm Cleaton
Addressed review comments
5
6
__metaclass__ = type
7
13850.2.13 by Jeroen Vermeulen
Reformat imports.
8
import datetime
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
9
from operator import attrgetter
14017.2.2 by Jeroen Vermeulen
Satisfy findPublishedSourcePackageNames tests; remove one that is now redundant (also failed because updated badly).
10
11
import apt_pkg
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
12
from testtools.matchers import LessThan
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
13
from zope.security.proxy import removeSecurityProxy
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
14
15
from lp.archivepublisher.domination import (
14220.2.9 by Jeroen Vermeulen
Create arch-specific-publications cache for 2nd-pass binary domination.
16
    ArchSpecificPublicationsCache,
14220.2.6 by Jeroen Vermeulen
Limit 2nd binary-domination pass to packages with arch-indep publications.
17
    contains_arch_indep,
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
18
    Dominator,
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
19
    find_live_binary_versions_pass_1,
20
    find_live_binary_versions_pass_2,
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
21
    find_live_source_versions,
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
22
    GeneralizedPublication,
23
    STAY_OF_EXECUTION,
24
    )
8426.7.1 by Julian Edwards
migrate archivepublisher to the lp tree.
25
from lp.archivepublisher.publishing import Publisher
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
26
from lp.registry.interfaces.pocket import PackagePublishingPocket
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
27
from lp.registry.interfaces.series import SeriesStatus
14606.3.1 by William Grant
Merge canonical.database into lp.services.database.
28
from lp.services.database.sqlbase import flush_database_updates
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
29
from lp.services.log.logger import DevNullLogger
14198.1.1 by Jeroen Vermeulen
Lint.
30
from lp.soyuz.enums import PackagePublishingStatus
13850.2.10 by Jeroen Vermeulen
Paving the way for gina source domination.
31
from lp.soyuz.interfaces.publishing import ISourcePackagePublishingHistory
8294.6.1 by Julian Edwards
First stab at code-reorg. Still got a discrepancy on stuff I assigned to registry but not migrated yet.
32
from lp.soyuz.tests.test_publishing import TestNativePublishingBase
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
33
from lp.testing import (
34
    StormStatementRecorder,
35
    TestCaseWithFactory,
36
    )
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
37
from lp.testing.fakemethod import FakeMethod
14606.3.1 by William Grant
Merge canonical.database into lp.services.database.
38
from lp.testing.layers import ZopelessDatabaseLayer
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
39
from lp.testing.matchers import HasQueryCount
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
40
41
42
class TestDominator(TestNativePublishingBase):
43
    """Test Dominator class."""
44
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
45
    def createSourceAndBinaries(self, version, with_debug=False,
46
                                archive=None):
11116.4.9 by William Grant
Add judgeAndDominate test.
47
        """Create a source and binaries with the given version."""
48
        source = self.getPubSource(
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
49
            version=version, archive=archive,
11116.4.9 by William Grant
Add judgeAndDominate test.
50
            status=PackagePublishingStatus.PUBLISHED)
51
        binaries = self.getPubBinaries(
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
52
            pub_source=source, with_debug=with_debug,
11116.4.9 by William Grant
Add judgeAndDominate test.
53
            status=PackagePublishingStatus.PUBLISHED)
54
        return (source, binaries)
55
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
56
    def createSimpleDominationContext(self):
57
        """Create simple domination context.
58
59
        Creates source and binary publications for:
60
61
         * Dominated: foo_1.0 & foo-bin_1.0_i386
62
         * Dominant: foo_1.1 & foo-bin_1.1_i386
63
7659.7.1 by Julian Edwards
Remove secure publishing records.
64
        Return the corresponding publication records as a 4-tuple:
5293.2.6 by Celso Providelo
more comments, r=sinzui.
65
66
         (dominant_source, dominant_binary, dominated_source,
67
          dominated_binary)
68
69
        Note that as an optimization the binaries list is already unpacked.
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
70
        """
11116.4.9 by William Grant
Add judgeAndDominate test.
71
        foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0')
72
        foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1')
11116.4.10 by William Grant
Merge checkBinaryPublication and checkSourcePublication; we no longer need to have the refreshing functionality, since S[SB]PPH are dead.
73
        return (foo_11_source, foo_11_binaries[0],
74
                foo_10_source, foo_10_binaries[0])
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
75
11116.4.12 by William Grant
Remove duplicated test code.
76
    def dominateAndCheck(self, dominant, dominated, supersededby):
13850.2.10 by Jeroen Vermeulen
Paving the way for gina source domination.
77
        generalization = GeneralizedPublication(
78
            is_source=ISourcePackagePublishingHistory.providedBy(dominant))
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
79
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
80
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
81
        pubs = [dominant, dominated]
82
        live_versions = [generalization.getPackageVersion(dominant)]
83
        dominator.dominatePackage(pubs, live_versions, generalization)
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
84
        flush_database_updates()
85
5293.2.6 by Celso Providelo
more comments, r=sinzui.
86
        # The dominant version remains correctly published.
11116.4.12 by William Grant
Remove duplicated test code.
87
        self.checkPublication(dominant, PackagePublishingStatus.PUBLISHED)
88
        self.assertTrue(dominant.supersededby is None)
89
        self.assertTrue(dominant.datesuperseded is None)
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
90
5293.2.6 by Celso Providelo
more comments, r=sinzui.
91
        # The dominated version is correctly dominated.
11116.4.12 by William Grant
Remove duplicated test code.
92
        self.checkPublication(dominated, PackagePublishingStatus.SUPERSEDED)
93
        self.assertEqual(dominated.supersededby, supersededby)
94
        self.checkPastDate(dominated.datesuperseded)
95
96
    def testManualSourceDomination(self):
97
        """Test source domination procedure."""
98
        [dominant_source, dominant_binary, dominated_source,
99
         dominated_binary] = self.createSimpleDominationContext()
100
101
        self.dominateAndCheck(
102
            dominant_source, dominated_source,
11116.4.10 by William Grant
Merge checkBinaryPublication and checkSourcePublication; we no longer need to have the refreshing functionality, since S[SB]PPH are dead.
103
            dominant_source.sourcepackagerelease)
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
104
11116.4.9 by William Grant
Add judgeAndDominate test.
105
    def testManualBinaryDomination(self):
106
        """Test binary domination procedure."""
5293.2.6 by Celso Providelo
more comments, r=sinzui.
107
        [dominant_source, dominant, dominated_source,
108
         dominated] = self.createSimpleDominationContext()
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
109
11116.4.12 by William Grant
Remove duplicated test code.
110
        self.dominateAndCheck(
111
            dominant, dominated, dominant.binarypackagerelease.build)
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
112
11116.4.9 by William Grant
Add judgeAndDominate test.
113
    def testJudgeAndDominate(self):
114
        """Verify that judgeAndDominate correctly dominates everything."""
115
        foo_10_source, foo_10_binaries = self.createSourceAndBinaries('1.0')
116
        foo_11_source, foo_11_binaries = self.createSourceAndBinaries('1.1')
117
        foo_12_source, foo_12_binaries = self.createSourceAndBinaries('1.2')
118
119
        dominator = Dominator(self.logger, foo_10_source.archive)
120
        dominator.judgeAndDominate(
7675.996.6 by William Grant
Remove stayofexecution from lucilleconfig. I invoke YAGNI and hardcode it to 5 days.
121
            foo_10_source.distroseries, foo_10_source.pocket)
11116.4.9 by William Grant
Add judgeAndDominate test.
122
123
        self.checkPublications(
11116.4.13 by William Grant
Fix lint.
124
            [foo_12_source] + foo_12_binaries,
125
            PackagePublishingStatus.PUBLISHED)
126
        self.checkPublications(
127
            [foo_11_source] + foo_11_binaries,
128
            PackagePublishingStatus.SUPERSEDED)
129
        self.checkPublications(
130
            [foo_10_source] + foo_10_binaries,
131
            PackagePublishingStatus.SUPERSEDED)
11116.4.9 by William Grant
Add judgeAndDominate test.
132
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
133
    def testJudgeAndDominateWithDDEBs(self):
134
        """Verify that judgeAndDominate ignores DDEBs correctly.
135
136
        DDEBs are superseded by their corresponding DEB publications, so they
137
        are forbidden from superseding publications (an attempt would result
138
        in an AssertionError), and shouldn't be directly considered for
139
        superseding either.
140
        """
7675.1039.9 by William Grant
Revert test DB user changes. We should grant those users the relevant permission instead.
141
        ppa = self.factory.makeArchive()
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
142
        foo_10_source, foo_10_binaries = self.createSourceAndBinaries(
143
            '1.0', with_debug=True, archive=ppa)
144
        foo_11_source, foo_11_binaries = self.createSourceAndBinaries(
145
            '1.1', with_debug=True, archive=ppa)
146
        foo_12_source, foo_12_binaries = self.createSourceAndBinaries(
147
            '1.2', with_debug=True, archive=ppa)
148
149
        dominator = Dominator(self.logger, ppa)
150
        dominator.judgeAndDominate(
7675.996.6 by William Grant
Remove stayofexecution from lucilleconfig. I invoke YAGNI and hardcode it to 5 days.
151
            foo_10_source.distroseries, foo_10_source.pocket)
7675.757.3 by William Grant
Dominator now excludes DDEBs from the candidate query, and a test has been added to verify that judgeAndDominate works over an archive with both DEBs and DDEBs.
152
153
        self.checkPublications(
154
            [foo_12_source] + foo_12_binaries,
155
            PackagePublishingStatus.PUBLISHED)
156
        self.checkPublications(
157
            [foo_11_source] + foo_11_binaries,
158
            PackagePublishingStatus.SUPERSEDED)
159
        self.checkPublications(
160
            [foo_10_source] + foo_10_binaries,
161
            PackagePublishingStatus.SUPERSEDED)
162
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
163
    def test_dominateBinaries_rejects_empty_publication_list(self):
164
        """Domination asserts for non-empty input list."""
165
        package = self.factory.makeBinaryPackageName()
166
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
167
        dominator._sortPackages = FakeMethod({package.name: []})
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
168
        # This isn't a really good exception. It should probably be
169
        # something more indicative of bad input.
170
        self.assertRaises(
171
            AssertionError,
172
            dominator.dominateBinaries,
173
            self.factory.makeDistroArchSeries().distroseries,
174
            self.factory.getAnyPocket())
175
176
    def test_dominateSources_rejects_empty_publication_list(self):
177
        """Domination asserts for non-empty input list."""
178
        package = self.factory.makeSourcePackageName()
179
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
180
        dominator._sortPackages = FakeMethod({package.name: []})
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
181
        # This isn't a really good exception. It should probably be
182
        # something more indicative of bad input.
183
        self.assertRaises(
184
            AssertionError,
185
            dominator.dominateSources,
186
            self.factory.makeDistroSeries(), self.factory.getAnyPocket())
11116.4.8 by William Grant
Reorder tests more sanely.
187
14090.3.21 by Julian Edwards
re-apply reverted qa-bad changes
188
    def test_archall_domination(self):
189
        # Arch-all binaries should not be dominated when a new source
190
        # version builds an updated arch-all binary, because slower builds
191
        # of other architectures will leave the previous version
192
        # uninstallable if they depend on the arch-all binary.
193
        # See https://bugs.launchpad.net/launchpad/+bug/34086
194
195
        # Set up a source, "foo" which builds "foo-bin" and foo-common
196
        # (which is arch-all).
197
        foo_10_src = self.getPubSource(
198
            sourcename="foo", version="1.0", architecturehintlist="i386",
199
            status=PackagePublishingStatus.PUBLISHED)
200
        [foo_10_i386_bin] = self.getPubBinaries(
201
            binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
202
            architecturespecific=True, version="1.0", pub_source=foo_10_src)
203
        [build] = foo_10_src.getBuilds()
204
        bpr = self.factory.makeBinaryPackageRelease(
205
            binarypackagename="foo-common", version="1.0", build=build,
206
            architecturespecific=False)
207
        foo_10_all_bins = self.publishBinaryInArchive(
208
            bpr, self.ubuntutest.main_archive, pocket=foo_10_src.pocket,
209
            status=PackagePublishingStatus.PUBLISHED)
210
211
        # Now, make version 1.1 of foo and add a foo-common but not foo-bin
212
        # (imagine that it's not finished building yet).
213
        foo_11_src = self.getPubSource(
214
            sourcename="foo", version="1.1", architecturehintlist="all",
215
            status=PackagePublishingStatus.PUBLISHED)
14198.1.1 by Jeroen Vermeulen
Lint.
216
        # Generate binary publications for architecture "all" (actually,
217
        # one such publication per architecture).
218
        self.getPubBinaries(
14090.3.21 by Julian Edwards
re-apply reverted qa-bad changes
219
            binaryname="foo-common", status=PackagePublishingStatus.PUBLISHED,
220
            architecturespecific=False, version="1.1", pub_source=foo_11_src)
221
222
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
223
        dominator.judgeAndDominate(
224
            foo_10_src.distroseries, foo_10_src.pocket)
225
226
        # The source will be superseded.
227
        self.checkPublication(foo_10_src, PackagePublishingStatus.SUPERSEDED)
228
        # The arch-specific has no dominant, so it's still published
229
        self.checkPublication(
230
            foo_10_i386_bin, PackagePublishingStatus.PUBLISHED)
231
        # The arch-indep has a dominant but must not be superseded yet
232
        # since the arch-specific is still published.
233
        self.checkPublications(
234
            foo_10_all_bins, PackagePublishingStatus.PUBLISHED)
235
236
        # Now creating a newer foo-bin should see those last two
237
        # publications superseded.
238
        [build2] = foo_11_src.getBuilds()
239
        foo_11_bin = self.factory.makeBinaryPackageRelease(
240
            binarypackagename="foo-bin", version="1.1", build=build2,
241
            architecturespecific=True)
242
        self.publishBinaryInArchive(
243
            foo_11_bin, self.ubuntutest.main_archive,
244
            pocket=foo_10_src.pocket,
245
            status=PackagePublishingStatus.PUBLISHED)
246
        dominator.judgeAndDominate(
247
            foo_10_src.distroseries, foo_10_src.pocket)
248
        self.checkPublication(
249
            foo_10_i386_bin, PackagePublishingStatus.SUPERSEDED)
250
        self.checkPublications(
251
            foo_10_all_bins, PackagePublishingStatus.SUPERSEDED)
252
14090.3.22 by Julian Edwards
Add failing tests for new corner cases.
253
    def test_any_superseded_by_all(self):
254
        # Set up a source, foo, which builds an architecture-dependent
255
        # binary, foo-bin.
256
        foo_10_src = self.getPubSource(
257
            sourcename="foo", version="1.0", architecturehintlist="i386",
258
            status=PackagePublishingStatus.PUBLISHED)
259
        [foo_10_i386_bin] = self.getPubBinaries(
260
            binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
261
            architecturespecific=True, version="1.0", pub_source=foo_10_src)
262
263
        # Now, make version 1.1 of foo, where foo-bin is now
264
        # architecture-independent.
265
        foo_11_src = self.getPubSource(
266
            sourcename="foo", version="1.1", architecturehintlist="all",
267
            status=PackagePublishingStatus.PUBLISHED)
268
        [foo_10_all_bin, foo_10_all_bin_2] = self.getPubBinaries(
269
            binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
270
            architecturespecific=False, version="1.1", pub_source=foo_11_src)
271
272
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
273
        dominator.judgeAndDominate(
274
            foo_10_src.distroseries, foo_10_src.pocket)
275
276
        # The source will be superseded.
277
        self.checkPublication(foo_10_src, PackagePublishingStatus.SUPERSEDED)
278
        # The arch-specific is superseded by the new arch-indep.
279
        self.checkPublication(
280
            foo_10_i386_bin, PackagePublishingStatus.SUPERSEDED)
281
282
    def test_schitzoid_package(self):
283
        # Test domination of a source that produces an arch-indep and an
284
        # arch-all, that then switches both on the next version to the
285
        # other arch type.
286
        foo_10_src = self.getPubSource(
287
            sourcename="foo", version="1.0", architecturehintlist="i386",
288
            status=PackagePublishingStatus.PUBLISHED)
289
        [foo_10_i386_bin] = self.getPubBinaries(
290
            binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
291
            architecturespecific=True, version="1.0", pub_source=foo_10_src)
292
        [build] = foo_10_src.getBuilds()
293
        bpr = self.factory.makeBinaryPackageRelease(
294
            binarypackagename="foo-common", version="1.0", build=build,
295
            architecturespecific=False)
296
        foo_10_all_bins = self.publishBinaryInArchive(
297
            bpr, self.ubuntutest.main_archive, pocket=foo_10_src.pocket,
298
            status=PackagePublishingStatus.PUBLISHED)
299
300
        foo_11_src = self.getPubSource(
301
            sourcename="foo", version="1.1", architecturehintlist="i386",
302
            status=PackagePublishingStatus.PUBLISHED)
303
        [foo_11_i386_bin] = self.getPubBinaries(
304
            binaryname="foo-common", status=PackagePublishingStatus.PUBLISHED,
305
            architecturespecific=True, version="1.1", pub_source=foo_11_src)
306
        [build] = foo_11_src.getBuilds()
307
        bpr = self.factory.makeBinaryPackageRelease(
308
            binarypackagename="foo-bin", version="1.1", build=build,
309
            architecturespecific=False)
14198.1.1 by Jeroen Vermeulen
Lint.
310
        # Generate binary publications for architecture "all" (actually,
311
        # one such publication per architecture).
312
        self.publishBinaryInArchive(
14090.3.22 by Julian Edwards
Add failing tests for new corner cases.
313
            bpr, self.ubuntutest.main_archive, pocket=foo_11_src.pocket,
314
            status=PackagePublishingStatus.PUBLISHED)
315
316
        dominator = Dominator(self.logger, self.ubuntutest.main_archive)
317
        dominator.judgeAndDominate(foo_10_src.distroseries, foo_10_src.pocket)
318
319
        self.checkPublications(foo_10_all_bins + [foo_10_i386_bin],
320
                               PackagePublishingStatus.SUPERSEDED)
321
322
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
323
class TestDomination(TestNativePublishingBase):
324
    """Test overall domination procedure."""
325
326
    def testCarefulDomination(self):
327
        """Test the careful domination procedure.
328
329
        Check if it works on a development series.
330
        A SUPERSEDED, DELETED or OBSOLETE published source should
331
        have its scheduleddeletiondate set.
332
        """
333
        publisher = Publisher(
334
            self.logger, self.config, self.disk_pool,
335
            self.ubuntutest.main_archive)
336
337
        superseded_source = self.getPubSource(
338
            status=PackagePublishingStatus.SUPERSEDED)
339
        self.assertTrue(superseded_source.scheduleddeletiondate is None)
340
        deleted_source = self.getPubSource(
341
            status=PackagePublishingStatus.DELETED)
342
        self.assertTrue(deleted_source.scheduleddeletiondate is None)
343
        obsoleted_source = self.getPubSource(
344
            status=PackagePublishingStatus.OBSOLETE)
345
        self.assertTrue(obsoleted_source.scheduleddeletiondate is None)
346
347
        publisher.B_dominate(True)
348
349
        # The publishing records will be scheduled for removal.
350
        # DELETED and OBSOLETED publications are set to be deleted
351
        # immediately, whereas SUPERSEDED ones get a stay of execution
352
        # according to the configuration.
11116.4.10 by William Grant
Merge checkBinaryPublication and checkSourcePublication; we no longer need to have the refreshing functionality, since S[SB]PPH are dead.
353
        self.checkPublication(
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
354
            deleted_source, PackagePublishingStatus.DELETED)
355
        self.checkPastDate(deleted_source.scheduleddeletiondate)
356
11116.4.10 by William Grant
Merge checkBinaryPublication and checkSourcePublication; we no longer need to have the refreshing functionality, since S[SB]PPH are dead.
357
        self.checkPublication(
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
358
            obsoleted_source, PackagePublishingStatus.OBSOLETE)
359
        self.checkPastDate(deleted_source.scheduleddeletiondate)
360
11116.4.10 by William Grant
Merge checkBinaryPublication and checkSourcePublication; we no longer need to have the refreshing functionality, since S[SB]PPH are dead.
361
        self.checkPublication(
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
362
            superseded_source, PackagePublishingStatus.SUPERSEDED)
363
        self.checkPastDate(
364
            superseded_source.scheduleddeletiondate,
7675.995.1 by William Grant
Hardcode stay of execution to one day. No more lucilleconfig here.
365
            lag=datetime.timedelta(days=STAY_OF_EXECUTION))
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
366
11149.5.1 by Jeroen Vermeulen
Test cruft in archivepublisher.
367
5293.2.5 by Celso Providelo
applying review comments, r=sinzui.
368
class TestDominationOfObsoletedSeries(TestDomination):
369
    """Replay domination tests upon a OBSOLETED distroseries."""
370
371
    def setUp(self):
372
        TestDomination.setUp(self)
373
        self.ubuntutest['breezy-autotest'].status = (
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
374
            SeriesStatus.OBSOLETE)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
375
376
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
377
def remove_security_proxies(proxied_objects):
378
    """Return list of `proxied_objects`, without their proxies.
379
380
    The dominator runs only in scripts, where security proxies don't get
381
    in the way.  To test realistically for this environment, strip the
382
    proxies wherever necessary and do as you will.
383
    """
384
    return [removeSecurityProxy(obj) for obj in proxied_objects]
385
386
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
387
def make_spphs_for_versions(factory, versions):
388
    """Create publication records for each of `versions`.
389
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
390
    All these publications will be in the same source package, archive,
391
    distroseries, and pocket.  They will all be in Published status.
392
393
    The records are created in the same order in which they are specified.
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
394
    Make the order irregular to prove that version ordering is not a
395
    coincidence of object creation order etc.
396
397
    Versions may also be identical; each publication record will still have
398
    its own package release.
399
    """
400
    spn = factory.makeSourcePackageName()
401
    distroseries = factory.makeDistroSeries()
402
    pocket = factory.getAnyPocket()
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
403
    archive = distroseries.main_archive
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
404
    sprs = [
405
        factory.makeSourcePackageRelease(
406
            sourcepackagename=spn, version=version)
407
        for version in versions]
408
    return [
409
        factory.makeSourcePackagePublishingHistory(
410
            distroseries=distroseries, pocket=pocket,
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
411
            sourcepackagerelease=spr, archive=archive,
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
412
            status=PackagePublishingStatus.PUBLISHED)
413
        for spr in sprs]
414
415
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
416
def make_bpphs_for_versions(factory, versions):
417
    """Create publication records for each of `versions`.
418
419
    All these publications will be in the same binary package, source
420
    package, archive, distroarchseries, and pocket.  They will all be in
421
    Published status.
422
    """
423
    bpn = factory.makeBinaryPackageName()
424
    spn = factory.makeSourcePackageName()
425
    das = factory.makeDistroArchSeries()
426
    archive = das.distroseries.main_archive
427
    pocket = factory.getAnyPocket()
428
    bprs = [
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
429
        factory.makeBinaryPackageRelease(
430
            binarypackagename=bpn, version=version)
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
431
        for version in versions]
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
432
    return remove_security_proxies([
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
433
        factory.makeBinaryPackagePublishingHistory(
434
            binarypackagerelease=bpr, binarypackagename=bpn,
435
            distroarchseries=das, pocket=pocket, archive=archive,
436
            sourcepackagename=spn, status=PackagePublishingStatus.PUBLISHED)
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
437
        for bpr in bprs])
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
438
439
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
440
def list_source_versions(spphs):
441
    """Extract the versions from `spphs` as a list, in the same order."""
442
    return [spph.sourcepackagerelease.version for spph in spphs]
443
444
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
445
def alter_creation_dates(spphs, ages):
446
    """Set `datecreated` on each of `spphs` according to `ages`.
447
448
    :param spphs: Iterable of `SourcePackagePublishingHistory`.  Their
449
        respective creation dates will be offset by the respective ages found
450
        in `ages` (with the two being matched up in the same order).
451
    :param ages: Iterable of ages.  Must provide the same number of items as
452
        `spphs`.  Ages are `timedelta` objects that will be subtracted from
453
        the creation dates on the respective records in `spph`.
454
    """
455
    for spph, age in zip(spphs, ages):
456
        spph.datecreated -= age
457
458
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
459
class TestGeneralizedPublication(TestCaseWithFactory):
460
    """Test publication generalization helpers."""
461
462
    layer = ZopelessDatabaseLayer
463
464
    def test_getPackageVersion_gets_source_version(self):
465
        spph = self.factory.makeSourcePackagePublishingHistory()
466
        self.assertEqual(
467
            spph.sourcepackagerelease.version,
468
            GeneralizedPublication(is_source=True).getPackageVersion(spph))
469
470
    def test_getPackageVersion_gets_binary_version(self):
471
        bpph = self.factory.makeBinaryPackagePublishingHistory()
472
        self.assertEqual(
473
            bpph.binarypackagerelease.version,
474
            GeneralizedPublication(is_source=False).getPackageVersion(bpph))
475
476
    def test_compare_sorts_versions(self):
477
        versions = [
478
            '1.1v2',
479
            '1.1v1',
480
            '1.1v3',
481
            ]
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
482
        spphs = make_spphs_for_versions(self.factory, versions)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
483
        sorted_spphs = sorted(spphs, cmp=GeneralizedPublication().compare)
484
        self.assertEqual(
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
485
            sorted(versions), list_source_versions(sorted_spphs))
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
486
487
    def test_compare_orders_versions_by_debian_rules(self):
488
        versions = [
489
            '1.1.0',
490
            '1.10',
491
            '1.1',
492
            '1.1ubuntu0',
493
            ]
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
494
        spphs = make_spphs_for_versions(self.factory, versions)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
495
14514.3.1 by Colin Watson
Port to new python-apt API.
496
        debian_sorted_versions = sorted(versions, cmp=apt_pkg.version_compare)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
497
498
        # Assumption: in this case, Debian version ordering is not the
499
        # same as alphabetical version ordering.
500
        self.assertNotEqual(sorted(versions), debian_sorted_versions)
501
502
        # The compare method produces the Debian ordering.
503
        sorted_spphs = sorted(spphs, cmp=GeneralizedPublication().compare)
504
        self.assertEqual(
14514.3.1 by Colin Watson
Port to new python-apt API.
505
            sorted(versions, cmp=apt_pkg.version_compare),
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
506
            list_source_versions(sorted_spphs))
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
507
508
    def test_compare_breaks_tie_with_creation_date(self):
509
        # When two publications are tied for comparison because they are
510
        # for the same package release, they are ordered by creation
511
        # date.
512
        distroseries = self.factory.makeDistroSeries()
513
        pocket = self.factory.getAnyPocket()
514
        spr = self.factory.makeSourcePackageRelease()
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
515
        ages = [
516
            datetime.timedelta(2),
517
            datetime.timedelta(1),
518
            datetime.timedelta(3),
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
519
            ]
520
        spphs = [
521
            self.factory.makeSourcePackagePublishingHistory(
522
                sourcepackagerelease=spr, distroseries=distroseries,
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
523
                pocket=pocket)
524
            for counter in xrange(len(ages))]
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
525
        alter_creation_dates(spphs, ages)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
526
527
        self.assertEqual(
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
528
            [spphs[2], spphs[0], spphs[1]],
529
            sorted(spphs, cmp=GeneralizedPublication().compare))
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
530
531
    def test_compare_breaks_tie_for_releases_with_same_version(self):
532
        # When two publications are tied for comparison because they
533
        # belong to releases with the same version string, they are
534
        # ordered by creation date.
535
        version = "1.%d" % self.factory.getUniqueInteger()
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
536
        ages = [
537
            datetime.timedelta(2),
538
            datetime.timedelta(1),
539
            datetime.timedelta(3),
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
540
            ]
541
        distroseries = self.factory.makeDistroSeries()
542
        pocket = self.factory.getAnyPocket()
543
        spphs = [
544
            self.factory.makeSourcePackagePublishingHistory(
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
545
                distroseries=distroseries, pocket=pocket,
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
546
                sourcepackagerelease=self.factory.makeSourcePackageRelease(
547
                    version=version))
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
548
            for counter in xrange(len(ages))]
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
549
        alter_creation_dates(spphs, ages)
13850.2.4 by Jeroen Vermeulen
Test GeneralizedPublication.
550
551
        self.assertEqual(
13850.2.5 by Jeroen Vermeulen
Test GeneralizedPublication.
552
            [spphs[2], spphs[0], spphs[1]],
553
            sorted(spphs, cmp=GeneralizedPublication().compare))
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
554
555
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
556
def jumble(ordered_list):
13850.2.27 by Jeroen Vermeulen
Typo.
557
    """Jumble the elements of `ordered_list` into a weird order.
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
558
559
    Ordering is very important in domination.  We jumble some of our lists to
560
    insure against "lucky coincidences" that might give our tests the right
561
    answers for the wrong reasons.
562
    """
563
    even = [
564
        item for offset, item in enumerate(ordered_list) if offset % 2 == 0]
565
    odd = [
566
        item for offset, item in enumerate(ordered_list) if offset % 2 != 0]
567
    return list(reversed(odd)) + even
568
569
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
570
class TestDominatorMethods(TestCaseWithFactory):
571
572
    layer = ZopelessDatabaseLayer
573
574
    def makeDominator(self, publications):
13850.2.17 by Jeroen Vermeulen
Support for new gina domination loop.
575
        """Create a `Dominator` suitable for `publications`."""
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
576
        if len(publications) == 0:
577
            archive = self.factory.makeArchive()
578
        else:
579
            archive = publications[0].archive
580
        return Dominator(DevNullLogger(), archive)
581
582
    def test_dominatePackage_survives_empty_publications_list(self):
583
        # Nothing explodes when dominatePackage is called with an empty
584
        # packages list.
585
        self.makeDominator([]).dominatePackage(
586
            [], [], GeneralizedPublication(True))
587
        # The test is that we get here without error.
588
        pass
589
590
    def test_dominatePackage_leaves_live_version_untouched(self):
591
        # dominatePackage does not supersede live versions.
592
        [pub] = make_spphs_for_versions(self.factory, ['3.1'])
593
        self.makeDominator([pub]).dominatePackage(
594
            [pub], ['3.1'], GeneralizedPublication(True))
595
        self.assertEqual(PackagePublishingStatus.PUBLISHED, pub.status)
596
597
    def test_dominatePackage_deletes_dead_version_without_successor(self):
598
        # dominatePackage marks non-live package versions without
599
        # superseding versions as deleted.
600
        [pub] = make_spphs_for_versions(self.factory, ['1.1'])
601
        self.makeDominator([pub]).dominatePackage(
602
            [pub], [], GeneralizedPublication(True))
603
        self.assertEqual(PackagePublishingStatus.DELETED, pub.status)
604
605
    def test_dominatePackage_supersedes_older_pub_with_newer_live_pub(self):
606
        # When marking a package as superseded, dominatePackage
607
        # designates a newer live version as the superseding version.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
608
        generalization = GeneralizedPublication(True)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
609
        pubs = make_spphs_for_versions(self.factory, ['1.0', '1.1'])
610
        self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
611
            generalization.sortPublications(pubs), ['1.1'], generalization)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
612
        self.assertEqual(PackagePublishingStatus.SUPERSEDED, pubs[0].status)
613
        self.assertEqual(pubs[1].sourcepackagerelease, pubs[0].supersededby)
614
        self.assertEqual(PackagePublishingStatus.PUBLISHED, pubs[1].status)
615
616
    def test_dominatePackage_only_supersedes_with_live_pub(self):
617
        # When marking a package as superseded, dominatePackage will
618
        # only pick a live version as the superseding one.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
619
        generalization = GeneralizedPublication(True)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
620
        pubs = make_spphs_for_versions(
621
            self.factory, ['1.0', '2.0', '3.0', '4.0'])
622
        self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
623
            generalization.sortPublications(pubs), ['3.0'], generalization)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
624
        self.assertEqual([
625
                pubs[2].sourcepackagerelease,
626
                pubs[2].sourcepackagerelease,
627
                None,
628
                None,
629
                ],
630
            [pub.supersededby for pub in pubs])
631
632
    def test_dominatePackage_supersedes_with_oldest_newer_live_pub(self):
633
        # When marking a package as superseded, dominatePackage picks
634
        # the oldest of the newer, live versions as the superseding one.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
635
        generalization = GeneralizedPublication(True)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
636
        pubs = make_spphs_for_versions(self.factory, ['2.7', '2.8', '2.9'])
637
        self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
638
            generalization.sortPublications(pubs), ['2.8', '2.9'],
639
            generalization)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
640
        self.assertEqual(pubs[1].sourcepackagerelease, pubs[0].supersededby)
641
642
    def test_dominatePackage_only_supersedes_with_newer_live_pub(self):
643
        # When marking a package as superseded, dominatePackage only
644
        # considers a newer version as the superseding one.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
645
        generalization = GeneralizedPublication(True)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
646
        pubs = make_spphs_for_versions(self.factory, ['0.1', '0.2'])
647
        self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
648
            generalization.sortPublications(pubs), ['0.1'], generalization)
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
649
        self.assertEqual(None, pubs[1].supersededby)
650
        self.assertEqual(PackagePublishingStatus.DELETED, pubs[1].status)
651
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
652
    def test_dominatePackage_supersedes_replaced_pub_for_live_version(self):
653
        # Even if a publication record is for a live version, a newer
654
        # one for the same version supersedes it.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
655
        generalization = GeneralizedPublication(True)
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
656
        spr = self.factory.makeSourcePackageRelease()
657
        series = self.factory.makeDistroSeries()
658
        pocket = PackagePublishingPocket.RELEASE
659
        pubs = [
660
            self.factory.makeSourcePackagePublishingHistory(
661
                archive=series.main_archive, distroseries=series,
662
                pocket=pocket, status=PackagePublishingStatus.PUBLISHED,
663
                sourcepackagerelease=spr)
664
            for counter in xrange(3)]
665
        alter_creation_dates(pubs, [
666
            datetime.timedelta(3),
667
            datetime.timedelta(2),
668
            datetime.timedelta(1),
669
            ])
670
671
        self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
672
            generalization.sortPublications(pubs), [spr.version],
673
            generalization)
13850.2.24 by Jeroen Vermeulen
A newer publication record for a live package versions supersedes older ones for the same versions.
674
        self.assertEqual([
675
            PackagePublishingStatus.SUPERSEDED,
676
            PackagePublishingStatus.SUPERSEDED,
677
            PackagePublishingStatus.PUBLISHED,
678
            ],
679
            [pub.status for pub in pubs])
680
        self.assertEqual(
681
            [spr, spr, None], [pub.supersededby for pub in pubs])
682
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
683
    def test_dominatePackage_is_efficient(self):
684
        # dominatePackage avoids issuing too many queries.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
685
        generalization = GeneralizedPublication(True)
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
686
        versions = ["1.%s" % revision for revision in xrange(5)]
687
        pubs = make_spphs_for_versions(self.factory, versions)
688
        with StormStatementRecorder() as recorder:
689
            self.makeDominator(pubs).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
690
                generalization.sortPublications(pubs), versions[2:-1],
691
                generalization)
14017.3.5 by Jeroen Vermeulen
As per review: add query-count test.
692
        self.assertThat(recorder, HasQueryCount(LessThan(5)))
693
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
694
    def test_dominatePackage_advanced_scenario(self):
695
        # Put dominatePackage through its paces with complex combined
696
        # data.
697
        # This test should be redundant in theory (which in theory
698
        # equates practice but in practice does not).  If this fails,
699
        # don't just patch up the code or this test.  Create unit tests
700
        # that specifically cover the difference, then change the code
701
        # and/or adapt this test to return to harmony.
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
702
        generalization = GeneralizedPublication(True)
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
703
        series = self.factory.makeDistroSeries()
704
        package = self.factory.makeSourcePackageName()
705
        pocket = PackagePublishingPocket.RELEASE
706
707
        versions = ["1.%d" % number for number in xrange(4)]
708
709
        # We have one package releases for each version.
710
        relevant_releases = dict(
711
            (version, self.factory.makeSourcePackageRelease(
712
                sourcepackagename=package, version=version))
713
            for version in jumble(versions))
714
715
        # Each of those releases is subsequently published in
716
        # different components.
717
        components = jumble(
718
            [self.factory.makeComponent() for version in versions])
719
720
        # Map versions to lists of publications for that version, from
721
        # oldest to newest.  Each re-publishing into a different
722
        # component is meant to supersede publication into the previous
723
        # component.
724
        pubs_by_version = dict(
725
            (version, [
726
                self.factory.makeSourcePackagePublishingHistory(
727
                    archive=series.main_archive, distroseries=series,
728
                    pocket=pocket, status=PackagePublishingStatus.PUBLISHED,
729
                    sourcepackagerelease=relevant_releases[version],
730
                    component=component)
731
                for component in components])
732
            for version in jumble(versions))
733
734
        ages = jumble(
735
            [datetime.timedelta(age) for age in xrange(len(versions))])
736
737
        # Actually the "oldest to newest" order on the publications only
738
        # applies to their creation dates.  Their creation orders are
739
        # irrelevant.
740
        for pubs_list in pubs_by_version.itervalues():
741
            alter_creation_dates(pubs_list, ages)
742
            pubs_list.sort(key=attrgetter('datecreated'))
743
744
        live_versions = ["1.1", "1.2"]
745
        last_version_alive = sorted(live_versions)[-1]
746
747
        all_pubs = sum(pubs_by_version.itervalues(), [])
748
        Dominator(DevNullLogger(), series.main_archive).dominatePackage(
14220.2.1 by Jeroen Vermeulen
Move special-casing for publication liveness out of domination loop; specialized and slimmed down binary passes.
749
            generalization.sortPublications(all_pubs), live_versions,
750
            generalization)
13850.2.25 by Jeroen Vermeulen
Test for desired behaviour, and add massive compound test as a catchall for complex bugs.
751
752
        for version in reversed(versions):
753
            pubs = pubs_by_version[version]
754
755
            if version in live_versions:
756
                # Beware: loop-carried variable.  Used locally as well,
757
                # but tells later iterations what the highest-versioned
758
                # release so far was.  This is used in tracking
759
                # supersededby links.
760
                superseding_release = pubs[-1].sourcepackagerelease
761
762
            if version in live_versions:
763
                # The live versions' latest publications are Published,
764
                # their older ones Superseded.
765
                expected_status = (
766
                    [PackagePublishingStatus.SUPERSEDED] * (len(pubs) - 1) +
767
                    [PackagePublishingStatus.PUBLISHED])
768
                expected_supersededby = (
769
                    [superseding_release] * (len(pubs) - 1) + [None])
770
            elif version < last_version_alive:
771
                # The superseded versions older than the last live
772
                # version have all been superseded.
773
                expected_status = (
774
                    [PackagePublishingStatus.SUPERSEDED] * len(pubs))
775
                expected_supersededby = [superseding_release] * len(pubs)
776
            else:
777
                # Versions that are newer than any live release have
778
                # been deleted.
779
                expected_status = (
780
                    [PackagePublishingStatus.DELETED] * len(pubs))
781
                expected_supersededby = [None] * len(pubs)
782
783
            self.assertEqual(expected_status, [pub.status for pub in pubs])
784
            self.assertEqual(
785
                expected_supersededby, [pub.supersededby for pub in pubs])
786
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
787
    def test_dominateSourceVersions_dominates_publications(self):
788
        # dominateSourceVersions finds the publications for a package
789
        # and calls dominatePackage on them.
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
790
        pubs = make_spphs_for_versions(self.factory, ['0.1', '0.2', '0.3'])
791
        package_name = pubs[0].sourcepackagerelease.sourcepackagename.name
792
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
793
        self.makeDominator(pubs).dominateSourceVersions(
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
794
            pubs[0].distroseries, pubs[0].pocket, package_name, ['0.2'])
795
        self.assertEqual([
796
                PackagePublishingStatus.SUPERSEDED,
797
                PackagePublishingStatus.PUBLISHED,
798
                PackagePublishingStatus.DELETED,
799
                ],
800
            [pub.status for pub in pubs])
801
        self.assertEqual(
802
            [pubs[1].sourcepackagerelease, None, None],
803
            [pub.supersededby for pub in pubs])
804
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
805
    def test_dominateSourceVersions_ignores_other_pockets(self):
806
        # dominateSourceVersions ignores publications in other pockets
807
        # than the one specified.
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
808
        pubs = make_spphs_for_versions(self.factory, ['2.3', '2.4'])
809
        package_name = pubs[0].sourcepackagerelease.sourcepackagename.name
810
        removeSecurityProxy(pubs[0]).pocket = PackagePublishingPocket.UPDATES
811
        removeSecurityProxy(pubs[1]).pocket = PackagePublishingPocket.PROPOSED
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
812
        self.makeDominator(pubs).dominateSourceVersions(
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
813
            pubs[0].distroseries, pubs[0].pocket, package_name, ['2.3'])
814
        self.assertEqual(PackagePublishingStatus.PUBLISHED, pubs[1].status)
815
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
816
    def test_dominateSourceVersions_ignores_other_packages(self):
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
817
        pubs = make_spphs_for_versions(self.factory, ['1.0', '1.1'])
818
        other_package_name = self.factory.makeSourcePackageName().name
14017.3.2 by Jeroen Vermeulen
Rename dominateRemovedSourceVersions; the name is no longer accurate.
819
        self.makeDominator(pubs).dominateSourceVersions(
13850.2.12 by Jeroen Vermeulen
Delete non-live versions without superseding versions.
820
            pubs[0].distroseries, pubs[0].pocket, other_package_name, ['1.1'])
821
        self.assertEqual(PackagePublishingStatus.PUBLISHED, pubs[0].status)
13850.2.17 by Jeroen Vermeulen
Support for new gina domination loop.
822
823
    def test_findPublishedSourcePackageNames_finds_package(self):
824
        spph = self.factory.makeSourcePackagePublishingHistory(
825
            status=PackagePublishingStatus.PUBLISHED)
826
        dominator = self.makeDominator([spph])
827
        self.assertContentEqual(
14017.2.1 by Jeroen Vermeulen
New meaning for findPublishedSourcePackageNames (test change).
828
            [(spph.sourcepackagerelease.sourcepackagename.name, 1)],
13850.2.17 by Jeroen Vermeulen
Support for new gina domination loop.
829
            dominator.findPublishedSourcePackageNames(
830
                spph.distroseries, spph.pocket))
831
832
    def test_findPublishedSourcePackageNames_ignores_other_states(self):
833
        series = self.factory.makeDistroSeries()
834
        pocket = PackagePublishingPocket.RELEASE
835
        spphs = dict(
836
            (status, self.factory.makeSourcePackagePublishingHistory(
837
                distroseries=series, archive=series.main_archive,
838
                pocket=pocket, status=status))
839
            for status in PackagePublishingStatus.items)
840
        published_spph = spphs[PackagePublishingStatus.PUBLISHED]
841
        dominator = self.makeDominator(spphs.values())
842
        self.assertContentEqual(
14017.2.1 by Jeroen Vermeulen
New meaning for findPublishedSourcePackageNames (test change).
843
            [(published_spph.sourcepackagerelease.sourcepackagename.name, 1)],
13850.2.17 by Jeroen Vermeulen
Support for new gina domination loop.
844
            dominator.findPublishedSourcePackageNames(series, pocket))
845
846
    def test_findPublishedSourcePackageNames_ignores_other_archives(self):
847
        spph = self.factory.makeSourcePackagePublishingHistory(
848
            status=PackagePublishingStatus.PUBLISHED)
849
        dominator = self.makeDominator([spph])
850
        dominator.archive = self.factory.makeArchive()
851
        self.assertContentEqual(
852
            [],
853
            dominator.findPublishedSourcePackageNames(
854
                spph.distroseries, spph.pocket))
855
856
    def test_findPublishedSourcePackageNames_ignores_other_series(self):
857
        spph = self.factory.makeSourcePackagePublishingHistory(
858
            status=PackagePublishingStatus.PUBLISHED)
859
        distro = spph.distroseries.distribution
860
        other_series = self.factory.makeDistroSeries(distribution=distro)
861
        dominator = self.makeDominator([spph])
862
        self.assertContentEqual(
863
            [],
864
            dominator.findPublishedSourcePackageNames(
865
                other_series, spph.pocket))
866
867
    def test_findPublishedSourcePackageNames_ignores_other_pockets(self):
868
        spph = self.factory.makeSourcePackagePublishingHistory(
869
            status=PackagePublishingStatus.PUBLISHED,
870
            pocket=PackagePublishingPocket.RELEASE)
871
        dominator = self.makeDominator([spph])
872
        self.assertContentEqual(
873
            [],
874
            dominator.findPublishedSourcePackageNames(
875
                spph.distroseries, PackagePublishingPocket.SECURITY))
876
14017.2.1 by Jeroen Vermeulen
New meaning for findPublishedSourcePackageNames (test change).
877
    def test_findPublishedSourcePackageNames_counts_published_SPPHs(self):
878
        series = self.factory.makeDistroSeries()
879
        pocket = PackagePublishingPocket.RELEASE
880
        spr = self.factory.makeSourcePackageRelease()
881
        spphs = [
882
            self.factory.makeSourcePackagePublishingHistory(
883
                distroseries=series, sourcepackagerelease=spr, pocket=pocket,
884
                status=PackagePublishingStatus.PUBLISHED)
885
            for counter in xrange(2)]
886
        dominator = self.makeDominator(spphs)
14017.3.3 by Jeroen Vermeulen
Slightly nicer test assertions.
887
        self.assertContentEqual(
888
            [(spr.sourcepackagename.name, len(spphs))],
889
            dominator.findPublishedSourcePackageNames(series, pocket))
14017.2.1 by Jeroen Vermeulen
New meaning for findPublishedSourcePackageNames (test change).
890
891
    def test_findPublishedSourcePackageNames_counts_no_other_state(self):
892
        series = self.factory.makeDistroSeries()
893
        pocket = PackagePublishingPocket.RELEASE
894
        spr = self.factory.makeSourcePackageRelease()
895
        spphs = [
896
            self.factory.makeSourcePackagePublishingHistory(
897
                distroseries=series, sourcepackagerelease=spr, pocket=pocket,
898
                status=status)
899
            for status in PackagePublishingStatus.items]
900
        dominator = self.makeDominator(spphs)
14017.3.3 by Jeroen Vermeulen
Slightly nicer test assertions.
901
        self.assertContentEqual(
902
            [(spr.sourcepackagename.name, 1)],
903
            dominator.findPublishedSourcePackageNames(series, pocket))
14017.2.1 by Jeroen Vermeulen
New meaning for findPublishedSourcePackageNames (test change).
904
13850.2.17 by Jeroen Vermeulen
Support for new gina domination loop.
905
    def test_findPublishedSPPHs_finds_published_SPPH(self):
906
        spph = self.factory.makeSourcePackagePublishingHistory(
907
            status=PackagePublishingStatus.PUBLISHED)
908
        package_name = spph.sourcepackagerelease.sourcepackagename.name
909
        dominator = self.makeDominator([spph])
910
        self.assertContentEqual(
911
            [spph],
912
            dominator.findPublishedSPPHs(
913
                spph.distroseries, spph.pocket, package_name))
914
915
    def test_findPublishedSPPHs_ignores_other_states(self):
916
        series = self.factory.makeDistroSeries()
917
        package = self.factory.makeSourcePackageName()
918
        pocket = PackagePublishingPocket.RELEASE
919
        spphs = dict(
920
            (status, self.factory.makeSourcePackagePublishingHistory(
921
                distroseries=series, archive=series.main_archive,
922
                pocket=pocket, status=status,
923
                sourcepackagerelease=self.factory.makeSourcePackageRelease(
924
                    sourcepackagename=package)))
925
            for status in PackagePublishingStatus.items)
926
        dominator = self.makeDominator(spphs.values())
927
        self.assertContentEqual(
928
            [spphs[PackagePublishingStatus.PUBLISHED]],
929
            dominator.findPublishedSPPHs(series, pocket, package.name))
930
931
    def test_findPublishedSPPHs_ignores_other_archives(self):
932
        spph = self.factory.makeSourcePackagePublishingHistory(
933
            status=PackagePublishingStatus.PUBLISHED)
934
        package = spph.sourcepackagerelease.sourcepackagename
935
        dominator = self.makeDominator([spph])
936
        dominator.archive = self.factory.makeArchive()
937
        self.assertContentEqual(
938
            [],
939
            dominator.findPublishedSPPHs(
940
                spph.distroseries, spph.pocket, package.name))
941
942
    def test_findPublishedSPPHs_ignores_other_series(self):
943
        spph = self.factory.makeSourcePackagePublishingHistory(
944
            status=PackagePublishingStatus.PUBLISHED)
945
        distro = spph.distroseries.distribution
946
        package = spph.sourcepackagerelease.sourcepackagename
947
        other_series = self.factory.makeDistroSeries(distribution=distro)
948
        dominator = self.makeDominator([spph])
949
        self.assertContentEqual(
950
            [],
951
            dominator.findPublishedSPPHs(
952
                other_series, spph.pocket, package.name))
953
954
    def test_findPublishedSPPHs_ignores_other_pockets(self):
955
        spph = self.factory.makeSourcePackagePublishingHistory(
956
            status=PackagePublishingStatus.PUBLISHED,
957
            pocket=PackagePublishingPocket.RELEASE)
958
        package = spph.sourcepackagerelease.sourcepackagename
959
        dominator = self.makeDominator([spph])
960
        self.assertContentEqual(
961
            [],
962
            dominator.findPublishedSPPHs(
963
                spph.distroseries, PackagePublishingPocket.SECURITY,
964
                package.name))
965
966
    def test_findPublishedSPPHs_ignores_other_packages(self):
967
        spph = self.factory.makeSourcePackagePublishingHistory(
968
            status=PackagePublishingStatus.PUBLISHED)
969
        other_package = self.factory.makeSourcePackageName()
970
        dominator = self.makeDominator([spph])
971
        self.assertContentEqual(
972
            [],
973
            dominator.findPublishedSPPHs(
974
                spph.distroseries, spph.pocket, other_package.name))
14220.1.5 by Jeroen Vermeulen
Extract finding of publications for domination.
975
976
    def test_findBinariesForDomination_finds_published_publications(self):
977
        bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
978
        dominator = self.makeDominator(bpphs)
979
        self.assertContentEqual(
980
            bpphs, dominator.findBinariesForDomination(
981
                bpphs[0].distroarchseries, bpphs[0].pocket))
982
983
    def test_findBinariesForDomination_skips_single_pub_packages(self):
984
        # The domination algorithm that uses findBinariesForDomination
985
        # always keeps the latest version live.  Thus, a single
986
        # publication isn't worth dominating.  findBinariesForDomination
987
        # won't return it.
988
        bpphs = make_bpphs_for_versions(self.factory, ['1.0'])
989
        dominator = self.makeDominator(bpphs)
990
        self.assertContentEqual(
991
            [], dominator.findBinariesForDomination(
992
                bpphs[0].distroarchseries, bpphs[0].pocket))
993
994
    def test_findBinariesForDomination_ignores_other_distroseries(self):
995
        bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
996
        dominator = self.makeDominator(bpphs)
997
        das = bpphs[0].distroarchseries
998
        other_series = self.factory.makeDistroSeries(
999
            distribution=das.distroseries.distribution)
1000
        other_das = self.factory.makeDistroArchSeries(
1001
            distroseries=other_series, architecturetag=das.architecturetag,
1002
            processorfamily=das.processorfamily)
1003
        self.assertContentEqual(
1004
            [], dominator.findBinariesForDomination(
1005
                other_das, bpphs[0].pocket))
1006
1007
    def test_findBinariesForDomination_ignores_other_architectures(self):
1008
        bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1009
        dominator = self.makeDominator(bpphs)
1010
        other_das = self.factory.makeDistroArchSeries(
1011
            distroseries=bpphs[0].distroseries)
1012
        self.assertContentEqual(
1013
            [], dominator.findBinariesForDomination(
1014
                other_das, bpphs[0].pocket))
1015
1016
    def test_findBinariesForDomination_ignores_other_archive(self):
1017
        bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1018
        dominator = self.makeDominator(bpphs)
1019
        dominator.archive = self.factory.makeArchive()
1020
        self.assertContentEqual(
1021
            [], dominator.findBinariesForDomination(
1022
                bpphs[0].distroarchseries, bpphs[0].pocket))
1023
1024
    def test_findBinariesForDomination_ignores_other_pocket(self):
1025
        bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1026
        dominator = self.makeDominator(bpphs)
1027
        for bpph in bpphs:
1028
            removeSecurityProxy(bpph).pocket = PackagePublishingPocket.UPDATES
1029
        self.assertContentEqual(
1030
            [], dominator.findBinariesForDomination(
1031
                bpphs[0].distroarchseries, PackagePublishingPocket.SECURITY))
1032
1033
    def test_findBinariesForDomination_ignores_other_status(self):
1034
        # If we have one BPPH for each possible status, plus one
1035
        # Published one to stop findBinariesForDomination from skipping
1036
        # the package, findBinariesForDomination returns only the
1037
        # Published ones.
1038
        versions = [
1039
            '1.%d' % self.factory.getUniqueInteger()
1040
            for status in PackagePublishingStatus.items] + ['0.9']
1041
        bpphs = make_bpphs_for_versions(self.factory, versions)
1042
        dominator = self.makeDominator(bpphs)
1043
1044
        for bpph, status in zip(bpphs, PackagePublishingStatus.items):
1045
            bpph.status = status
1046
1047
        # These are the Published publications.  The other ones will all
1048
        # be ignored.
1049
        published_bpphs = [
1050
            bpph
1051
            for bpph in bpphs
1052
                if bpph.status == PackagePublishingStatus.PUBLISHED]
1053
1054
        self.assertContentEqual(
1055
            published_bpphs,
1056
            dominator.findBinariesForDomination(
1057
                bpphs[0].distroarchseries, bpphs[0].pocket))
1058
1059
    def test_findSourcesForDomination_finds_published_publications(self):
1060
        spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1061
        dominator = self.makeDominator(spphs)
1062
        self.assertContentEqual(
1063
            spphs, dominator.findSourcesForDomination(
1064
                spphs[0].distroseries, spphs[0].pocket))
1065
1066
    def test_findSourcesForDomination_skips_single_pub_packages(self):
1067
        # The domination algorithm that uses findSourcesForDomination
1068
        # always keeps the latest version live.  Thus, a single
1069
        # publication isn't worth dominating.  findSourcesForDomination
1070
        # won't return it.
1071
        spphs = make_spphs_for_versions(self.factory, ['2.0'])
1072
        dominator = self.makeDominator(spphs)
1073
        self.assertContentEqual(
1074
            [], dominator.findSourcesForDomination(
1075
                spphs[0].distroseries, spphs[0].pocket))
1076
1077
    def test_findSourcesForDomination_ignores_other_distroseries(self):
1078
        spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1079
        dominator = self.makeDominator(spphs)
1080
        other_series = self.factory.makeDistroSeries(
1081
            distribution=spphs[0].distroseries.distribution)
1082
        self.assertContentEqual(
1083
            [], dominator.findSourcesForDomination(
1084
                other_series, spphs[0].pocket))
1085
1086
    def test_findSourcesForDomination_ignores_other_pocket(self):
1087
        spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1088
        dominator = self.makeDominator(spphs)
1089
        for spph in spphs:
1090
            removeSecurityProxy(spph).pocket = PackagePublishingPocket.UPDATES
1091
        self.assertContentEqual(
1092
            [], dominator.findSourcesForDomination(
1093
                spphs[0].distroseries, PackagePublishingPocket.SECURITY))
1094
1095
    def test_findSourcesForDomination_ignores_other_status(self):
1096
        versions = [
1097
            '1.%d' % self.factory.getUniqueInteger()
1098
            for status in PackagePublishingStatus.items] + ['0.9']
1099
        spphs = make_spphs_for_versions(self.factory, versions)
1100
        dominator = self.makeDominator(spphs)
1101
1102
        for spph, status in zip(spphs, PackagePublishingStatus.items):
1103
            spph.status = status
1104
1105
        # These are the Published publications.  The other ones will all
1106
        # be ignored.
1107
        published_spphs = [
1108
            spph
1109
            for spph in spphs
1110
                if spph.status == PackagePublishingStatus.PUBLISHED]
1111
1112
        self.assertContentEqual(
1113
            published_spphs,
1114
            dominator.findSourcesForDomination(
1115
                spphs[0].distroseries, spphs[0].pocket))
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1116
1117
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1118
def make_publications_arch_specific(pubs, arch_specific=True):
1119
    """Set the `architecturespecific` attribute for given SPPHs.
1120
1121
    :param pubs: An iterable of `BinaryPackagePublishingHistory`.
1122
    :param arch_specific: Whether the binary package releases published
1123
        by `pubs` are to be architecture-specific.  If not, they will be
1124
        treated as being for the "all" architecture.
1125
    """
1126
    for pub in pubs:
1127
        bpr = removeSecurityProxy(pub).binarypackagerelease
1128
        bpr.architecturespecific = arch_specific
1129
1130
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1131
class TestLivenessFunctions(TestCaseWithFactory):
1132
    """Tests for the functions that say which versions are live."""
1133
1134
    layer = ZopelessDatabaseLayer
1135
1136
    def test_find_live_source_versions_blesses_latest(self):
14220.3.1 by Jeroen Vermeulen
Review changes.
1137
        # find_live_source_versions, assuming that you passed it
1138
        # publications sorted from most current to least current
1139
        # version, simply returns the most current version.
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1140
        spphs = make_spphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1141
        self.assertEqual(['1.2'], find_live_source_versions(spphs))
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1142
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1143
    def test_find_live_binary_versions_pass_1_blesses_latest(self):
14220.3.1 by Jeroen Vermeulen
Review changes.
1144
        # find_live_binary_versions_pass_1 always includes the latest
1145
        # version among the input publications in its result.
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1146
        bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1147
        make_publications_arch_specific(bpphs)
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1148
        self.assertEqual(['1.2'], find_live_binary_versions_pass_1(bpphs))
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1149
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1150
    def test_find_live_binary_versions_pass_1_blesses_arch_all(self):
14220.3.1 by Jeroen Vermeulen
Review changes.
1151
        # find_live_binary_versions_pass_1 includes any
1152
        # architecture-independent publications among the input in its
1153
        # result.
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1154
        versions = list(reversed(['1.%d' % version for version in range(3)]))
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1155
        bpphs = make_bpphs_for_versions(self.factory, versions)
1156
1157
        # All of these publications are architecture-specific, except
1158
        # the last one.  This would happen if the binary package had
1159
        # just changed from being architecture-specific to being
1160
        # architecture-independent.
1161
        make_publications_arch_specific(bpphs, True)
1162
        make_publications_arch_specific(bpphs[-1:], False)
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1163
        self.assertEqual(
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1164
            versions[:1] + versions[-1:],
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1165
            find_live_binary_versions_pass_1(bpphs))
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1166
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1167
    def test_find_live_binary_versions_pass_2_blesses_latest(self):
14220.3.1 by Jeroen Vermeulen
Review changes.
1168
        # find_live_binary_versions_pass_2 always includes the latest
1169
        # version among the input publications in its result.
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1170
        bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1171
        make_publications_arch_specific(bpphs, False)
14220.2.10 by Jeroen Vermeulen
Review afterthought from earlier branch; pass cache to 2nd-pass binary domination liveness function.
1172
        cache = ArchSpecificPublicationsCache()
1173
        self.assertEqual(
1174
            ['1.2'], find_live_binary_versions_pass_2(bpphs, cache))
14220.2.2 by Jeroen Vermeulen
Initial tests of liveness functions; not passing yet.
1175
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1176
    def test_find_live_binary_versions_pass_2_blesses_arch_specific(self):
14220.3.1 by Jeroen Vermeulen
Review changes.
1177
        # find_live_binary_versions_pass_2 includes any
1178
        # architecture-specific publications among the input in its
1179
        # result.
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1180
        versions = list(reversed(['1.%d' % version for version in range(3)]))
1181
        bpphs = make_bpphs_for_versions(self.factory, versions)
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1182
        make_publications_arch_specific(bpphs)
14220.2.10 by Jeroen Vermeulen
Review afterthought from earlier branch; pass cache to 2nd-pass binary domination liveness function.
1183
        cache = ArchSpecificPublicationsCache()
1184
        self.assertEqual(
1185
            versions, find_live_binary_versions_pass_2(bpphs, cache))
14220.2.3 by Jeroen Vermeulen
Most liveness-function tests pass.
1186
14220.2.4 by Jeroen Vermeulen
Still working on tests. Shorter names for first-pass and second-pass liveness functions.
1187
    def test_find_live_binary_versions_pass_2_reprieves_arch_all(self):
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1188
        # An arch-all BPPH for a BPR built by an SPR that also still has
1189
        # active arch-dependent BPPHs gets a reprieve: it can't be
1190
        # superseded until those arch-dependent BPPHs have been
1191
        # superseded.
1192
        bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1193
        make_publications_arch_specific(bpphs, False)
1194
        dependent = self.factory.makeBinaryPackagePublishingHistory(
1195
            binarypackagerelease=bpphs[1].binarypackagerelease)
1196
        make_publications_arch_specific([dependent], True)
14220.2.10 by Jeroen Vermeulen
Review afterthought from earlier branch; pass cache to 2nd-pass binary domination liveness function.
1197
        cache = ArchSpecificPublicationsCache()
14220.2.5 by Jeroen Vermeulen
Successfully tested the binary-phase-2 arch-all domination reprieve.
1198
        self.assertEqual(
14220.2.10 by Jeroen Vermeulen
Review afterthought from earlier branch; pass cache to 2nd-pass binary domination liveness function.
1199
            ['1.2', '1.1'], find_live_binary_versions_pass_2(bpphs, cache))
14220.2.6 by Jeroen Vermeulen
Limit 2nd binary-domination pass to packages with arch-indep publications.
1200
1201
1202
class TestDominationHelpers(TestCaseWithFactory):
1203
    """Test lightweight helpers for the `Dominator`."""
1204
1205
    layer = ZopelessDatabaseLayer
1206
1207
    def test_contains_arch_indep_says_True_for_arch_indep(self):
1208
        bpphs = [self.factory.makeBinaryPackagePublishingHistory()]
1209
        make_publications_arch_specific(bpphs, False)
1210
        self.assertTrue(contains_arch_indep(bpphs))
1211
1212
    def test_contains_arch_indep_says_False_for_arch_specific(self):
1213
        bpphs = [self.factory.makeBinaryPackagePublishingHistory()]
1214
        make_publications_arch_specific(bpphs, True)
1215
        self.assertFalse(contains_arch_indep(bpphs))
1216
1217
    def test_contains_arch_indep_says_True_for_combination(self):
1218
        bpphs = make_bpphs_for_versions(self.factory, ['1.1', '1.0'])
1219
        make_publications_arch_specific(bpphs[:1], True)
1220
        make_publications_arch_specific(bpphs[1:], False)
1221
        self.assertTrue(contains_arch_indep(bpphs))
1222
1223
    def test_contains_arch_indep_says_False_for_empty_list(self):
1224
        self.assertFalse(contains_arch_indep([]))
14220.2.9 by Jeroen Vermeulen
Create arch-specific-publications cache for 2nd-pass binary domination.
1225
1226
1227
class TestArchSpecificPublicationsCache(TestCaseWithFactory):
1228
    """Tests for `ArchSpecificPublicationsCache`."""
1229
1230
    layer = ZopelessDatabaseLayer
1231
1232
    def makeCache(self):
1233
        """Shorthand: create a ArchSpecificPublicationsCache."""
1234
        return ArchSpecificPublicationsCache()
1235
1236
    def makeSPR(self):
1237
        """Create a `BinaryPackageRelease`."""
1238
        # Return an un-proxied SPR.  This is script code, so it won't be
1239
        # running into them in real life.
1240
        return removeSecurityProxy(self.factory.makeSourcePackageRelease())
1241
1242
    def makeBPPH(self, spr=None, arch_specific=True, archive=None,
1243
                 distroseries=None):
1244
        """Create a `BinaryPackagePublishingHistory`."""
1245
        if spr is None:
1246
            spr = self.makeSPR()
1247
        bpb = self.factory.makeBinaryPackageBuild(source_package_release=spr)
1248
        bpr = self.factory.makeBinaryPackageRelease(
1249
            build=bpb, architecturespecific=arch_specific)
1250
        das = self.factory.makeDistroArchSeries(distroseries=distroseries)
1251
        return removeSecurityProxy(
1252
            self.factory.makeBinaryPackagePublishingHistory(
1253
                binarypackagerelease=bpr, archive=archive,
1254
                distroarchseries=das, pocket=PackagePublishingPocket.UPDATES,
1255
                status=PackagePublishingStatus.PUBLISHED))
1256
1257
    def test_getKey_is_consistent_and_distinguishing(self):
1258
        # getKey consistently returns the same key for the same BPPH,
1259
        # but different keys for non-matching BPPHs.
1260
        bpphs = [
1261
            self.factory.makeBinaryPackagePublishingHistory()
1262
            for counter in range(2)]
1263
        cache = self.makeCache()
1264
        self.assertContentEqual(
1265
            [cache.getKey(bpph) for bpph in bpphs],
1266
            set(cache.getKey(bpph) for bpph in bpphs * 2))
1267
1268
    def test_hasArchSpecificPublications_is_consistent_and_correct(self):
14220.2.14 by Jeroen Vermeulen
Review changes.
1269
        # hasArchSpecificPublications consistently, repeatably returns
1270
        # the same result for the same key.  Naturally, different keys
1271
        # can still produce different results.
14220.2.9 by Jeroen Vermeulen
Create arch-specific-publications cache for 2nd-pass binary domination.
1272
        spr = self.makeSPR()
1273
        dependent = self.makeBPPH(spr, arch_specific=True)
1274
        bpph1 = self.makeBPPH(
1275
            spr, arch_specific=False, archive=dependent.archive,
1276
            distroseries=dependent.distroseries)
1277
        bpph2 = self.makeBPPH(arch_specific=False)
1278
        cache = self.makeCache()
1279
        self.assertEqual(
1280
            [True, True, False, False],
1281
            [
1282
                cache.hasArchSpecificPublications(bpph1),
1283
                cache.hasArchSpecificPublications(bpph1),
1284
                cache.hasArchSpecificPublications(bpph2),
1285
                cache.hasArchSpecificPublications(bpph2),
1286
            ])
1287
1288
    def test_hasArchSpecificPublications_caches_results(self):
1289
        # Results are cached, so once the presence of archive-specific
1290
        # publications has been looked up in the database, the query is
1291
        # not performed again for the same inputs.
1292
        spr = self.makeSPR()
1293
        self.makeBPPH(spr, arch_specific=True)
1294
        bpph = self.makeBPPH(spr, arch_specific=False)
1295
        cache = self.makeCache()
1296
        cache.hasArchSpecificPublications(bpph)
1297
        spr.getActiveArchSpecificPublications = FakeMethod()
1298
        cache.hasArchSpecificPublications(bpph)
1299
        self.assertEqual(0, spr.getActiveArchSpecificPublications.call_count)