← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/bpb-currentcomponent-assertion into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #384220 Build sampledata is broken
  https://bugs.launchpad.net/bugs/384220

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

This branch kills build-views.txt with chemical fire, and converts it to a bunch of (regrettably, large) unit tests. It also does a few bits of drive-by that I noticed.
-- 
https://code.launchpad.net/~stevenk/launchpad/bpb-currentcomponent-assertion/+merge/45210
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bpb-currentcomponent-assertion into lp:launchpad.
=== removed file 'lib/lp/soyuz/browser/tests/build-views.txt'
--- lib/lp/soyuz/browser/tests/build-views.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/soyuz/browser/tests/build-views.txt	1970-01-01 00:00:00 +0000
@@ -1,430 +0,0 @@
-= Build Pages =
-
-For the subsequent tests we will use a specific 'pmount' build record
-from the sampledata which happens to be in FAILEDTOBUILD status.
-
-    >>> from zope.component import getUtility
-    >>> from lp.buildmaster.enums import BuildStatus
-    >>> from lp.registry.interfaces.distribution import IDistributionSet
-
-    >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
-    >>> hoary = ubuntu.getSeries('hoary')
-    >>> hoary_pmount = hoary.getSourcePackage('pmount')
-
-    >>> hoary_failed_build = hoary_pmount.getBuildRecords(
-    ...      build_state=BuildStatus.FAILEDTOBUILD)[0]
-
-
-== Build Menu ==
-
-The menu presented in the build page depends on the targeted archive.
-For instance the 'PPA' action-menu link is not enabled for builds
-targeted to the PRIMARY archive.
-
-    >>> from lp.soyuz.browser.build import BuildContextMenu
-    >>> build_menu = BuildContextMenu(hoary_failed_build)
-
-    >>> print build_menu.links
-    ['ppa', 'records', 'retry', 'rescore']
-
-    >>> build_menu.is_ppa_build
-    False
-
-    >>> build_menu.ppa().enabled
-    False
-
-The 'PPA' action-menu item will be enabled if we target the build to
-Celso's PPA.
-
-    >>> from lp.registry.interfaces.person import IPersonSet
-
-    >>> cprov = getUtility(IPersonSet).getByName('cprov')
-    >>> cprov_failed_build = cprov.archive.getBuildRecords(
-    ...      build_state=BuildStatus.FAILEDTOBUILD)[0]
-
-    >>> build_menu = BuildContextMenu(cprov_failed_build)
-
-    >>> print build_menu.links
-    ['ppa', 'records', 'retry', 'rescore']
-
-    >>> build_menu.is_ppa_build
-    True
-
-    >>> build_menu.ppa().enabled
-    True
-
-
-== Build +index page ==
-
-Setup an 'empty' request:
-
-    >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
-    >>> empty_request = LaunchpadTestRequest(form={})
-
-Let's instantiate the view for +index:
-
-    >>> from zope.component import getMultiAdapter
-    >>> hoary_failed_build_view = getMultiAdapter(
-    ...     (hoary_failed_build, empty_request), name="+index")
-
-`BuildView` has some cached properties that are used multiple times in
-the related templates.
-
-    >>> print hoary_failed_build_view.is_ppa
-    False
-
-    >>> print hoary_failed_build_view.buildqueue
-    None
-
-    >>> print hoary_failed_build_view.component.name
-    main
-
-'BuildView.user_can_retry_build' property checks not only the
-user's permissions to retry but also if a build is in a status that it
-can be retried.
-
-The build cannot be retried (see IBuild) because it's targeted to a
-stable distroseries.
-
-    >>> hoary_failed_build.can_be_retried
-    False
-
-    >>> hoary_failed_build_view.user_can_retry_build
-    False
-
-The Celso's PPA failed-to-build build record can be retried, since PPA
-distroseries never freeze.
-
-    >>> cprov_failed_build.can_be_retried
-    True
-
-While the build is now in a state to be rebuilt, the view property
-still checks to ensure the user has the proper permission. Anonymous
-users, obviously, don't have 'launchpad.Edit' permission on this
-build.
-
-    >>> cprov_failed_build_view = getMultiAdapter(
-    ...     (cprov_failed_build, empty_request), name="+index")
-
-    >>> cprov_failed_build_view.user_can_retry_build
-    False
-
-If accessed by an user with the required permission, Foo Bar in this
-case, the 'user_can_retry_build' property finally returns True.
-
-    >>> login("foo.bar@xxxxxxxxxxxxx")
-
-    >>> cprov_failed_build_view = getMultiAdapter(
-    ...     (cprov_failed_build, empty_request), name="+index")
-
-    >>> cprov_failed_build_view.user_can_retry_build
-    True
-
-Buildd admins can retry any build as long is it's in a state that
-permits it to be re-tried.  FAILEDTOBUILD is one of those states:
-
-    >>> from lp.soyuz.tests.test_publishing import (
-    ...      SoyuzTestPublisher)
-    >>> from lp.soyuz.enums import (
-    ...     PackagePublishingStatus)
-    >>> test_publisher = SoyuzTestPublisher()
-    >>> test_publisher.prepareBreezyAutotest()
-    >>> test_source = test_publisher.getPubSource(
-    ...     status=PackagePublishingStatus.PUBLISHED,
-    ...     sourcename='sourceone')
-    >>> [failed_build] = test_source.createMissingBuilds()
-    >>> failed_build.status = BuildStatus.FAILEDTOBUILD
-
-    >>> failed_build.can_be_retried
-    True
-
-Mr "no privileges" has no rights to retry the build:
-
-    >>> login("no-priv@xxxxxxxxxxxxx")
-    >>> failed_build_view = getMultiAdapter(
-    ...     (failed_build, empty_request), name="+index")
-    >>> failed_build_view.user_can_retry_build
-    False
-
-If he is put in the buildd-admins group, however, he is now able to
-retry it.
-
-    >>> buildd_admins = getUtility(IPersonSet).getByName(
-    ...     "launchpad-buildd-admins")
-    >>> nopriv = getUtility(IPersonSet).getByName("no-priv")
-    >>> login("foo.bar@xxxxxxxxxxxxx")
-    >>> ignored = buildd_admins.addMember(nopriv, nopriv)
-
-    >>> login("no-priv@xxxxxxxxxxxxx")
-    >>> failed_build_view = getMultiAdapter(
-    ...     (failed_build, empty_request), name="+index")
-    >>> failed_build_view.user_can_retry_build
-    True
-
-A person in a team that has rights to upload to a packageset can also retry it.
-
-So, create a user, a team, and the packageset:
-
-    >>> login('admin@xxxxxxxxxxxxx')
-    >>> from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
-    >>> from lp.soyuz.interfaces.packageset import IPackagesetSet
-    >>> joe = factory.makePerson(email='joe@xxxxxxxxxxx', password='test')
-    >>> desktop = factory.makeTeam(name='desktop', owner=joe)
-    >>> main_archive = test_publisher.distroseries.main_archive
-    >>> rebuild_ps = getUtility(IPackagesetSet).new(
-    ...     u'rebuild', u'Test package set', desktop,
-    ...     distroseries=test_publisher.distroseries)
-    >>> rebuild_spn = (failed_build.source_package_release.sourcepackagename,)
-    >>> rebuild_ps.add(rebuild_spn)
-
-Joe will not have permission to retry the build until we grant it:
-
-    >>> login('joe@xxxxxxxxxxx')
-    >>> failed_build_view = getMultiAdapter(
-    ...     (failed_build, empty_request), name="+index")
-    >>> failed_build_view.user_can_retry_build
-    False
-    >>> login('admin@xxxxxxxxxxxxx')
-    >>> perms = getUtility(IArchivePermissionSet).newPackagesetUploader(
-    ...     main_archive, desktop, rebuild_ps)
-    >>> login('joe@xxxxxxxxxxx')
-    >>> failed_build_view = getMultiAdapter(
-    ...     (failed_build, empty_request), name="+index")
-    >>> failed_build_view.user_can_retry_build
-    True
-
-See pagetests/soyuz/xx-build-record.txt for further information about
-the build-retry permission system.
-
-`BuildView.package_upload` returns the cached `PackageUpload` record
-corresponding to this build. It's None if the binaries for a build were
-not yet collected.
-
-    >>> print cprov_failed_build_view.package_upload
-    None
-
-Automatically, 'BuildView.has_published_binaries' reflects this condition.
-
-    >>> print cprov_failed_build_view.has_published_binaries
-    False
-
-First let's create a package upload for this build:
-XXX: noodles 2009-01-16 bug 317863: move this into the STP.
-
-    >>> from lp.registry.interfaces.pocket import (
-    ...     PackagePublishingPocket)
-    >>> from lp.soyuz.model.queue import PackageUploadBuild
-    >>> build = cprov_failed_build_view.context
-    >>> package_upload = build.distro_series.createQueueEntry(
-    ...     PackagePublishingPocket.UPDATES, 'changes.txt', 'my changes',
-    ...     build.archive)
-    >>> package_upload_build = PackageUploadBuild(
-    ...     packageupload =package_upload,
-    ...     build=cprov_failed_build_view.context)
-    >>> print package_upload.status.name
-    NEW
-
-Now, our build has a package upload and its status is
-NEW. 'has_published_binaries' remains False.
-
-    >>> cprov_failed_build_view = create_initialized_view(
-    ...     cprov_failed_build, '+index')
-
-    >>> print cprov_failed_build_view.package_upload.status.name
-    NEW
-
-    >>> print cprov_failed_build_view.has_published_binaries
-    False
-
-The view 'package_upload' is still available after it has been
-accepted and processed. Afterwards 'has_published_binaries' becomes
-True.
-
-    >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> package_upload.setDone()
-    >>> login("no-priv@xxxxxxxxxxxxx")
-
-    >>> cprov_failed_build_view = create_initialized_view(
-    ...     cprov_failed_build, '+index')
-
-    >>> print cprov_failed_build_view.package_upload.status.name
-    DONE
-
-    >>> print cprov_failed_build_view.has_published_binaries
-    True
-
-The BuildIndex view also has a files helper which returns
-all the files from the related binary package releases.
-
-    >>> hoary_pmount_build = hoary.getBuildRecords(
-    ...     build_state=BuildStatus.FULLYBUILT, name='pmount',
-    ...     arch_tag='hppa')[0]
-    >>> hoary_pmount_build_view = create_initialized_view(
-    ...     hoary_pmount_build, '+index')
-    >>> len(hoary_pmount_build_view.files)
-    1
-    >>> deb_file = hoary_pmount_build_view.files[0]
-    >>> print deb_file.filename
-    pmount_1.9-1_all.deb
-
-Files that are still referenced by binary package releases but have
-been deleted will not be included in the view's files.
-
-    >>> deb_file.deleted
-    False
-    >>> from zope.security.proxy import removeSecurityProxy
-    >>> removeSecurityProxy(deb_file.context).content = None
-    >>> deb_file.deleted
-    True
-
-    >>> hoary_pmount_build_view = create_initialized_view(
-    ...     hoary_pmount_build, '+index')
-    >>> len(hoary_pmount_build_view.files)
-    0
-
-
-== BuildRescoringView ==
-
-`BuildRescoringView` is used for setting new values to the
-corresponding `BuildQueue.lastscore` record for a `Build`.
-
-It redirects users to the `Build` page when the build cannot be
-rescored.
-
-    >>> print cprov_failed_build.can_be_rescored
-    False
-
-    >>> view = create_initialized_view(
-    ...    cprov_failed_build, name="+rescore")
-
-    >>> view.request.response.getStatus()
-    302
-    >>> print view.request.response.getHeader('Location')
-    http://launchpad.dev/~cprov/+archive/ppa/+build/26
-
-Canceled 'Rescore' form redirects users back to the Build page.
-
-    # Fetch an PENDING build from the sampledata.
-    >>> pending_build = ubuntu.getBuildRecords(
-    ...      build_state=BuildStatus.NEEDSBUILD)[0]
-
-    >>> view = create_initialized_view(
-    ...    pending_build, name="+rescore")
-
-    >>> print view.cancel_url
-    http://launchpad.dev/ubuntu/+source/alsa-utils/1.0.9a-4ubuntu1/+build/11
-
-The 'priority' field only accepts long integer values.
-
-    >>> view = create_initialized_view(
-    ...    pending_build, name="+rescore", form={
-    ...    'field.priority': str(2 ** 31 + 1),
-    ...    'field.actions.rescore': 'Rescore',
-    ...    })
-
-    >>> for error in view.errors:
-    ...     print '%s -> %s' % (error.widget_title, error.doc())
-    Priority -> Value is too big
-
-    >>> view = create_initialized_view(
-    ...    pending_build, name="+rescore", form={
-    ...    'field.priority': '-' + str(2 ** 31 + 1),
-    ...    'field.actions.rescore': 'Rescore',
-    ...    })
-
-    >>> for error in view.errors:
-    ...     print '%s -> %s' % (error.widget_title, error.doc())
-    Priority -> Value is too small
-
-Submitting valid values will update the build 'score' and redirect
-users to the build page with an appropriate notification.
-
-    >>> print pending_build.buildqueue_record.lastscore
-    10
-
-    >>> view = create_initialized_view(
-    ...    pending_build, name="+rescore", form={
-    ...    'field.priority': '0',
-    ...    'field.actions.rescore': 'Rescore',
-    ...    })
-
-    >>> view.request.response.getStatus()
-    302
-    >>> print view.request.response.getHeader('Location')
-    http://launchpad.dev/ubuntu/+source/alsa-utils/1.0.9a-4ubuntu1/+build/11
-
-    >>> for notification in view.request.response.notifications:
-    ...     print notification.message
-    Build rescored to 0.
-
-    >>> print pending_build.buildqueue_record.lastscore
-    0
-
-
-== BuildRecordsView ==
-
-The BuildRecordsView can also be used to filter by architecture tag.
-
-    >>> view = create_initialized_view(
-    ...     hoary, name="+builds", form={'build_state': 'all'})
-    >>> view.setupBuildList()
-    >>> for build in view.complete_builds:
-    ...     print build.arch_tag
-    i386
-    ...
-    hppa
-    ...
-
-    >>> view = create_initialized_view(
-    ...     hoary, name="+builds", form={
-    ...         'build_state': 'all',
-    ...         'arch_tag': 'hppa',
-    ...         })
-    >>> view.setupBuildList()
-    >>> for build in view.complete_builds:
-    ...     print build.arch_tag
-    hppa
-
-The architecture_options property iterates through the available
-architectures of the context constructing a distinct, sorted list
-of options for the template.
-
-    >>> view = create_initialized_view(
-    ...     ubuntu, name="+builds", form={
-    ...         'build_state': 'all',
-    ...         'arch_tag': 'hppa',
-    ...         })
-    >>> for option in view.architecture_options:
-    ...     option_str = option['name']
-    ...     if option['selected'] is not None:
-    ...         option_str += " (selected)"
-    ...     print option_str
-    All architectures
-    hppa (selected)
-    i386
-
-
-== Dispatch time estimates ==
-
-A dispatch time estimate is available for pending binary builds that have not
-been suspended.
-
-    >>> from lp.services.job.interfaces.job import JobStatus
-    >>> pending_build = ubuntu.getBuildRecords(
-    ...      build_state=BuildStatus.NEEDSBUILD)[0]
-
-    >>> view = create_initialized_view(pending_build, name="+index")
-    >>> view.dispatch_time_estimate_available
-    True
-    >>> view.context.status == BuildStatus.NEEDSBUILD
-    True
-    >>> view.context.buildqueue_record.job.status == JobStatus.WAITING
-    True
-
-If we suspend the binary build job, however, no estimate is available.
-
-    >>> view.context.buildqueue_record.job.suspend()
-    >>> view.context.buildqueue_record.job.status == JobStatus.SUSPENDED
-    True
-    >>> view.dispatch_time_estimate_available
-    False

