Merge lp:~julian-edwards/launchpad/arch-all-domination-bug-34086 into lp:launchpad

Proposed by Julian Edwards
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 14169
Proposed branch: lp:~julian-edwards/launchpad/arch-all-domination-bug-34086
Merge into: lp:launchpad
Diff against target: 528 lines (+346/-60)
4 files modified
lib/lp/archivepublisher/domination.py (+52/-30)
lib/lp/archivepublisher/tests/test_dominator.py (+133/-30)
lib/lp/soyuz/model/publishing.py (+55/-0)
lib/lp/soyuz/tests/test_publishing.py (+106/-0)
To merge this branch: bzr merge lp:~julian-edwards/launchpad/arch-all-domination-bug-34086
Reviewer Review Type Date Requested Status
William Grant (community) code Approve
Review via email: mp+79675@code.launchpad.net

Commit message

[r=wgrant][bug=34086] Prevent superseding of arch-indep binaries until all binaries from the same source are all also superseded.

Description of the change

Fix problems discovered in the previous branch that was backed out where arch-indep and arch-specific binaries flip.

Since the last branch is being re-applied the diff is large. The actual changes are here: http://pastebin.ubuntu.com/711881/

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archivepublisher/domination.py'
2--- lib/lp/archivepublisher/domination.py 2011-10-18 02:09:38 +0000
3+++ lib/lp/archivepublisher/domination.py 2011-10-18 12:00:30 +0000
4@@ -153,6 +153,7 @@
5 class.
6 """
7 def __init__(self, is_source=True):
8+ self.is_source = is_source
9 if is_source:
10 self.traits = SourcePublicationTraits
11 else:
12@@ -204,6 +205,27 @@
13 self.logger = logger
14 self.archive = archive
15
16+ def _checkArchIndep(self, publication):
17+ """Return True if the binary publication can be superseded.
18+
19+ If the publication is an arch-indep binary, we can only supersede
20+ it if all the binaries from the same source are also superseded,
21+ else those binaries may become uninstallable.
22+ See bug 34086.
23+ """
24+ binary = publication.binarypackagerelease
25+ if not binary.architecturespecific:
26+ # getOtherPublicationsForSameSource returns PENDING in
27+ # addition to PUBLISHED binaries, and we rely on this since
28+ # they must also block domination.
29+ others = publication.getOtherPublicationsForSameSource()
30+ if others.any():
31+ # Don't dominate this arch:all binary as there are
32+ # other arch-specific binaries from the same build
33+ # that are still active.
34+ return False
35+ return True
36+
37 def dominatePackage(self, publications, live_versions, generalization):
38 """Dominate publications for a single package.
39
40@@ -260,7 +282,9 @@
41 pub.supersede(current_dominant, logger=self.logger)
42 self.logger.debug2(
43 "Superseding older publication for version %s.", version)
44- elif version in live_versions:
45+ elif (version in live_versions or
46+ (not generalization.is_source and
47+ not self._checkArchIndep(pub))):
48 # This publication stays active; if any publications
49 # that follow right after this are to be superseded,
50 # this is the release that they are superseded by.
51@@ -298,6 +322,7 @@
52 # one, this dominatePackage call will never result in a
53 # deletion.
54 latest_version = generalization.getPackageVersion(publications[0])
55+ self.logger.debug2("Dominating %s" % name)
56 self.dominatePackage(
57 publications, [latest_version], generalization)
58
59@@ -359,27 +384,6 @@
60
61 self.logger.debug("Beginning superseded processing...")
62
63- # XXX: dsilvers 2005-09-22 bug=55030:
64- # Need to make binaries go in groups but for now this'll do.
65- # An example of the concrete problem here is:
66- # - Upload foo-1.0, which builds foo and foo-common (arch all).
67- # - Upload foo-1.1, ditto.
68- # - foo-common-1.1 is built (along with the i386 binary for foo)
69- # - foo-common-1.0 is superseded
70- # Foo is now uninstallable on any architectures which don't yet
71- # have a build of foo-1.1, as the foo-common for foo-1.0 is gone.
72-
73- # Essentially we ideally don't want to lose superseded binaries
74- # unless the entire group is ready to be made pending removal.
75- # In this instance a group is defined as all the binaries from a
76- # given build. This assumes we've copied the arch_all binaries
77- # from whichever build provided them into each arch-specific build
78- # which we publish. If instead we simply publish the arch-all
79- # binaries from another build then instead we should scan up from
80- # the binary to its source, and then back from the source to each
81- # binary published in *this* distroarchseries for that source.
82- # if the binaries as a group (in that definition) are all superseded
83- # then we can consider them eligible for removal.
84 for pub_record in binary_records:
85 binpkg_release = pub_record.binarypackagerelease
86 self.logger.debug(
87@@ -450,19 +454,19 @@
88 generalization = GeneralizedPublication(is_source=False)
89
90 for distroarchseries in distroseries.architectures:
91- self.logger.debug(
92+ self.logger.info(
93 "Performing domination across %s/%s (%s)",
94 distroseries.name, pocket.title,
95 distroarchseries.architecturetag)
96
97- bpph_location_clauses = And(
98+ bpph_location_clauses = [
99 BinaryPackagePublishingHistory.status ==
100 PackagePublishingStatus.PUBLISHED,
101 BinaryPackagePublishingHistory.distroarchseries ==
102 distroarchseries,
103 BinaryPackagePublishingHistory.archive == self.archive,
104 BinaryPackagePublishingHistory.pocket == pocket,
105- )
106+ ]
107 candidate_binary_names = Select(
108 BinaryPackageName.id,
109 And(
110@@ -474,7 +478,7 @@
111 ),
112 group_by=BinaryPackageName.id,
113 having=Count(BinaryPackagePublishingHistory.id) > 1)
114- binaries = IStore(BinaryPackagePublishingHistory).find(
115+ main_clauses = [
116 BinaryPackagePublishingHistory,
117 BinaryPackageRelease.id ==
118 BinaryPackagePublishingHistory.binarypackagereleaseID,
119@@ -482,10 +486,28 @@
120 candidate_binary_names),
121 BinaryPackageRelease.binpackageformat !=
122 BinaryPackageFormat.DDEB,
123- bpph_location_clauses)
124- self.logger.debug("Dominating binaries...")
125- self._dominatePublications(
126- self._sortPackages(binaries, generalization), generalization)
127+ ]
128+ main_clauses.extend(bpph_location_clauses)
129+
130+ def do_domination(pass2_msg=""):
131+ msg = "binaries..." + pass2_msg
132+ self.logger.info("Finding %s" % msg)
133+ bins = IStore(
134+ BinaryPackagePublishingHistory).find(*main_clauses)
135+ self.logger.info("Dominating %s" % msg)
136+ sorted_packages = self._sortPackages(bins, generalization)
137+ self._dominatePublications(sorted_packages, generalization)
138+
139+ do_domination()
140+
141+ # We need to make a second pass to cover the cases where:
142+ # * arch-specific binaries were not all dominated before arch-all
143+ # ones that depend on them
144+ # * An arch-all turned into an arch-specific, or vice-versa
145+ # * A package is completely schizophrenic and changes all of
146+ # its binaries between arch-all and arch-any (apparently
147+ # occurs sometimes!)
148+ do_domination("(2nd pass)")
149
150 def _composeActiveSourcePubsCondition(self, distroseries, pocket):
151 """Compose ORM condition for restricting relevant source pubs."""
152
153=== modified file 'lib/lp/archivepublisher/tests/test_dominator.py'
154--- lib/lp/archivepublisher/tests/test_dominator.py 2011-10-18 02:20:28 +0000
155+++ lib/lp/archivepublisher/tests/test_dominator.py 2011-10-18 12:00:30 +0000
156@@ -23,7 +23,9 @@
157 from lp.registry.interfaces.pocket import PackagePublishingPocket
158 from lp.registry.interfaces.series import SeriesStatus
159 from lp.services.log.logger import DevNullLogger
160-from lp.soyuz.enums import PackagePublishingStatus
161+from lp.soyuz.enums import (
162+ PackagePublishingStatus,
163+ )
164 from lp.soyuz.interfaces.publishing import ISourcePackagePublishingHistory
165 from lp.soyuz.tests.test_publishing import TestNativePublishingBase
166 from lp.testing import (
167@@ -169,6 +171,136 @@
168 dominator._dominatePublications,
169 pubs, GeneralizedPublication(True))
170
171+ def test_archall_domination(self):
172+ # Arch-all binaries should not be dominated when a new source
173+ # version builds an updated arch-all binary, because slower builds
174+ # of other architectures will leave the previous version
175+ # uninstallable if they depend on the arch-all binary.
176+ # See https://bugs.launchpad.net/launchpad/+bug/34086
177+
178+ # Set up a source, "foo" which builds "foo-bin" and foo-common
179+ # (which is arch-all).
180+ foo_10_src = self.getPubSource(
181+ sourcename="foo", version="1.0", architecturehintlist="i386",
182+ status=PackagePublishingStatus.PUBLISHED)
183+ [foo_10_i386_bin] = self.getPubBinaries(
184+ binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
185+ architecturespecific=True, version="1.0", pub_source=foo_10_src)
186+ [build] = foo_10_src.getBuilds()
187+ bpr = self.factory.makeBinaryPackageRelease(
188+ binarypackagename="foo-common", version="1.0", build=build,
189+ architecturespecific=False)
190+ foo_10_all_bins = self.publishBinaryInArchive(
191+ bpr, self.ubuntutest.main_archive, pocket=foo_10_src.pocket,
192+ status=PackagePublishingStatus.PUBLISHED)
193+
194+ # Now, make version 1.1 of foo and add a foo-common but not foo-bin
195+ # (imagine that it's not finished building yet).
196+ foo_11_src = self.getPubSource(
197+ sourcename="foo", version="1.1", architecturehintlist="all",
198+ status=PackagePublishingStatus.PUBLISHED)
199+ foo_11_all_bins = self.getPubBinaries(
200+ binaryname="foo-common", status=PackagePublishingStatus.PUBLISHED,
201+ architecturespecific=False, version="1.1", pub_source=foo_11_src)
202+
203+ dominator = Dominator(self.logger, self.ubuntutest.main_archive)
204+ dominator.judgeAndDominate(
205+ foo_10_src.distroseries, foo_10_src.pocket)
206+
207+ # The source will be superseded.
208+ self.checkPublication(foo_10_src, PackagePublishingStatus.SUPERSEDED)
209+ # The arch-specific has no dominant, so it's still published
210+ self.checkPublication(
211+ foo_10_i386_bin, PackagePublishingStatus.PUBLISHED)
212+ # The arch-indep has a dominant but must not be superseded yet
213+ # since the arch-specific is still published.
214+ self.checkPublications(
215+ foo_10_all_bins, PackagePublishingStatus.PUBLISHED)
216+
217+ # Now creating a newer foo-bin should see those last two
218+ # publications superseded.
219+ [build2] = foo_11_src.getBuilds()
220+ foo_11_bin = self.factory.makeBinaryPackageRelease(
221+ binarypackagename="foo-bin", version="1.1", build=build2,
222+ architecturespecific=True)
223+ self.publishBinaryInArchive(
224+ foo_11_bin, self.ubuntutest.main_archive,
225+ pocket=foo_10_src.pocket,
226+ status=PackagePublishingStatus.PUBLISHED)
227+ dominator.judgeAndDominate(
228+ foo_10_src.distroseries, foo_10_src.pocket)
229+ self.checkPublication(
230+ foo_10_i386_bin, PackagePublishingStatus.SUPERSEDED)
231+ self.checkPublications(
232+ foo_10_all_bins, PackagePublishingStatus.SUPERSEDED)
233+
234+ def test_any_superseded_by_all(self):
235+ # Set up a source, foo, which builds an architecture-dependent
236+ # binary, foo-bin.
237+ foo_10_src = self.getPubSource(
238+ sourcename="foo", version="1.0", architecturehintlist="i386",
239+ status=PackagePublishingStatus.PUBLISHED)
240+ [foo_10_i386_bin] = self.getPubBinaries(
241+ binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
242+ architecturespecific=True, version="1.0", pub_source=foo_10_src)
243+
244+ # Now, make version 1.1 of foo, where foo-bin is now
245+ # architecture-independent.
246+ foo_11_src = self.getPubSource(
247+ sourcename="foo", version="1.1", architecturehintlist="all",
248+ status=PackagePublishingStatus.PUBLISHED)
249+ [foo_10_all_bin, foo_10_all_bin_2] = self.getPubBinaries(
250+ binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
251+ architecturespecific=False, version="1.1", pub_source=foo_11_src)
252+
253+ dominator = Dominator(self.logger, self.ubuntutest.main_archive)
254+ dominator.judgeAndDominate(
255+ foo_10_src.distroseries, foo_10_src.pocket)
256+
257+ # The source will be superseded.
258+ self.checkPublication(foo_10_src, PackagePublishingStatus.SUPERSEDED)
259+ # The arch-specific is superseded by the new arch-indep.
260+ self.checkPublication(
261+ foo_10_i386_bin, PackagePublishingStatus.SUPERSEDED)
262+
263+ def test_schitzoid_package(self):
264+ # Test domination of a source that produces an arch-indep and an
265+ # arch-all, that then switches both on the next version to the
266+ # other arch type.
267+ foo_10_src = self.getPubSource(
268+ sourcename="foo", version="1.0", architecturehintlist="i386",
269+ status=PackagePublishingStatus.PUBLISHED)
270+ [foo_10_i386_bin] = self.getPubBinaries(
271+ binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
272+ architecturespecific=True, version="1.0", pub_source=foo_10_src)
273+ [build] = foo_10_src.getBuilds()
274+ bpr = self.factory.makeBinaryPackageRelease(
275+ binarypackagename="foo-common", version="1.0", build=build,
276+ architecturespecific=False)
277+ foo_10_all_bins = self.publishBinaryInArchive(
278+ bpr, self.ubuntutest.main_archive, pocket=foo_10_src.pocket,
279+ status=PackagePublishingStatus.PUBLISHED)
280+
281+ foo_11_src = self.getPubSource(
282+ sourcename="foo", version="1.1", architecturehintlist="i386",
283+ status=PackagePublishingStatus.PUBLISHED)
284+ [foo_11_i386_bin] = self.getPubBinaries(
285+ binaryname="foo-common", status=PackagePublishingStatus.PUBLISHED,
286+ architecturespecific=True, version="1.1", pub_source=foo_11_src)
287+ [build] = foo_11_src.getBuilds()
288+ bpr = self.factory.makeBinaryPackageRelease(
289+ binarypackagename="foo-bin", version="1.1", build=build,
290+ architecturespecific=False)
291+ foo_11_all_bins = self.publishBinaryInArchive(
292+ bpr, self.ubuntutest.main_archive, pocket=foo_11_src.pocket,
293+ status=PackagePublishingStatus.PUBLISHED)
294+
295+ dominator = Dominator(self.logger, self.ubuntutest.main_archive)
296+ dominator.judgeAndDominate(foo_10_src.distroseries, foo_10_src.pocket)
297+
298+ self.checkPublications(foo_10_all_bins + [foo_10_i386_bin],
299+ PackagePublishingStatus.SUPERSEDED)
300+
301
302 class TestDomination(TestNativePublishingBase):
303 """Test overall domination procedure."""
304@@ -223,35 +355,6 @@
305 self.ubuntutest['breezy-autotest'].status = (
306 SeriesStatus.OBSOLETE)
307
308- def test_any_superseded_by_all(self):
309- # Set up a source, foo, which builds an architecture-dependent
310- # binary, foo-bin.
311- foo_10_src = self.getPubSource(
312- sourcename="foo", version="1.0", architecturehintlist="i386",
313- status=PackagePublishingStatus.PUBLISHED)
314- [foo_10_i386_bin] = self.getPubBinaries(
315- binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
316- architecturespecific=True, version="1.0", pub_source=foo_10_src)
317-
318- # Now, make version 1.1 of foo, where foo-bin is now
319- # architecture-independent.
320- foo_11_src = self.getPubSource(
321- sourcename="foo", version="1.1", architecturehintlist="all",
322- status=PackagePublishingStatus.PUBLISHED)
323- [foo_10_all_bin, foo_10_all_bin_2] = self.getPubBinaries(
324- binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
325- architecturespecific=False, version="1.1", pub_source=foo_11_src)
326-
327- dominator = Dominator(self.logger, self.ubuntutest.main_archive)
328- dominator.judgeAndDominate(
329- foo_10_src.distroseries, foo_10_src.pocket)
330-
331- # The source will be superseded.
332- self.checkPublication(foo_10_src, PackagePublishingStatus.SUPERSEDED)
333- # The arch-specific is superseded by the new arch-indep.
334- self.checkPublication(
335- foo_10_i386_bin, PackagePublishingStatus.SUPERSEDED)
336-
337
338 def make_spphs_for_versions(factory, versions):
339 """Create publication records for each of `versions`.
340
341=== modified file 'lib/lp/soyuz/model/publishing.py'
342--- lib/lp/soyuz/model/publishing.py 2011-10-18 02:09:38 +0000
343+++ lib/lp/soyuz/model/publishing.py 2011-10-18 12:00:30 +0000
344@@ -33,6 +33,7 @@
345 Desc,
346 LeftJoin,
347 Or,
348+ Select,
349 Sum,
350 )
351 from storm.store import Store
352@@ -1118,6 +1119,60 @@
353 section=self.section,
354 priority=self.priority)
355
356+ def getOtherPublicationsForSameSource(self, include_archindep=False):
357+ """Return all the other published or pending binaries for this
358+ source.
359+
360+ For example if source package foo builds:
361+ foo - i386
362+ foo - amd64
363+ foo-common - arch-all (published in i386 and amd64)
364+ then if this publication is the arch-all amd64, return foo(i386),
365+ foo(amd64). If include_archindep is True then also return
366+ foo-common (i386)
367+
368+ :param include_archindep: If True, return architecture independent
369+ publications too. Defaults to False.
370+
371+ :return: an iterable of `BinaryPackagePublishingHistory`
372+ """
373+ # Avoid circular wotsits.
374+ from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
375+ from lp.soyuz.model.distroarchseries import DistroArchSeries
376+ from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
377+ source_select = Select(
378+ SourcePackageRelease.id,
379+ And(
380+ BinaryPackageBuild.source_package_release_id ==
381+ SourcePackageRelease.id,
382+ BinaryPackageRelease.build == BinaryPackageBuild.id,
383+ self.binarypackagereleaseID == BinaryPackageRelease.id,
384+ ))
385+ pubs = [
386+ BinaryPackageBuild.source_package_release_id ==
387+ SourcePackageRelease.id,
388+ SourcePackageRelease.id.is_in(source_select),
389+ BinaryPackageRelease.build == BinaryPackageBuild.id,
390+ BinaryPackagePublishingHistory.binarypackagereleaseID ==
391+ BinaryPackageRelease.id,
392+ BinaryPackagePublishingHistory.archiveID == self.archive.id,
393+ BinaryPackagePublishingHistory.distroarchseriesID ==
394+ DistroArchSeries.id,
395+ DistroArchSeries.distroseriesID == self.distroseries.id,
396+ BinaryPackagePublishingHistory.pocket == self.pocket,
397+ BinaryPackagePublishingHistory.status.is_in(
398+ active_publishing_status),
399+ BinaryPackagePublishingHistory.id != self.id
400+ ]
401+
402+ if not include_archindep:
403+ pubs.append(BinaryPackageRelease.architecturespecific == True)
404+
405+ return IMasterStore(BinaryPackagePublishingHistory).find(
406+ BinaryPackagePublishingHistory,
407+ *pubs
408+ )
409+
410 def supersede(self, dominant=None, logger=None):
411 """See `IBinaryPackagePublishingHistory`."""
412 # At this point only PUBLISHED (ancient versions) or PENDING (
413
414=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
415--- lib/lp/soyuz/tests/test_publishing.py 2011-10-18 02:09:38 +0000
416+++ lib/lp/soyuz/tests/test_publishing.py 2011-10-18 12:00:30 +0000
417@@ -1471,6 +1471,112 @@
418 self.assertEquals(spph.ancestor.displayname, ancestor.displayname)
419
420
421+class TestGetOtherPublicationsForSameSource(TestNativePublishingBase):
422+ """Test parts of the BinaryPackagePublishingHistory model.
423+
424+ See also lib/lp/soyuz/doc/publishing.txt
425+ """
426+
427+ layer = LaunchpadZopelessLayer
428+
429+ def _makeMixedSingleBuildPackage(self, version="1.0"):
430+ # Set up a source with a build that generated four binaries,
431+ # two of them an arch-all.
432+ foo_src_pub = self.getPubSource(
433+ sourcename="foo", version=version, architecturehintlist="i386",
434+ status=PackagePublishingStatus.PUBLISHED)
435+ [foo_bin_pub] = self.getPubBinaries(
436+ binaryname="foo-bin", status=PackagePublishingStatus.PUBLISHED,
437+ architecturespecific=True, version=version,
438+ pub_source=foo_src_pub)
439+ # Now need to grab the build for the source so we can add
440+ # more binaries to it.
441+ [build] = foo_src_pub.getBuilds()
442+ foo_one_common = self.factory.makeBinaryPackageRelease(
443+ binarypackagename="foo-one-common", version=version, build=build,
444+ architecturespecific=False)
445+ foo_one_common_pubs = self.publishBinaryInArchive(
446+ foo_one_common, self.ubuntutest.main_archive,
447+ pocket=foo_src_pub.pocket,
448+ status=PackagePublishingStatus.PUBLISHED)
449+ foo_two_common = self.factory.makeBinaryPackageRelease(
450+ binarypackagename="foo-two-common", version=version, build=build,
451+ architecturespecific=False)
452+ foo_two_common_pubs = self.publishBinaryInArchive(
453+ foo_two_common, self.ubuntutest.main_archive,
454+ pocket=foo_src_pub.pocket,
455+ status=PackagePublishingStatus.PUBLISHED)
456+ foo_three = self.factory.makeBinaryPackageRelease(
457+ binarypackagename="foo-three", version=version, build=build,
458+ architecturespecific=True)
459+ [foo_three_pub] = self.publishBinaryInArchive(
460+ foo_three, self.ubuntutest.main_archive,
461+ pocket=foo_src_pub.pocket,
462+ status=PackagePublishingStatus.PUBLISHED)
463+ # So now we have source foo, which has arch specific binaries
464+ # foo-bin and foo-three, and arch:all binaries foo-one-common and
465+ # foo-two-common. The latter two will have multiple publications,
466+ # one for each DAS in the series.
467+ return (
468+ foo_src_pub, foo_bin_pub, foo_one_common_pubs,
469+ foo_two_common_pubs, foo_three_pub)
470+
471+ def test_getOtherPublicationsForSameSource(self):
472+ # By default getOtherPublicationsForSameSource should return all
473+ # of the other binaries built by the same source as the passed
474+ # binary publication, except the arch-indep ones.
475+ (foo_src_pub, foo_bin_pub, foo_one_common_pubs, foo_two_common_pubs,
476+ foo_three_pub) = self._makeMixedSingleBuildPackage()
477+
478+ foo_one_common_pub = foo_one_common_pubs[0]
479+ others = foo_one_common_pub.getOtherPublicationsForSameSource()
480+ others = list(others)
481+
482+ self.assertContentEqual([foo_three_pub, foo_bin_pub], others)
483+
484+ def test_getOtherPublicationsForSameSource_include_archindep(self):
485+ # Check that the arch-indep binaries are returned if requested.
486+ (foo_src_pub, foo_bin_pub, foo_one_common_pubs, foo_two_common_pubs,
487+ foo_three_pub) = self._makeMixedSingleBuildPackage()
488+
489+ foo_one_common_pub = foo_one_common_pubs[0]
490+ others = foo_one_common_pub.getOtherPublicationsForSameSource(
491+ include_archindep=True)
492+ others = list(others)
493+
494+ # We expect all publications created above to be returned,
495+ # except the one we use to call the method on.
496+ expected = [foo_three_pub, foo_bin_pub]
497+ expected.extend(foo_one_common_pubs[1:])
498+ expected.extend(foo_two_common_pubs)
499+ self.assertContentEqual(expected, others)
500+
501+ def test_getOtherPublicationsForSameSource_inactive(self):
502+ # Check that inactive publications are not returned.
503+ (foo_src_pub, foo_bin_pub, foo_one_common_pubs, foo_two_common_pubs,
504+ foo_three_pub) = self._makeMixedSingleBuildPackage()
505+ foo_bin_pub.status = PackagePublishingStatus.SUPERSEDED
506+ foo_three_pub.status = PackagePublishingStatus.SUPERSEDED
507+ foo_one_common_pub = foo_one_common_pubs[0]
508+ others = foo_one_common_pub.getOtherPublicationsForSameSource()
509+ others = list(others)
510+
511+ self.assertEqual(0, len(others))
512+
513+ def test_getOtherPublicationsForSameSource_multiple_versions(self):
514+ # Check that publications for only the same version as the
515+ # context binary publication are returned.
516+ (foo_src_pub, foo_bin_pub, foo_one_common_pubs, foo_two_common_pubs,
517+ foo_three_pub) = self._makeMixedSingleBuildPackage(version="1.0")
518+ self._makeMixedSingleBuildPackage(version="1.1")
519+
520+ foo_one_common_pub = foo_one_common_pubs[0]
521+ others = foo_one_common_pub.getOtherPublicationsForSameSource()
522+ others = list(others)
523+
524+ self.assertContentEqual([foo_three_pub, foo_bin_pub], others)
525+
526+
527 class TestGetBuiltBinaries(TestNativePublishingBase):
528 """Test SourcePackagePublishingHistory.getBuiltBinaries() works."""
529