← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-3 into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-3 into lp:launchpad with lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-2 as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bpb-currentcomponent-assertion-part-3/+merge/46209

This branch moves more of binarypackagebuild.txt into unit tests.
-- 
https://code.launchpad.net/~stevenk/launchpad/bpb-currentcomponent-assertion-part-3/+merge/46209
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-3 into lp:launchpad.
=== modified file 'lib/lp/soyuz/doc/binarypackagebuild.txt'
--- lib/lp/soyuz/doc/binarypackagebuild.txt	2011-01-13 23:24:21 +0000
+++ lib/lp/soyuz/doc/binarypackagebuild.txt	2011-01-13 23:24:29 +0000
@@ -1,446 +1,4 @@
-== The BuildSet Class ==
-
-The BuildSet class gives us some useful ways to consider the
-collection of builds.
-
-    >>> bs = getUtility(IBinaryPackageBuildSet)
-
-We can find builds given a source package release and architecture tag.
-
-    >>> i386_builds = bs.getBuildBySRAndArchtag(20, 'i386')
-    >>> i386_builds.count()
-    4
-
-IHasBuildRecords uses a base method provided by IBinaryPackageBuildSet,
-getBuildsByArchIds():
-
-It receives list of architectures IDs:
-
-    >>> hoary = ubuntu.getSeries('hoary')
-    >>> arch_ids = [arch.id for arch in hoary.architectures]
-    >>> bs.getBuildsByArchIds(ubuntu, arch_ids).count()
-    5
-
-It still working for empty list or None:
-
-    >>> bs.getBuildsByArchIds(ubuntu, []).count()
-    0
-
-    >>> bs.getBuildsByArchIds(ubuntu, None).count()
-    0
-
-Using build status, only the successfully built ones:
-
-    >>> bs.getBuildsByArchIds(ubuntu, arch_ids,
-    ...     status=BuildStatus.FULLYBUILT).count()
-    2
-
-Check the result content:
-
-    >>> [b.title for b in bs.getBuildsByArchIds(ubuntu, arch_ids,
-    ...     status=BuildStatus.FULLYBUILT)]
-    [u'i386 build of pmount 0.1-1 in ubuntu hoary RELEASE', u'hppa build
-    of pmount 0.1-1 in ubuntu hoary RELEASE']
-
-Using optional 'name' filter (matching with SQL LIKE %||filter||%)
-
-    >>> bs.getBuildsByArchIds(ubuntu, arch_ids,
-    ...     status=BuildStatus.FULLYBUILT,
-    ...     name='pmo').count()
-    2
-
-Checking optional 'pocket' restriction:
-
-    >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
-    >>> bs.getBuildsByArchIds(ubuntu, arch_ids,
-    ...     pocket=PackagePublishingPocket.UPDATES).count()
-    0
-
-    >>> bs.getBuildsByArchIds(ubuntu, arch_ids,
-    ...     pocket=PackagePublishingPocket.RELEASE).count()
-    5
-
-getBuildsByArchIds will also return builds for archives other than the
-primary archive.
-
-    >>> breezy = ubuntu.getSeries('breezy-autotest')
-    >>> arch_ids = [arch.id for arch in breezy.architectures]
-    >>> [(build.archive.purpose.name, build.title) for build in
-    ...    bs.getBuildsByArchIds(ubuntu, arch_ids, name='commercialpackage')]
-    [('PARTNER', u'i386 build of commercialpackage 1.0-1 in ubuntu breezy-autotest RELEASE')]
-
-`IBinaryPackageBuildSet` also provides getStatusSummaryForBuilds which
-summarizes the build status of a set of builds:
-
-First we'll define a helper to print the build summary:
-
-    >>> def print_build_summary(summary):
-    ...     print "%s\n%s\nRelevant builds:\n%s" % (
-    ...         summary['status'].title,
-    ...         summary['status'].description,
-    ...         "\n".join(
-    ...             " - %s" % build.title for build in summary['builds'])
-    ...     )
-
-    >>> build_summary = bs.getStatusSummaryForBuilds(i386_builds)
-    >>> print_build_summary(build_summary)
-    NEEDSBUILD
-    There are some builds waiting to be built.
-    Relevant builds:
-     - i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-
-The build set class furthermore provides a mechanism to load build-related
-data from the database for a given set of builds:
-
-    >>> from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
-    >>> from storm.expr import In
-    >>> from canonical.launchpad.webapp.interfaces import (
-    ...     IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
-    >>> store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
-    >>> results = list(store.find(
-    ...     BinaryPackageBuild, In(BinaryPackageBuild.id, (2,6,7,8))))
-    >>> rset = removeSecurityProxy(bs)._prefetchBuildData(results)
-    >>> def filename_or_none(item):
-    ...     if item is not None:
-    ...         return '%s' % item.filename
-    ...     else:
-    ...         return 'n/a'
-    >>> def id_or_none(item):
-    ...     if item is not None:
-    ...         return '%d' % item.id
-    ...     else:
-    ...         return 'n/a'
-    >>> def sort_result_key(row):
-    ...     return row[0].id
-    >>> for row in sorted(rset, key=sort_result_key):
-    ...     (sourcepackagerelease, buildlog,
-    ...      sourcepackagename, buildlog_content, builder,
-    ...      package_build, build_farm_job) = row
-    ...     print(
-    ...         'builder: %s, spr: %s, log: %s' %
-    ...         (id_or_none(builder),
-    ...          sourcepackagerelease.title, filename_or_none(buildlog)))
-    builder:   1, spr: mozilla-firefox - 0.9, log: netapplet-1.0.0.tar.gz
-    builder: n/a, spr: mozilla-firefox - 0.9, log: n/a
-    builder:   1, spr:        pmount - 0.1-1, log: netapplet-1.0.0.tar.gz
-    builder:   1, spr:          foobar - 1.0, log: netapplet-1.0.0.tar.gz
-
-
-== IHadBuildRecords.getBuildRecords() Implementations ==
-
-XXX: Michael Nelson 20090701 bug=394276
-The documentation for IHasBuildRecords is now in
-lp/soyuz/doc/hasbuildrecords.txt. The following implementation tests should
-be converted to unit-tests in lib/soyuz/tests/test_hasbuildrecords.py.
-
-We can find recent and pending builds for a given distrarchoseries.
-
-    >>> hoaryi386 = hoary['i386']
-    >>> hoaryi386.title
-    u'The Hoary Hedgehog Release for i386 (x86)'
-
-Exercises IHasBuildRecords abilities for distroarchseriess
-
-    >>> hoaryi386.getBuildRecords().count()
-    4
-
-    >>> hoaryi386.getBuildRecords(build_state=BuildStatus.FULLYBUILT).count()
-    1
-
-    >>> hoaryi386.getBuildRecords(name='pm').count()
-    1
-
-    >>> hoaryi386.getBuildRecords(
-    ...     pocket=PackagePublishingPocket.RELEASE).count()
-    4
-
-    >>> hoaryi386.getBuildRecords(
-    ...     pocket=PackagePublishingPocket.UPDATES).count()
-    0
-
-
-For SourcePackages, getBuildRecords() returns all build records
-published in its context (distroseries and distribution main
-archives), independent of their corresponding source publishing
-status.
-
-    >>> firefox = warty.getSourcePackage('mozilla-firefox')
-
-    >>> firefox.getBuildRecords().count()
-    8
-
-    >>> firefox.getBuildRecords(
-    ...     build_state=BuildStatus.FULLYBUILT).count()
-    6
-
-    >>> firefox.getBuildRecords(
-    ...     pocket=PackagePublishingPocket.RELEASE).count()
-    8
-
-    >>> firefox.getBuildRecords(
-    ...     pocket=PackagePublishingPocket.UPDATES).count()
-    0
-
-As mentioned above, SourcePackage.getBuildRecords() will return builds
-for packages that are no longer published. At first, there are no
-traces of the 'old-source' sourcepackage in ubuntutest/breezy-autotest
-
-    >>> ubuntutest = getUtility(IDistributionSet).getByName('ubuntutest')
-    >>> breezy_autotest = ubuntutest.getSeries('breezy-autotest')
-    >>> print breezy_autotest.getSourcePackage('old-source')
-    None
-
-Once the SourcePackage exists and has builds, they will be returned by
-getBuildRecords() ordered by descending creation date.
-
-    # Create a DELETED and a SUPERSEDED source publication in
-    # ubuntutest/breezy-autotest.
-    >>> from lp.soyuz.enums import PackagePublishingStatus
-    >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> old_source_pub = test_publisher.getPubSource(
-    ...     sourcename='old-source', version='1.0',
-    ...     status=PackagePublishingStatus.SUPERSEDED)
-    >>> [superseded_build] = old_source_pub.createMissingBuilds()
-    >>> deleted_source_pub = test_publisher.getPubSource(
-    ...     sourcename='old-source', version='1.1',
-    ...     status=PackagePublishingStatus.DELETED)
-    >>> [deleted_build] = deleted_source_pub.createMissingBuilds()
-    >>> login(ANONYMOUS)
-
-    >>> old_source_sp = breezy_autotest.getSourcePackage('old-source')
-    >>> old_source_builds = old_source_sp.getBuildRecords()
-    >>> [deleted_build, superseded_build] == list(old_source_builds)
-    True
-
-    >>> deleted_build.date_created > superseded_build.date_created
-    True
-
-Builds records for the exactly the same `SourcePackageRelease`s may
-exist in a rebuild archive context, but they do not 'leak' to the
-domain of SourcePackage.
-
-    # Create a rebuild archive, copy the 'old-source' source
-    # publications to it and create builds in the rebuild archive
-    # context.
-    >>> from lp.soyuz.enums import ArchivePurpose
-    >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> rebuild_archive = factory.makeArchive(
-    ...     ubuntutest, ubuntutest.owner, 'test-rebuild',
-    ...     ArchivePurpose.COPY)
-    >>> rebuild_old_pub = old_source_pub.copyTo(
-    ...     breezy_autotest, PackagePublishingPocket.RELEASE,
-    ...     rebuild_archive)
-    >>> [rebuild_old_build] = rebuild_old_pub.createMissingBuilds()
-    >>> rebuild_deleted_pub = deleted_source_pub.copyTo(
-    ...     breezy_autotest, PackagePublishingPocket.RELEASE,
-    ...     rebuild_archive)
-    >>> [rebuild_deleted_build] = rebuild_deleted_pub.createMissingBuilds()
-    >>> login(ANONYMOUS)
-
-    >>> rebuild_builds = rebuild_archive.getBuildRecords()
-    >>> [rebuild_deleted_build, rebuild_old_build] == list(rebuild_builds)
-    True
-
-    >>> old_source_sp.getBuildRecords().count()
-    2
-
-For a given distribution as well:
-
-    >>> ubuntu.getBuildRecords().count()
-    17
-
-    >>> builds = ubuntu.getBuildRecords(build_state=BuildStatus.FULLYBUILT)
-    >>> for build in builds:
-    ...     print build.date_finished, build.id, build.status.value
-    2007-08-10 00:00:14+00:00 30 1
-    2007-08-09 23:59:59+00:00 29 1
-    2005-03-25 00:00:03+00:00 7 1
-    2005-03-25 00:00:02+00:00 16 1
-    2005-03-25 00:00:01+00:00 19 1
-    2004-09-27 11:57:14+00:00 2 1
-    2004-09-27 11:57:13+00:00 18 1
-
-Retrieve the current PENDING builds
-
-    >>> builds = ubuntu.getBuildRecords(build_state=BuildStatus.NEEDSBUILD)
-    >>> builds.count()
-    2
-
-Note, by ordering the build by BuildQueue.lastscore, it already notice
-the existence of a new pending build, since retry already creates a
-new BuildQueue record:
-
-    >>> builds = ubuntu.getBuildRecords(build_state=BuildStatus.NEEDSBUILD)
-    >>> builds.count()
-    2
-
-Note that they are ordered by DESC lastscore, as expected:
-
-    >>> for b in builds:
-    ...     b.id, b.status.value, b.buildqueue_record.lastscore
-    (9, 0, 2505)
-    (11, 0, 10)
-
-Define a helper function to print out build details.
-
-    >>> def print_build_details(builds):
-    ...     for build in builds:
-    ...         if build.archive.owner:
-    ...             print "%s: %s" % (build.archive.owner.name, build.title)
-    ...         else:
-    ...             print "main: %s" % (build.title)
-
-Using the optional name argument to filter build results:
-
-    >>> builds = ubuntu.getBuildRecords(name='pm')
-    >>> builds.count()
-    4
-    >>> print_build_details(builds)
-    ubuntu-team: i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of pmount 0.1-1 in ubuntu breezy-autotest RELEASE
-    ubuntu-team: hppa build of pmount 0.1-1 in ubuntu hoary RELEASE
-    ubuntu-team: i386 build of pmount 0.1-1 in ubuntu hoary RELEASE
-
-or using optional pocket argument:
-
-    >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
-
-    >>> ubuntu.getBuildRecords(
-    ...    build_state=BuildStatus.NEEDSBUILD,
-    ...    pocket=PackagePublishingPocket.RELEASE).count()
-    2
-
-    >>> ubuntu.getBuildRecords(
-    ...    build_state=BuildStatus.NEEDSBUILD,
-    ...    pocket=PackagePublishingPocket.SECURITY).count()
-    0
-
-IHasBuildRecords is implemented by Builder.  It can filter on build state
-and name.  A user can also be passed for security checks on private builds;
-if user is not passed then the query runs anonymously which means private
-builds are excluded from anything returned.
-
-Log in as admin to avoid security on IBinaryPackageBuild for the moment.
-
-    >>> login('foo.bar@xxxxxxxxxxxxx')
-
-Let's create a private PPA for cprov (and hence its builds become private):
-
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> cprov = removeSecurityProxy(getUtility(IPersonSet).getByName('cprov'))
-    >>> cprov_private_ppa = factory.makeArchive(
-    ...     owner=cprov, private=True, name='p3a',
-    ...     distribution=cprov.archive.distribution)
-    >>> from lp.buildmaster.interfaces.builder import IBuilderSet
-    >>> bob = getUtility(IBuilderSet)['bob']
-    >>> binaries = test_publisher.getPubBinaries(
-    ...     archive=cprov_private_ppa, builder=bob,
-    ...     binaryname='privacycheck-bin')
-    >>> flush_database_updates()
-
-The default set of builds with no user specified excludes private builds:
-
-    >>> bob_builds = bob.getBuildRecords()
-    >>> print_build_details(bob_builds)
-    ubuntu-team: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-    cprov: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    no-priv: i386 build of cdrkit 1.0 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    ...
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu breezy-autotest
-    RELEASE
-
-    >>> bob_builds.count()
-    16
-
-If we include an admin user, we can see all the builds.  Here, we get
-an additional private build for cprov:
-
-    >>> from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
-    >>> admin = getUtility(ILaunchpadCelebrities).admin
-    >>> bob_builds = bob.getBuildRecords(user=admin)
-    >>> print_build_details(bob_builds)
-    cprov: i386 build of privacycheck 666 in ubuntutest breezy-autotest...
-    ubuntu-team: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-    cprov: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    no-priv: i386 build of cdrkit 1.0 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    ...
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu breezy-autotest
-        RELEASE
-
-    >>> bob_builds.count()
-    17
-
-Cprov can also see his own builds of course:
-
-    >>> bob_builds = bob.getBuildRecords(user=cprov)
-    >>> print_build_details(bob_builds)
-    cprov: i386 build of privacycheck 666 in ubuntutest breezy-autotest...
-    ubuntu-team: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-    cprov: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    no-priv: i386 build of cdrkit 1.0 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    ...
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu breezy-autotest
-        RELEASE
-
-    >>> bob_builds.count()
-    17
-
-Buildd admins specifically are not allowed to see private builds, which will
-be filtered from the list returned:
-
-    >>> buildd_admin = factory.makePerson()
-    >>> buildd_admins = getUtility(
-    ...     IPersonSet).getByName('launchpad-buildd-admins')
-    >>> ignored = buildd_admins.addMember(buildd_admin, buildd_admin)
-    >>> bob_builds = bob.getBuildRecords(user=buildd_admin)
-    >>> print_build_details(bob_builds)
-    ubuntu-team: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    cprov: i386 build of pmount 0.1-1 in ubuntu warty RELEASE
-    cprov: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    no-priv: i386 build of cdrkit 1.0 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
-    ...
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu warty RELEASE
-    ubuntu-team: i386 build of mozilla-firefox 0.9 in ubuntu breezy-autotest
-    RELEASE
-
-    >>> bob_builds.count()
-    16
-
-You can filter on build state:
-
-    >>> bob_failed_builds = bob.getBuildRecords(
-    ...     build_state=BuildStatus.FAILEDTOBUILD, user=admin)
-    >>> bob_failed_builds.count()
-    3
-
-You can filter on package name:
-
-    >>> bob_pmount_builds = bob.getBuildRecords(name='pmount', user=admin)
-    >>> bob_pmount_builds.count()
-    4
-
-You can filter on build state and package name:
-
-    >>> bob_pmount_ok_builds = bob.getBuildRecords(
-    ...    build_state=BuildStatus.FULLYBUILT, name='pmount', user=admin)
-    >>> bob_pmount_ok_builds.count()
-    4
-
-
+<<< test_imported_builds >>>
 == AssertionErrors in IBinaryPackageBuild ==
 
 Build records inserted by gina don't provide calculated_buildstart
@@ -535,6 +93,7 @@
     >>> print failedtoupload_build.upload_log.filename
     upload_22_log.txt
 
+<<< And back into test_build >>>
 
 == Updating build-dependencies line ==
 
@@ -652,6 +211,7 @@
     >>> flush_database_caches()
     >>> login(ANONYMOUS)
 
+<<< Smells like test_build_set >>>
 === Retrying DEPWAIT builds ===
 
 It depends on the callsite to decide whether or not to 'retry' a
@@ -688,7 +248,7 @@
 other buildd tasks because the procedure is 'atomic' enough, i.e.,
 after the commit the retried jobs are ready to be dispatched.
 
-
+<<< test_build, once more with feeling >>>
 == Build rescoring ==
 
 Some builds can be rescored, to determine if it's possible check the
@@ -720,7 +280,7 @@
 
     >>> login(ANONYMOUS)
 
-
+<<< test_build_privacy >>>
 == Build record security ==
 
 IBinaryPackageBuild's content class is wrapped in a Zope security
@@ -922,7 +482,7 @@
     >>> bq.estimated_duration
     datetime.timedelta(0, 3600)
 
-
+<<< test_build_set >>>
 == IBinaryPackageBuildSet.getBuildsBySourcePackageRelease() ==
 
 getBuildsBySourcePackageRelease() will return all the Build records for

=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py	2011-01-13 11:42:44 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py	2011-01-13 23:24:29 +0000
@@ -49,9 +49,9 @@
         super(TestBinaryPackageBuild, self).setUp()
         publisher = SoyuzTestPublisher()
         publisher.prepareBreezyAutotest()
-        gedit_spr = publisher.getPubSource(
-            spr_only=True, sourcename="gedit",
-            status=PackagePublishingStatus.PUBLISHED)
+        gedit_spph = publisher.getPubSource(
+            sourcename="gedit", status=PackagePublishingStatus.PUBLISHED)
+        gedit_spr = gedit_spph.sourcepackagerelease
         self.build = gedit_spr.createBuild(
             distro_arch_series=publisher.distroseries['i386'],
             archive=gedit_spr.upload_archive,

=== modified file 'lib/lp/soyuz/tests/test_hasbuildrecords.py'
--- lib/lp/soyuz/tests/test_hasbuildrecords.py	2010-10-04 19:50:45 +0000
+++ lib/lp/soyuz/tests/test_hasbuildrecords.py	2011-01-13 23:24:29 +0000
@@ -1,20 +1,33 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test implementations of the IHasBuildRecords interface."""
 
+from datetime import (
+    datetime,
+    timedelta,
+    )
+import pytz
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
 from canonical.testing.layers import LaunchpadZopelessLayer
-from lp.buildmaster.enums import BuildFarmJobType
+from lp.buildmaster.enums import (
+    BuildFarmJobType,
+    BuildStatus,
+    )
 from lp.buildmaster.interfaces.builder import IBuilderSet
 from lp.buildmaster.interfaces.buildfarmjob import (
     IBuildFarmJob,
     )
 from lp.buildmaster.interfaces.packagebuild import IPackageBuildSource
+from lp.registry.interfaces.person import IPersonSet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.model.sourcepackage import SourcePackage
+from lp.soyuz.enums import (
+    ArchivePurpose,
+    PackagePublishingStatus,
+    )
 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuild
 from lp.soyuz.interfaces.buildrecords import (
     IHasBuildRecords,
@@ -22,6 +35,12 @@
     )
 from lp.soyuz.model.processor import ProcessorFamilySet
 from lp.soyuz.tests.test_binarypackagebuild import BaseTestCaseWithThreeBuilds
+from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
+from lp.testing import (
+    person_logged_in,
+    TestCaseWithFactory,
+    )
+from lp.testing.sampledata import ADMIN_EMAIL
 
 
 class TestHasBuildRecordsInterface(BaseTestCaseWithThreeBuilds):
@@ -37,7 +56,6 @@
     def setUp(self):
         """Use `SoyuzTestPublisher` to publish some sources in archives."""
         super(TestHasBuildRecordsInterface, self).setUp()
-
         self.context = self.publisher.distroseries.distribution
 
     def testProvidesHasBuildRecords(self):
@@ -64,6 +82,65 @@
         self.assertContentEqual(i386_builds, builds)
 
 
+class TestDistributionHasBuildRecords(TestCaseWithFactory):
+    """Populate a distroseries with builds"""
+
+    layer = LaunchpadZopelessLayer
+
+    def setUp(self):
+        super(TestDistributionHasBuildRecords, self).setUp()
+        self.admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
+        self.pf_one = self.factory.makeProcessorFamily()
+        pf_proc_1 = self.pf_one.addProcessor(
+            self.factory.getUniqueString(), '', '')
+        self.pf_two = self.factory.makeProcessorFamily()
+        pf_proc_2 = self.pf_two.addProcessor(
+            self.factory.getUniqueString(), '', '')
+        self.distroseries = self.factory.makeDistroSeries()
+        self.distribution = self.distroseries.distribution
+        self.das_one = self.factory.makeDistroArchSeries(
+            distroseries=self.distroseries, processorfamily=self.pf_one,
+            supports_virtualized=True)
+        self.das_two = self.factory.makeDistroArchSeries(
+            distroseries=self.distroseries, processorfamily=self.pf_two,
+            supports_virtualized=True)
+        self.archive = self.factory.makeArchive(
+            distribution=self.distroseries.distribution,
+            purpose=ArchivePurpose.PRIMARY)
+        self.arch_ids = [arch.id for arch in self.distroseries.architectures]
+        with person_logged_in(self.admin):
+            self.publisher = SoyuzTestPublisher()
+            self.publisher.prepareBreezyAutotest()
+            self.distroseries.nominatedarchindep = self.das_one
+            self.publisher.addFakeChroots(distroseries=self.distroseries)
+            self.builder_one = self.factory.makeBuilder(processor=pf_proc_1)
+            self.builder_two = self.factory.makeBuilder(processor=pf_proc_2)
+        self.builds = []
+        self.createBuilds()
+
+    def createBuilds(self):
+        for i in range(5):
+            # Create some test builds
+            spph = self.publisher.getPubSource(
+                sourcename=self.factory.getUniqueString(),
+                version="%s.%s" % (self.factory.getUniqueInteger(), i),
+                distroseries=self.distroseries, architecturehintlist='any')
+            builds = spph.createMissingBuilds()
+            for b in builds:
+                if i == 4:
+                    b.status = BuildStatus.FAILEDTOBUILD
+                else:
+                    b.status = BuildStatus.FULLYBUILT
+                b.buildqueue_record.destroySelf()
+                b.date_started = datetime.now(pytz.UTC)
+                b.date_finished = b.date_started + timedelta(minutes=5)
+            self.builds += builds
+
+    def test_get_build_records(self):
+        # A Distribution also implements IHasBuildRecords
+        builds = self.distribution.getBuildRecords().count()
+        self.assertEquals(10, builds)
+
 class TestDistroSeriesHasBuildRecords(TestHasBuildRecordsInterface):
     """Test the DistroSeries implementation of IHasBuildRecords."""
 
@@ -73,13 +150,30 @@
         self.context = self.publisher.distroseries
 
 
-class TestDistroArchSeriesHasBuildRecords(TestHasBuildRecordsInterface):
+class TestDistroArchSeriesHasBuildRecords(TestDistributionHasBuildRecords):
     """Test the DistroArchSeries implementation of IHasBuildRecords."""
 
+    layer = LaunchpadZopelessLayer
+
     def setUp(self):
         super(TestDistroArchSeriesHasBuildRecords, self).setUp()
 
-        self.context = self.publisher.distroseries['i386']
+    def test_distroarchseries(self):
+        # Test .getBuildRecords for DASes
+        builds = self.das_one.getBuildRecords().count()
+        self.assertEquals(5, builds)
+        builds = self.das_one.getBuildRecords(
+            build_state=BuildStatus.FULLYBUILT).count()
+        self.assertEquals(4, builds)
+        spn = self.builds[0].source_package_release.sourcepackagename.name
+        builds = self.das_one.getBuildRecords(name=spn).count()
+        self.assertEquals(1, builds)
+        builds = self.das_one.getBuildRecords(
+            pocket=PackagePublishingPocket.RELEASE).count()
+        self.assertEquals(5, builds)
+        builds = self.das_one.getBuildRecords(
+            pocket=PackagePublishingPocket.UPDATES).count()
+        self.assertEquals(0, builds)
 
 
 class TestArchiveHasBuildRecords(TestHasBuildRecordsInterface):
@@ -144,7 +238,6 @@
         # can only test this by creating a lone IBuildFarmJob of a
         # different type.
         from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
-        from lp.buildmaster.enums import BuildStatus
         build_farm_job = getUtility(IBuildFarmJobSource).new(
             job_type=BuildFarmJobType.RECIPEBRANCHBUILD, virtualized=True,
             status=BuildStatus.BUILDING)
@@ -180,11 +273,9 @@
 
     def setUp(self):
         super(TestSourcePackageHasBuildRecords, self).setUp()
-
         gedit_name = self.builds[0].source_package_release.sourcepackagename
         self.context = SourcePackage(
-            gedit_name,
-            self.builds[0].distro_arch_series.distroseries)
+            gedit_name, self.builds[0].distro_arch_series.distroseries)
 
         # Convert the other two builds to be builds of
         # gedit as well so that the one source package (gedit) will have
@@ -192,3 +283,88 @@
         for build in self.builds[1:3]:
             spr = build.source_package_release
             removeSecurityProxy(spr).sourcepackagename = gedit_name
+
+        # Set them as sucessfully built
+        for build in self.builds:
+            build.status = BuildStatus.FULLYBUILT
+            build.buildqueue_record.destroySelf()
+            removeSecurityProxy(build).date_created = (
+                self.factory.getUniqueDate())
+            build.date_started = datetime.now(pytz.UTC)
+            build.date_finished = build.date_started + timedelta(minutes=5)
+
+    def test_get_build_records(self):
+        # Test .getBuildRecords() for SPRs
+        builds = self.context.getBuildRecords(
+            build_state=BuildStatus.FULLYBUILT).count()
+        self.assertEquals(3, builds)
+        builds = self.context.getBuildRecords(
+            pocket=PackagePublishingPocket.RELEASE).count()
+        self.assertEquals(3, builds)
+        builds = self.context.getBuildRecords(
+            pocket=PackagePublishingPocket.UPDATES).count()
+        self.assertEquals(0, builds)
+
+    def test_ordering_date(self):
+        # Build records returned are ordered by creation date
+        builds = self.context.getBuildRecords(
+            build_state=BuildStatus.FULLYBUILT)
+        date_created = [build.date_created for build in builds]
+        self.assertTrue(date_created[0] > date_created[1] > date_created[2])
+
+    def test_ordering_lastscore(self):
+        # PENDING build records returned are ordered by score
+        spph = self.factory.makeSourcePackagePublishingHistory()
+        spr = spph.sourcepackagerelease
+        source_package = SourcePackage.new(
+            spph.sourcepackagerelease.sourcepackagename, spph.distroseries)
+        build1 = self.factory.makeBinaryPackageBuild(
+            source_package_release=spr)
+        build2 = self.factory.makeBinaryPackageBuild(
+            source_package_release=spr)
+        build1.queueBuild()
+        build2.queueBuild()
+        build1.buildqueue_record.lastscore = 10
+        build2.buildqueue_record.lastscore = 1000
+        builds = list(source_package.getBuildRecords())
+        self.assertEquals([build2, build1], builds)
+
+    def test_copy_archive_without_leak(self):
+        # If source publications are copied to a .COPY archive, the originals
+        # don't leak
+        admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
+        source_name = self.factory.getUniqueString()
+        spn = self.factory.makeSourcePackageName(name=source_name)
+        pf = self.factory.makeProcessorFamily()
+        pf_proc = pf.addProcessor(self.factory.getUniqueString(), '', '')
+        distroseries = self.factory.makeDistroSeries()
+        das = self.factory.makeDistroArchSeries(
+            distroseries=distroseries, processorfamily=pf,
+            supports_virtualized=True)
+        with person_logged_in(admin):
+            publisher = SoyuzTestPublisher()
+            publisher.prepareBreezyAutotest()
+            publisher.addFakeChroots(distroseries=distroseries)
+            distroseries.nominatedarchindep = das
+            builder = self.factory.makeBuilder(processor=pf_proc)
+        spph = self.factory.makeSourcePackagePublishingHistory(
+            sourcepackagename=spn, distroseries=distroseries)
+        del_spph = self.factory.makeSourcePackagePublishingHistory(
+            distroseries=distroseries,
+            status=PackagePublishingStatus.DELETED)
+        spph.createMissingBuilds()
+        del_spph.createMissingBuilds()
+        copy = self.factory.makeArchive(
+            purpose=ArchivePurpose.COPY,
+            distribution=distroseries.distribution)
+        copy_spph = spph.copyTo(
+            distroseries, PackagePublishingPocket.RELEASE, copy)
+        copy_del_spph = del_spph.copyTo(
+            distroseries, PackagePublishingPocket.RELEASE, copy)
+        [copy_build] = copy_spph.createMissingBuilds()
+        [copy_del_build] = copy_del_spph.createMissingBuilds()
+        builds = copy.getBuildRecords()
+        self.assertEquals([copy_del_build, copy_build], list(builds))
+        source = SourcePackage(spn, spph.distroseries)
+        builds = source.getBuildRecords().count()
+        self.assertEquals(1, builds)