158
160
[foo_10_source] + foo_10_binaries,
159
161
PackagePublishingStatus.SUPERSEDED)
161
def testEmptyDomination(self):
162
"""Domination asserts for not empty input list."""
163
dominator = Dominator(self.logger, self.ubuntutest.main_archive)
165
# This isn't a really good exception. It should probably be
166
# something more indicative of bad input.
169
dominator._dominatePublications,
170
pubs, GeneralizedPublication(True))
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)
167
dominator._sortPackages = FakeMethod({package.name: []})
168
# This isn't a really good exception. It should probably be
169
# something more indicative of bad input.
172
dominator.dominateBinaries,
173
self.factory.makeDistroArchSeries().distroseries,
174
self.factory.getAnyPocket())
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)
180
dominator._sortPackages = FakeMethod({package.name: []})
181
# This isn't a really good exception. It should probably be
182
# something more indicative of bad input.
185
dominator.dominateSources,
186
self.factory.makeDistroSeries(), self.factory.getAnyPocket())
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
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)
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)
216
# Generate binary publications for architecture "all" (actually,
217
# one such publication per architecture).
219
binaryname="foo-common", status=PackagePublishingStatus.PUBLISHED,
220
architecturespecific=False, version="1.1", pub_source=foo_11_src)
222
dominator = Dominator(self.logger, self.ubuntutest.main_archive)
223
dominator.judgeAndDominate(
224
foo_10_src.distroseries, foo_10_src.pocket)
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)
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)
253
def test_any_superseded_by_all(self):
254
# Set up a source, foo, which builds an architecture-dependent
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)
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)
272
dominator = Dominator(self.logger, self.ubuntutest.main_archive)
273
dominator.judgeAndDominate(
274
foo_10_src.distroseries, foo_10_src.pocket)
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)
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
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)
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)
310
# Generate binary publications for architecture "all" (actually,
311
# one such publication per architecture).
312
self.publishBinaryInArchive(
313
bpr, self.ubuntutest.main_archive, pocket=foo_11_src.pocket,
314
status=PackagePublishingStatus.PUBLISHED)
316
dominator = Dominator(self.logger, self.ubuntutest.main_archive)
317
dominator.judgeAndDominate(foo_10_src.distroseries, foo_10_src.pocket)
319
self.checkPublications(foo_10_all_bins + [foo_10_i386_bin],
320
PackagePublishingStatus.SUPERSEDED)
173
323
class TestDomination(TestNativePublishingBase):
788
986
dominator.findPublishedSPPHs(
789
987
spph.distroseries, spph.pocket, other_package.name))
989
def test_findBinariesForDomination_finds_published_publications(self):
990
bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
991
dominator = self.makeDominator(bpphs)
992
self.assertContentEqual(
993
bpphs, dominator.findBinariesForDomination(
994
bpphs[0].distroarchseries, bpphs[0].pocket))
996
def test_findBinariesForDomination_skips_single_pub_packages(self):
997
# The domination algorithm that uses findBinariesForDomination
998
# always keeps the latest version live. Thus, a single
999
# publication isn't worth dominating. findBinariesForDomination
1001
bpphs = make_bpphs_for_versions(self.factory, ['1.0'])
1002
dominator = self.makeDominator(bpphs)
1003
self.assertContentEqual(
1004
[], dominator.findBinariesForDomination(
1005
bpphs[0].distroarchseries, bpphs[0].pocket))
1007
def test_findBinariesForDomination_ignores_other_distroseries(self):
1008
bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1009
dominator = self.makeDominator(bpphs)
1010
das = bpphs[0].distroarchseries
1011
other_series = self.factory.makeDistroSeries(
1012
distribution=das.distroseries.distribution)
1013
other_das = self.factory.makeDistroArchSeries(
1014
distroseries=other_series, architecturetag=das.architecturetag,
1015
processorfamily=das.processorfamily)
1016
self.assertContentEqual(
1017
[], dominator.findBinariesForDomination(
1018
other_das, bpphs[0].pocket))
1020
def test_findBinariesForDomination_ignores_other_architectures(self):
1021
bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1022
dominator = self.makeDominator(bpphs)
1023
other_das = self.factory.makeDistroArchSeries(
1024
distroseries=bpphs[0].distroseries)
1025
self.assertContentEqual(
1026
[], dominator.findBinariesForDomination(
1027
other_das, bpphs[0].pocket))
1029
def test_findBinariesForDomination_ignores_other_archive(self):
1030
bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1031
dominator = self.makeDominator(bpphs)
1032
dominator.archive = self.factory.makeArchive()
1033
self.assertContentEqual(
1034
[], dominator.findBinariesForDomination(
1035
bpphs[0].distroarchseries, bpphs[0].pocket))
1037
def test_findBinariesForDomination_ignores_other_pocket(self):
1038
bpphs = make_bpphs_for_versions(self.factory, ['1.0', '1.1'])
1039
dominator = self.makeDominator(bpphs)
1041
removeSecurityProxy(bpph).pocket = PackagePublishingPocket.UPDATES
1042
self.assertContentEqual(
1043
[], dominator.findBinariesForDomination(
1044
bpphs[0].distroarchseries, PackagePublishingPocket.SECURITY))
1046
def test_findBinariesForDomination_ignores_other_status(self):
1047
# If we have one BPPH for each possible status, plus one
1048
# Published one to stop findBinariesForDomination from skipping
1049
# the package, findBinariesForDomination returns only the
1052
'1.%d' % self.factory.getUniqueInteger()
1053
for status in PackagePublishingStatus.items] + ['0.9']
1054
bpphs = make_bpphs_for_versions(self.factory, versions)
1055
dominator = self.makeDominator(bpphs)
1057
for bpph, status in zip(bpphs, PackagePublishingStatus.items):
1058
bpph.status = status
1060
# These are the Published publications. The other ones will all
1065
if bpph.status == PackagePublishingStatus.PUBLISHED]
1067
self.assertContentEqual(
1069
dominator.findBinariesForDomination(
1070
bpphs[0].distroarchseries, bpphs[0].pocket))
1072
def test_findSourcesForDomination_finds_published_publications(self):
1073
spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1074
dominator = self.makeDominator(spphs)
1075
self.assertContentEqual(
1076
spphs, dominator.findSourcesForDomination(
1077
spphs[0].distroseries, spphs[0].pocket))
1079
def test_findSourcesForDomination_skips_single_pub_packages(self):
1080
# The domination algorithm that uses findSourcesForDomination
1081
# always keeps the latest version live. Thus, a single
1082
# publication isn't worth dominating. findSourcesForDomination
1084
spphs = make_spphs_for_versions(self.factory, ['2.0'])
1085
dominator = self.makeDominator(spphs)
1086
self.assertContentEqual(
1087
[], dominator.findSourcesForDomination(
1088
spphs[0].distroseries, spphs[0].pocket))
1090
def test_findSourcesForDomination_ignores_other_distroseries(self):
1091
spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1092
dominator = self.makeDominator(spphs)
1093
other_series = self.factory.makeDistroSeries(
1094
distribution=spphs[0].distroseries.distribution)
1095
self.assertContentEqual(
1096
[], dominator.findSourcesForDomination(
1097
other_series, spphs[0].pocket))
1099
def test_findSourcesForDomination_ignores_other_pocket(self):
1100
spphs = make_spphs_for_versions(self.factory, ['2.0', '2.1'])
1101
dominator = self.makeDominator(spphs)
1103
removeSecurityProxy(spph).pocket = PackagePublishingPocket.UPDATES
1104
self.assertContentEqual(
1105
[], dominator.findSourcesForDomination(
1106
spphs[0].distroseries, PackagePublishingPocket.SECURITY))
1108
def test_findSourcesForDomination_ignores_other_status(self):
1110
'1.%d' % self.factory.getUniqueInteger()
1111
for status in PackagePublishingStatus.items] + ['0.9']
1112
spphs = make_spphs_for_versions(self.factory, versions)
1113
dominator = self.makeDominator(spphs)
1115
for spph, status in zip(spphs, PackagePublishingStatus.items):
1116
spph.status = status
1118
# These are the Published publications. The other ones will all
1123
if spph.status == PackagePublishingStatus.PUBLISHED]
1125
self.assertContentEqual(
1127
dominator.findSourcesForDomination(
1128
spphs[0].distroseries, spphs[0].pocket))
1131
def make_publications_arch_specific(pubs, arch_specific=True):
1132
"""Set the `architecturespecific` attribute for given SPPHs.
1134
:param pubs: An iterable of `BinaryPackagePublishingHistory`.
1135
:param arch_specific: Whether the binary package releases published
1136
by `pubs` are to be architecture-specific. If not, they will be
1137
treated as being for the "all" architecture.
1140
bpr = removeSecurityProxy(pub).binarypackagerelease
1141
bpr.architecturespecific = arch_specific
1144
class TestLivenessFunctions(TestCaseWithFactory):
1145
"""Tests for the functions that say which versions are live."""
1147
layer = ZopelessDatabaseLayer
1149
def test_find_live_source_versions_blesses_latest(self):
1150
# find_live_source_versions, assuming that you passed it
1151
# publications sorted from most current to least current
1152
# version, simply returns the most current version.
1153
spphs = make_spphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1154
self.assertEqual(['1.2'], find_live_source_versions(spphs))
1156
def test_find_live_binary_versions_pass_1_blesses_latest(self):
1157
# find_live_binary_versions_pass_1 always includes the latest
1158
# version among the input publications in its result.
1159
bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1160
make_publications_arch_specific(bpphs)
1161
self.assertEqual(['1.2'], find_live_binary_versions_pass_1(bpphs))
1163
def test_find_live_binary_versions_pass_1_blesses_arch_all(self):
1164
# find_live_binary_versions_pass_1 includes any
1165
# architecture-independent publications among the input in its
1167
versions = list(reversed(['1.%d' % version for version in range(3)]))
1168
bpphs = make_bpphs_for_versions(self.factory, versions)
1170
# All of these publications are architecture-specific, except
1171
# the last one. This would happen if the binary package had
1172
# just changed from being architecture-specific to being
1173
# architecture-independent.
1174
make_publications_arch_specific(bpphs, True)
1175
make_publications_arch_specific(bpphs[-1:], False)
1177
versions[:1] + versions[-1:],
1178
find_live_binary_versions_pass_1(bpphs))
1180
def test_find_live_binary_versions_pass_2_blesses_latest(self):
1181
# find_live_binary_versions_pass_2 always includes the latest
1182
# version among the input publications in its result.
1183
bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1184
make_publications_arch_specific(bpphs, False)
1185
cache = ArchSpecificPublicationsCache()
1187
['1.2'], find_live_binary_versions_pass_2(bpphs, cache))
1189
def test_find_live_binary_versions_pass_2_blesses_arch_specific(self):
1190
# find_live_binary_versions_pass_2 includes any
1191
# architecture-specific publications among the input in its
1193
versions = list(reversed(['1.%d' % version for version in range(3)]))
1194
bpphs = make_bpphs_for_versions(self.factory, versions)
1195
make_publications_arch_specific(bpphs)
1196
cache = ArchSpecificPublicationsCache()
1198
versions, find_live_binary_versions_pass_2(bpphs, cache))
1200
def test_find_live_binary_versions_pass_2_reprieves_arch_all(self):
1201
# An arch-all BPPH for a BPR built by an SPR that also still has
1202
# active arch-dependent BPPHs gets a reprieve: it can't be
1203
# superseded until those arch-dependent BPPHs have been
1205
bpphs = make_bpphs_for_versions(self.factory, ['1.2', '1.1', '1.0'])
1206
make_publications_arch_specific(bpphs, False)
1207
dependent = self.factory.makeBinaryPackagePublishingHistory(
1208
binarypackagerelease=bpphs[1].binarypackagerelease)
1209
make_publications_arch_specific([dependent], True)
1210
cache = ArchSpecificPublicationsCache()
1212
['1.2', '1.1'], find_live_binary_versions_pass_2(bpphs, cache))
1215
class TestDominationHelpers(TestCaseWithFactory):
1216
"""Test lightweight helpers for the `Dominator`."""
1218
layer = ZopelessDatabaseLayer
1220
def test_contains_arch_indep_says_True_for_arch_indep(self):
1221
bpphs = [self.factory.makeBinaryPackagePublishingHistory()]
1222
make_publications_arch_specific(bpphs, False)
1223
self.assertTrue(contains_arch_indep(bpphs))
1225
def test_contains_arch_indep_says_False_for_arch_specific(self):
1226
bpphs = [self.factory.makeBinaryPackagePublishingHistory()]
1227
make_publications_arch_specific(bpphs, True)
1228
self.assertFalse(contains_arch_indep(bpphs))
1230
def test_contains_arch_indep_says_True_for_combination(self):
1231
bpphs = make_bpphs_for_versions(self.factory, ['1.1', '1.0'])
1232
make_publications_arch_specific(bpphs[:1], True)
1233
make_publications_arch_specific(bpphs[1:], False)
1234
self.assertTrue(contains_arch_indep(bpphs))
1236
def test_contains_arch_indep_says_False_for_empty_list(self):
1237
self.assertFalse(contains_arch_indep([]))
1240
class TestArchSpecificPublicationsCache(TestCaseWithFactory):
1241
"""Tests for `ArchSpecificPublicationsCache`."""
1243
layer = ZopelessDatabaseLayer
1245
def makeCache(self):
1246
"""Shorthand: create a ArchSpecificPublicationsCache."""
1247
return ArchSpecificPublicationsCache()
1250
"""Create a `BinaryPackageRelease`."""
1251
# Return an un-proxied SPR. This is script code, so it won't be
1252
# running into them in real life.
1253
return removeSecurityProxy(self.factory.makeSourcePackageRelease())
1255
def makeBPPH(self, spr=None, arch_specific=True, archive=None,
1257
"""Create a `BinaryPackagePublishingHistory`."""
1259
spr = self.makeSPR()
1260
bpb = self.factory.makeBinaryPackageBuild(source_package_release=spr)
1261
bpr = self.factory.makeBinaryPackageRelease(
1262
build=bpb, architecturespecific=arch_specific)
1263
das = self.factory.makeDistroArchSeries(distroseries=distroseries)
1264
return removeSecurityProxy(
1265
self.factory.makeBinaryPackagePublishingHistory(
1266
binarypackagerelease=bpr, archive=archive,
1267
distroarchseries=das, pocket=PackagePublishingPocket.UPDATES,
1268
status=PackagePublishingStatus.PUBLISHED))
1270
def test_getKey_is_consistent_and_distinguishing(self):
1271
# getKey consistently returns the same key for the same BPPH,
1272
# but different keys for non-matching BPPHs.
1274
self.factory.makeBinaryPackagePublishingHistory()
1275
for counter in range(2)]
1276
cache = self.makeCache()
1277
self.assertContentEqual(
1278
[cache.getKey(bpph) for bpph in bpphs],
1279
set(cache.getKey(bpph) for bpph in bpphs * 2))
1281
def test_hasArchSpecificPublications_is_consistent_and_correct(self):
1282
# hasArchSpecificPublications consistently, repeatably returns
1283
# the same result for the same key. Naturally, different keys
1284
# can still produce different results.
1285
spr = self.makeSPR()
1286
dependent = self.makeBPPH(spr, arch_specific=True)
1287
bpph1 = self.makeBPPH(
1288
spr, arch_specific=False, archive=dependent.archive,
1289
distroseries=dependent.distroseries)
1290
bpph2 = self.makeBPPH(arch_specific=False)
1291
cache = self.makeCache()
1293
[True, True, False, False],
1295
cache.hasArchSpecificPublications(bpph1),
1296
cache.hasArchSpecificPublications(bpph1),
1297
cache.hasArchSpecificPublications(bpph2),
1298
cache.hasArchSpecificPublications(bpph2),
1301
def test_hasArchSpecificPublications_caches_results(self):
1302
# Results are cached, so once the presence of archive-specific
1303
# publications has been looked up in the database, the query is
1304
# not performed again for the same inputs.
1305
spr = self.makeSPR()
1306
self.makeBPPH(spr, arch_specific=True)
1307
bpph = self.makeBPPH(spr, arch_specific=False)
1308
cache = self.makeCache()
1309
cache.hasArchSpecificPublications(bpph)
1310
spr.getActiveArchSpecificPublications = FakeMethod()
1311
cache.hasArchSpecificPublications(bpph)
1312
self.assertEqual(0, spr.getActiveArchSpecificPublications.call_count)