=== added file 'lib/lp/soyuz/browser/tests/test_build_views.py'
--- lib/lp/soyuz/browser/tests/test_build_views.py	1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/browser/tests/test_build_views.py	2011-01-05 07:44:36 +0000
@@ -0,0 +1,283 @@
+# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+__metaclass__ = type
+
+from datetime import (
+    datetime,
+    timedelta,
+    )
+import pytz
+from zope.component import (
+    getMultiAdapter,
+    getUtility,
+    )
+from zope.security.proxy import removeSecurityProxy
+
+from canonical.launchpad.webapp import canonical_url
+from canonical.launchpad.webapp.servers import LaunchpadTestRequest
+from canonical.testing.layers import LaunchpadFunctionalLayer
+from lp.buildmaster.enums import BuildStatus
+from lp.registry.interfaces.person import IPersonSet
+from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.registry.interfaces.series import SeriesStatus
+from lp.services.job.interfaces.job import JobStatus
+from lp.soyuz.browser.build import BuildContextMenu
+from lp.soyuz.enums import ArchivePurpose
+from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
+from lp.soyuz.interfaces.packageset import IPackagesetSet
+from lp.soyuz.model.queue import PackageUploadBuild
+from lp.testing import (
+    person_logged_in,
+    TestCaseWithFactory,
+    )
+from lp.testing.sampledata import ADMIN_EMAIL
+from lp.testing.views import create_initialized_view
+
+
+class TestBuildViews(TestCaseWithFactory):
+    
+    layer = LaunchpadFunctionalLayer
+
+    def setUp(self):
+        super(TestBuildViews, self).setUp()
+        self.empty_request = LaunchpadTestRequest(form={})
+        self.admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
+
+    def assertBuildViewRetryIsExpected(self, build, person, expected):
+        with person_logged_in(person):
+            build_view = getMultiAdapter(
+                (build, self.empty_request), name="+index")
+            self.assertEquals(build_view.user_can_retry_build, expected)
+
+    def test_build_menu_primary(self):
+        # The menu presented in the build page depends on the targeted
+        # archive. For instance the 'PPA' action-menu link is not enabled
+        # for builds targeted to the PRIMARY archive.
+        archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
+        build = self.factory.makeBinaryPackageBuild(archive=archive)
+        build_menu = BuildContextMenu(build)
+        self.assertEquals(build_menu.links,
+            ['ppa', 'records', 'retry', 'rescore'])
+        self.assertFalse(build_menu.is_ppa_build)
+        self.assertFalse(build_menu.ppa().enabled)
+
+    def test_build_menu_ppa(self):
+        # The 'PPA' action-menu item will be enabled if we target the build
+        # to a PPA.
+        build = self.factory.makeBinaryPackageBuild()
+        build_menu = BuildContextMenu(build)
+        self.assertEquals(build_menu.links,
+            ['ppa', 'records', 'retry', 'rescore'])
+        self.assertTrue(build_menu.is_ppa_build)
+        self.assertTrue(build_menu.ppa().enabled)
+
+    def test_cannot_retry_stable_distroseries(self):
+        # 'BuildView.user_can_retry_build' property checks not only the
+        # user's permissions to retry but also if a build is in a status
+        # that it can be retried.
+        # The build cannot be retried (see IBuild) because it's targeted to a
+        # released distroseries.
+        archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
+        build = self.factory.makeBinaryPackageBuild(
+            archive=archive, status=BuildStatus.FAILEDTOBUILD)
+        distroseries = build.distro_arch_series.distroseries
+        with person_logged_in(self.admin):
+            distroseries.status = SeriesStatus.CURRENT
+        build_view = getMultiAdapter(
+            (build, self.empty_request), name="+index")
+        self.assertFalse(build_view.is_ppa)
+        self.assertEquals(build_view.buildqueue, None)
+        self.assertEquals(build_view.component.name, 'multiverse')
+        self.assertFalse(build.can_be_retried)
+        self.assertFalse(build_view.user_can_retry_build)
+
+    def test_retry_ppa_builds(self):
+        # PPA builds can always be retried, no matter what status the
+        # distroseries has.
+        build = self.factory.makeBinaryPackageBuild(
+            status=BuildStatus.FAILEDTOBUILD)
+        build_view = getMultiAdapter(
+            (build, self.empty_request), name="+index")
+        self.assertTrue(build.can_be_retried)
+        # Anonymous, therefore supposed to be disallowed
+        self.assertFalse(build_view.user_can_retry_build)
+        self.assertBuildViewRetryIsExpected(build, build.archive.owner, True)
+
+    def test_buildd_admins_retry_builds(self):
+        # Buildd admins can retry any build as long is it's in a state that
+        # permits it to be re-tried.
+        archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
+        build = self.factory.makeBinaryPackageBuild(
+            archive=archive, status=BuildStatus.FAILEDTOBUILD)
+        with person_logged_in(self.admin):
+            self.assertTrue(build.can_be_retried)
+        nopriv = getUtility(IPersonSet).getByName("no-priv")
+        # Mr no privledges can't retry
+        self.assertBuildViewRetryIsExpected(build, nopriv, False)
+        # But he can as a member of launchpad-buildd-admins
+        buildd_admins = getUtility(IPersonSet).getByName(
+            "launchpad-buildd-admins")
+        with person_logged_in(self.admin):
+            buildd_admins.addMember(nopriv, nopriv)
+        self.assertBuildViewRetryIsExpected(build, nopriv, True)
+
+    def test_packageset_upload_retry(self):
+        # A person in a team that has rights to upload to a packageset can
+        # also retry failed builds of contained source packages.
+        team = self.factory.makeTeam()
+        archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
+        build = self.factory.makeBinaryPackageBuild(
+            archive=archive, status=BuildStatus.FAILEDTOBUILD)
+        with person_logged_in(self.admin):
+            packageset = getUtility(IPackagesetSet).new(
+                u'rebuild', u'test', team,
+                distroseries=build.distro_arch_series.distroseries)
+            packageset.add((build.source_package_release.sourcepackagename,))
+        # The team doesn't have permission until we grant it
+        self.assertBuildViewRetryIsExpected(build, team.teamowner, False)
+        with person_logged_in(self.admin):
+            getUtility(IArchivePermissionSet).newPackagesetUploader(
+                archive, team, packageset)
+        self.assertBuildViewRetryIsExpected(build, team.teamowner, True)
+
+    def test_build_view_package_upload(self):
+        # `BuildView.package_upload` returns the cached `PackageUpload`
+        # record corresponding to this build. It's None if the binaries for
+        # a build were not yet collected.
+        build = self.factory.makeBinaryPackageBuild()
+        build_view = getMultiAdapter(
+            (build, self.empty_request), name="+index")
+        self.assertEquals(build_view.package_upload, None)
+        self.assertFalse(build_view.has_published_binaries)
+        package_upload = build.distro_series.createQueueEntry(
+            PackagePublishingPocket.UPDATES, 'changes.txt', 'my changes',
+            build.archive)
+        package_upload_build = PackageUploadBuild(
+            packageupload =package_upload, build=build)
+        self.assertEquals(package_upload.status.name, 'NEW')
+        build_view = getMultiAdapter(
+            (build, self.empty_request), name="+index")
+        self.assertEquals(build_view.package_upload.status.name, 'NEW')
+        self.assertFalse(build_view.has_published_binaries)
+        with person_logged_in(self.admin):
+            package_upload.setDone()
+        build_view = getMultiAdapter(
+            (build, self.empty_request), name="+index")
+        self.assertEquals(build_view.package_upload.status.name, 'DONE')
+        self.assertTrue(build_view.has_published_binaries)
+
+    def test_build_view_files_helper(self):
+        # The BuildIndex view also has a files helper which returns
+        # all the files from the related binary package releases.
+        build = self.factory.makeBinaryPackageBuild(
+            status=BuildStatus.FULLYBUILT)
+        bpr = self.factory.makeBinaryPackageRelease(build=build)
+        bprf = self.factory.makeBinaryPackageFile(binarypackagerelease=bpr)
+        build_view = create_initialized_view(build, '+index')
+        deb_file = build_view.files[0]
+        self.assertEquals(deb_file.filename, bprf.libraryfile.filename)
+        # Deleted files won't be included
+        self.assertFalse(deb_file.deleted)
+        removeSecurityProxy(deb_file.context).content = None
+        self.assertTrue(deb_file.deleted)
+        build_view = create_initialized_view(build, '+index')
+        self.assertEquals(len(build_view.files), 0)
+
+    def test_build_rescoring_view(self):
+        # `BuildRescoringView` is used for setting new values to the
+        # corresponding `BuildQueue.lastscore` record for a `Build`.
+        # It redirects users to the `Build` page when the build cannot be
+        # rescored.
+        build = self.factory.makeBinaryPackageBuild(
+            status=BuildStatus.FAILEDTOBUILD)
+        self.assertFalse(build.can_be_rescored)
+        view = create_initialized_view(build, name='+rescore')
+        self.assertEquals(view.request.response.getStatus(), 302)
+        self.assertEquals(view.request.response.getHeader('Location'),
+            canonical_url(build)) 
+        pending_build = self.factory.makeBinaryPackageBuild()
+        view = create_initialized_view(pending_build, name='+rescore')
+        self.assertEquals(view.cancel_url, canonical_url(pending_build))
+
+    def test_rescore_value_too_large(self):
+        build = self.factory.makeBinaryPackageBuild()
+        view = create_initialized_view(
+            build, name="+rescore", form={
+                'field.priority': str(2 ** 31 + 1),
+                'field.actions.rescore': 'Rescore'})
+        self.assertEquals(view.errors[0].widget_title, "Priority")
+        self.assertEquals(view.errors[0].doc(), "Value is too big")
+
+    def test_rescore_value_too_small(self):
+        build = self.factory.makeBinaryPackageBuild()
+        view = create_initialized_view(
+            build, name="+rescore", form={
+                'field.priority': '-' + str(2 ** 31 + 1),
+                'field.actions.rescore': 'Rescore'})
+        self.assertEquals(view.errors[0].widget_title, "Priority")
+        self.assertEquals(view.errors[0].doc(), "Value is too small")
+
+    def test_rescore(self):
+        pending_build = self.factory.makeBinaryPackageBuild()
+        pending_build.queueBuild()
+        with person_logged_in(self.admin):
+            view = create_initialized_view(
+                pending_build, name="+rescore", form={
+                    'field.priority': '0',
+                    'field.actions.rescore': 'Rescore'})
+        notification = view.request.response.notifications[0]
+        self.assertEquals(notification.message, "Build rescored to 0.")
+        self.assertEquals(pending_build.buildqueue_record.lastscore, 0)
+
+    def test_build_records_view(self):
+        # The BuildRecordsView can also be used to filter by architecture tag.
+        distroseries = self.factory.makeDistroSeries()
+        arch_list = []
+        for i in range(5):
+            das = self.factory.makeDistroArchSeries(distroseries=distroseries)
+            arch_list.append(das.architecturetag)
+            build = self.factory.makeBinaryPackageBuild(
+                distroarchseries=das, archive=distroseries.main_archive,
+                status=BuildStatus.FULLYBUILT)
+            with person_logged_in(self.admin):
+                build.date_started = (
+                    datetime.now(pytz.UTC) - timedelta(hours=1))
+                build.date_finished = datetime.now(pytz.UTC)
+        view = create_initialized_view(
+            distroseries, name="+builds", form={'build_state': 'all'})
+        view.setupBuildList()
+        build_arches = [build.arch_tag for build in view.complete_builds]
+        self.assertEquals(arch_list.sort(), build_arches.sort())
+        view = create_initialized_view(
+            distroseries, name="+builds", form={
+                'build_state': 'all', 'arch_tag': arch_list[0]})
+        view.setupBuildList()
+        self.assertEquals(len(view.complete_builds), 1)
+        self.assertEquals(view.complete_builds[0].arch_tag, arch_list[0])
+        # There is an extra entry for 'All architectures'
+        self.assertEquals(len(view.architecture_options), len(arch_list) + 1)
+        selected = []
+        option_arches = []
+        for option in view.architecture_options:
+            option_arches.append(option['name'])
+            if option['selected'] is not None:
+                selected.append(option['name'])
+        self.assertEquals(option_arches.sort(), arch_list.sort())
+        self.assertTrue(len(selected), 1)
+        self.assertEquals(selected, [arch_list[0]])
+
+    def test_dispatch_estimate(self):
+        # A dispatch time estimate is available for pending binary builds
+        # that have not been suspended.
+        build = self.factory.makeBinaryPackageBuild()
+        build.queueBuild()
+        view = create_initialized_view(build, name="+index")
+        job = view.context.buildqueue_record.job
+        self.assertTrue(view.dispatch_time_estimate_available)
+        self.assertEquals(view.context.status, BuildStatus.NEEDSBUILD)
+        self.assertEquals(job.status, JobStatus.WAITING)
+        # If we suspend the job, there is no estimate available
+        job.suspend()
+        self.assertEquals(job.status, JobStatus.SUSPENDED)
+        self.assertFalse(view.dispatch_time_estimate_available)

=== modified file 'lib/lp/soyuz/browser/tests/test_builder_views.py'
--- lib/lp/soyuz/browser/tests/test_builder_views.py	2010-10-27 14:25:19 +0000
+++ lib/lp/soyuz/browser/tests/test_builder_views.py	2011-01-05 07:44:36 +0000
@@ -11,6 +11,7 @@
 from lp.soyuz.browser.builder import BuilderEditView
 from lp.testing import TestCaseWithFactory
 from lp.testing.fakemethod import FakeMethod
+from lp.testing.sampledata import ADMIN_EMAIL
 
 
 class TestBuilderEditView(TestCaseWithFactory):
@@ -21,7 +22,7 @@
         super(TestBuilderEditView, self).setUp()
         # Login as an admin to ensure access to the view's context
         # object.
-        login('admin@xxxxxxxxxxxxx')
+        login(ADMIN_EMAIL)
         self.builder = removeSecurityProxy(self.factory.makeBuilder())
 
     def initialize_view(self):

=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py	2010-11-11 11:55:53 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py	2011-01-05 07:44:36 +0000
@@ -941,7 +941,7 @@
     def getBuildsByArchIds(self, distribution, arch_ids, status=None,
                            name=None, pocket=None):
         """See `IBinaryPackageBuildSet`."""
-        # If not distroarchseries was found return empty list
+        # If no distroarchseries were passed in, return an empty list
         if not arch_ids:
             return EmptyResultSet()