← Back to team overview

launchpad-reviewers team mailing list archive

Re: lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-5 into lp:launchpad

 

Review: Needs Fixing code
Hi Steven,

Thank you for taking on this large task, which should speed up the test nicely. I'm marking this needs-fixing, since I became dazed by such a large diff, so I'll want to reread it to make sure I haven't missed anything.

-Edwin

>=== removed file 'lib/lp/soyuz/doc/build-notification.txt'
>--- lib/lp/soyuz/doc/build-notification.txt	2011-01-12 23:07:40 +0000
>+++ lib/lp/soyuz/doc/build-notification.txt	1970-01-01 00:00:00 +0000
>@@ -1,629 +0,0 @@
>-=========================
>-Build Notification System
>-=========================
>-
>-IBinaryPackageBuild instance implements the 'notify' method which sends
>-a status report about the current record to the
>-ISourcePackageRelease.creator and the package uploader's preferred email
>-address.
>-
>-We rely on get_contact_email_addresses() to DTRT, either use the
>-Team.contactaddress of the Launchpad Buildd Celebrity or the
>-preferredemail of its members.
>-
>-The report is based on the emailtemplate/build-notification.txt.
>-
>-All build states are supported by the current implementation, however
>-only failures should be reported this time.
>-
>-  >>> from lp.soyuz.interfaces.binarypackagebuild import (
>-  ...     IBinaryPackageBuildSet)
>-  >>> from lp.testing.mail_helpers import pop_notifications
>-  >>> buildset = getUtility(IBinaryPackageBuildSet)
>-
>-To avoid consequences of modified sampledata, specially if we add
>-more builds for test we are going to pick a specific build record
>-in a known state to perform the tests.
>-
>-Notification for a FAILEDTOBUILD (failed) build record:
>-
>-  >>> failed_candidate = buildset.getByBuildID(9)
>-  >>> failed_candidate.source_package_release.name
>-  u'pmount'
>-  >>> failed_candidate.status.name
>-  'FAILEDTOBUILD'
>-  >>> failed_candidate.source_package_release.creator.name
>-  u'mark'
>-
>-  >>> failed_candidate.notify()
>-
>-Check how many email the system have sent:
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  3
>-
>-The members of launchpad-buildd-admins are notified:
>-
>-  >>> notifications.pop(0)['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-  >>> notifications.pop(0)['To']
>-  'foo.bar@xxxxxxxxxxxxx'
>-
>-The maintainer is notified:
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> build_notification['To']
>-  'mark@xxxxxxxxxxx'
>-
>-Checking subject and extra headers. Build notifications have a set of
>-special headers to help filtering on users' mailboxes, they are:
>-
>- * X-Creator-Recipient: the creator email address which can be
>-   notified or not according a configuration parameter.
>- * X-Launchpad-Build-{State, Component, Arch}: build record attributes
>- * X-Launchpad-PPA: omitted if it's not a PPA build-notification,
>-   contains the PPA owner.name otherwise.
>-
>-  >>> def dump_build_notification(notification):
>-  ...     clean_subject = notification['Subject'].replace(
>-  ...         '\n','').replace('\t', ' ')
>-  ...     build_state = notification['X-Launchpad-Build-State']
>-  ...     build_component = notification['X-Launchpad-Build-Component']
>-  ...     build_arch = notification['X-Launchpad-Build-Arch']
>-  ...     ppa_header = 'X-Launchpad-PPA' in notification.keys()
>-  ...     print 'Subject:', clean_subject
>-  ...     print 'X-Creator-Recipient:', notification['X-Creator-Recipient']
>-  ...     print 'X-Launchpad-Build-State:', build_state
>-  ...     print 'X-Launchpad-Build-Component:', build_component
>-  ...     print 'X-Launchpad-Build-Arch:', build_arch
>-  ...     if ppa_header:
>-  ...         print 'X-Launchpad-PPA:', notification['X-Launchpad-PPA']
>-  ...     else:
>-  ...         print 'X-Launchpad-PPA: omitted'
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #9] i386 build of pmount 0.1-1 in ubuntu warty RELEASE
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: FAILEDTOBUILD



I don't see any new test for X-Launchpad-Build-State.


>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: omitted
>-
>-Let's check the notification content.  It should contain:
>-
>- * The source package name
>- * The source package version
>- * The build architecture
>- * The build state
>- * The duration of the build
>- * A link to the build log
>- * A link to the build page
>- * A link to the source page
>-
>-This same basic content applies to all types of notification.
>-
>-  >>> notification_body = build_notification.get_payload(decode=True)
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: pmount
>-   * Version: 0.1-1
>-   * Architecture: i386
>-   * Archive: ubuntu primary archive
>-   * Component: main
>-   * State: Failed to build
>-   * Duration: three minutes
>-   * Build Log: http://launchpad.dev/ubuntu/+source/pmount/0.1-1/+buildjob/9/+files/netapplet-1.0.0.tar.gz
>-   * Builder: http://launchpad.dev/builders/bob
>-   * Source: http://launchpad.dev/ubuntu/+source/pmount/0.1-1
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  If you want further information about this situation, feel free to
>-  contact a member of the Launchpad Buildd Administrators team.
>-  <BLANKLINE>
>-  --
>-  i386 build of pmount 0.1-1 in ubuntu warty RELEASE
>-  http://launchpad.dev/ubuntu/+source/pmount/0.1-1/+buildjob/9
>-  <BLANKLINE>
>-
>-Notification for a pending (NEEDSBUILD) build record:
>-
>-  >>> pending_candidate = buildset.getByBuildID(11)
>-  >>> pending_candidate.source_package_release.name
>-  u'alsa-utils'
>-  >>> pending_candidate.status.name
>-  'NEEDSBUILD'
>-  >>> pending_candidate.source_package_release.creator.name
>-  u'mark'
>-
>-  >>> pending_candidate.notify()
>-
>-Check how many email the system have sent:
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  3
>-
>-The members of launchpad-buildd-admins are notified:
>-
>-  >>> notifications.pop(0)['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-  >>> notifications.pop(0)['To']
>-  'foo.bar@xxxxxxxxxxxxx'
>-
>-The maintainer is notified:
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> build_notification['To']
>-  'mark@xxxxxxxxxxx'
>-
>-Checking subject and extra headers:
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #11] i386 build of alsa-utils 1.0.9a-4ubuntu1 in ubuntu hoary RELEASE
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: NEEDSBUILD
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: omitted
>-
>-Check the notification content:
>-
>-  >>> notification_body = build_notification.get_payload()
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: alsa-utils
>-   * Version: 1.0.9a-4ubuntu1
>-   * Architecture: i386
>-   * Archive: ubuntu primary archive
>-   * Component: main
>-   * State: Needs building
>-   * Duration: not available
>-   * Build Log: not available
>-   * Builder: not available
>-   * Source: http://launchpad.dev/ubuntu/+source/alsa-utils/1.0.9a-4ubuntu1
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  If you want further information about this situation, feel free to
>-  contact a member of the Launchpad Buildd Administrators team.
>-  <BLANKLINE>
>-  --
>-  i386 build of alsa-utils 1.0.9a-4ubuntu1 in ubuntu hoary RELEASE
>-  http://launchpad.dev/ubuntu/+source/alsa-utils/1.0.9a-4ubuntu1/+buildjob/11
>-  <BLANKLINE>
>-
>-Notification for a BUILDING build record:
>-
>-  >>> building_candidate = buildset.getByBuildID(8)
>-  >>> building_candidate.source_package_release.name
>-  u'mozilla-firefox'
>-  >>> building_candidate.status.name
>-  'BUILDING'
>-  >>> building_candidate.source_package_release.creator.name
>-  u'mark'
>-
>-  >>> building_candidate.notify()
>-
>-Check how many email the system have sent:
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  3
>-
>-The members of launchpad-buildd-admins are notified:
>-
>-  >>> notifications.pop(0)['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-  >>> notifications.pop(0)['To']
>-  'foo.bar@xxxxxxxxxxxxx'
>-
>-The maintainer is notified:
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> build_notification['To']
>-  'mark@xxxxxxxxxxx'
>-
>-Checking subject and extra headers:
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #8] i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: BUILDING
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: omitted
>-
>-Check the notification content:
>-
>-  >>> notification_body = build_notification.get_payload()
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: mozilla-firefox
>-   * Version: 0.9
>-   * Architecture: i386
>-   * Archive: ubuntu primary archive
>-   * Component: main
>-   * State: Currently building
>-   * Duration: not finished
>-   * Build Log: see builder page
>-   * Builder: http://launchpad.dev/builders/bob
>-   * Source: http://launchpad.dev/ubuntu/+source/mozilla-firefox/0.9
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  If you want further information about this situation, feel free to
>-  contact a member of the Launchpad Buildd Administrators team.
>-  <BLANKLINE>
>-  --
>-  i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
>-  http://launchpad.dev/ubuntu/+source/mozilla-firefox/0.9/+buildjob/8
>-  <BLANKLINE>
>-
>-Notification for a SUPERSEDED build record:
>-
>-  >>> superseded_candidate = buildset.getByBuildID(15)
>-  >>> superseded_candidate.source_package_release.name
>-  u'at'
>-  >>> superseded_candidate.status.name
>-  'SUPERSEDED'
>-  >>> superseded_candidate.source_package_release.creator.name
>-  u'mark'
>-
>-  >>> superseded_candidate.notify()
>-
>-Check how many email the system have sent:
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  3
>-
>-The members of launchpad-buildd-admins are notified:
>-
>-  >>> notifications.pop(0)['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-  >>> notifications.pop(0)['To']
>-  'foo.bar@xxxxxxxxxxxxx'
>-
>-The maintainer is notified:
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> build_notification['To']
>-  'mark@xxxxxxxxxxx'
>-
>-Checking subject and extra headers:
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #15] i386 build of at 0.00 in ubuntu warty RELEASE
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: SUPERSEDED
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: omitted
>-
>-Check the notification content:
>-
>-  >>> notification_body = build_notification.get_payload()
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: at
>-   * Version: 0.00
>-   * Architecture: i386
>-   * Archive: ubuntu primary archive
>-   * Component: main
>-   * State: Build for superseded Source
>-   * Duration: not available
>-   * Build Log: not available
>-   * Builder: not available
>-   * Source: http://launchpad.dev/ubuntu/+source/at/0.00
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  If you want further information about this situation, feel free to
>-  contact a member of the Launchpad Buildd Administrators team.
>-  <BLANKLINE>
>-  --
>-  i386 build of at 0.00 in ubuntu warty RELEASE
>-  http://launchpad.dev/ubuntu/+source/at/0.00/+buildjob/15
>-  <BLANKLINE>
>-
>-Check if the 'build_notification' configuration option really suppress
>-notification as promised:
>-
>-  >>> from canonical.config import config
>-  >>> send_build_notification = """
>-  ...     [builddmaster]
>-  ...     send_build_notification: False
>-  ...     """
>-  >>> config.push('send_build_notification', send_build_notification)
>-  >>> superseeded_candidate = buildset.getByBuildID(15)
>-  >>> superseeded_candidate.notify()
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  0
>-
>-  >>> config_data = config.pop('send_build_notification')
>-
>-Check if 'notify_owner' config option really suppress email to
>-the SPR owner, but still sending it to the default recipient:
>-
>-  >>> notify_owner = """
>-  ...     [builddmaster]
>-  ...     send_build_notification: True
>-  ...     notify_owner: False
>-  ...     """
>-  >>> config.push('notify_owner', notify_owner)
>-  >>> superseded_candidate = buildset.getByBuildID(15)



I don't see any new tests for this config change.



>-
>-  >>> superseded_candidate.notify()
>-
>-Check how many email the system have sent:
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  2
>-
>-Only the members of launchpad-buildd-admins are notified:
>-
>-  >>> notifications.pop(0)['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-  >>> notifications.pop(0)['To']
>-  'foo.bar@xxxxxxxxxxxxx'
>-
>-Checking subject and extra headers:
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #15] i386 build of at 0.00 in ubuntu warty RELEASE
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: SUPERSEDED
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: omitted
>-
>-Just to keep the config sane, as it was before:
>-
>-  >>> config_data = config.pop('notify_owner')
>-
>-
>-PPA build notifications
>-=======================
>-
>-As for the normal (main archive) build candidates we are also able
>-send notification about current (changed) PPA build record status.
>-
>-PPA build notifications should be as much as possible similar to those
>-in the main archive, the important differences are:
>-
>- * We do not include 'buildd-admins' celebrity in its recipients,
>-   instead we include the Archive owner;
>-
>- * We try to be explicit in the subject and in the body of the message
>-   that it is about a PPA build candidate;
>-
>- * We don't have a 'source package' page for PPA sources.
>-
>- * We only warn the uploader (person specified in 'Changed-By'
>-   changesfile) and the signer (person who owns the GPG key used to
>-   sign the package) if the package was not copied.  Additionally,
>-   the Changed-By person is only notified if they are the PPA owner or
>-   they are in the team owning the PPA (to avoid spamming the innocent
>-   when PPA users upload unchanged source packages).
>-
>-  >>> from lp.registry.interfaces.person import IPersonSet
>-  >>> cprov = getUtility(IPersonSet).getByName('cprov')
>-
>-  >>> from lp.buildmaster.enums import BuildStatus
>-  >>> failed_candidate = cprov.archive.getBuildRecords(
>-  ...     build_state=BuildStatus.FAILEDTOBUILD, name='cdrkit')[0]
>-
>-  >>> failed_candidate.notify()
>-
>-Was this package copied?
>-
>-    >>> (failed_candidate.archive !=
>-    ... failed_candidate.source_package_release.upload_archive)
>-    True
>-
>-Since the package *was* copied, only the owner of the destination
>-archive will get notified.
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  1
>-
>-Checking the message contents:
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> notification_body = build_notification.get_payload(decode=True)
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: cdrkit
>-   * Version: 1.0
>-   * Architecture: i386
>-   * Archive: cprov PPA
>-   * Component: main
>-   * State: Failed to build
>-   * Duration: a minute
>-   * Build Log: http://launchpad.dev/~cprov/+archive/ppa/+buildjob/26/+files/netapplet-1.0.0.tar.gz
>-   * Builder: http://launchpad.dev/builders/bob
>-   * Source: not available
>-  ...
>-
>-The notification went to the PPA owner.
>-
>-  >>> build_notification['To']
>-  'celso.providelo@xxxxxxxxxxxxx'
>-
>-Checking subject and extra headers:
>-
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #26] i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE (cprov PPA)
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: FAILEDTOBUILD
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: cprov
>-
>-In order to test build notifications for sources that were not copied,
>-we will change the 'failed_candidate' source, setting its
>-'upload_archive' to the same archive was built, Celso's PPA.
>-
>-  >>> from canonical.database.sqlbase import commit
>-  >>> from canonical.testing.layers import LaunchpadZopelessLayer
>-
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
>-
>-  >>> from zope.security.proxy import removeSecurityProxy
>-  >>> naked_candidate = removeSecurityProxy(failed_candidate)
>-  >>> naked_sourcepackagerelease = naked_candidate.source_package_release
>-  >>> naked_sourcepackagerelease.upload_archive = failed_candidate.archive
>-
>-We also make 'Foo Bar' the source signer.
>-
>-  >>> from lp.registry.interfaces.gpg import IGPGKeySet
>-  >>> gpgkey = getUtility(IGPGKeySet).get(1)
>-  >>> print gpgkey.owner.name
>-  name16
>-  >>> naked_sourcepackagerelease.dscsigningkey = gpgkey


I don't see new tests for the signer.


>-
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
>-
>-Since 'mark' is the 'creator' it makes the failed-to-build source
>-look like a 'sponsored' upload.
>-
>-  >>> print failed_candidate.source_package_release.creator.name
>-  mark
>-
>-Finally we issue the notification.
>-
>-  >>> failed_candidate.notify()
>-
>-As expected for a 'not-copied and sponsored' PPA upload, only two
>-people involved with the source are notified.
>-
>- * 'cprov' who owns the PPA where the source is being built;
>- * 'name16' who signed the source upload;
>-
>-However, 'mark' who was listed as the creator of the source revision is
>-not notified because he is not in the PPA team or its owner.
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  2
>-
>-  >>> for notification in notifications:
>-  ...     print notification['To']
>-  celso.providelo@xxxxxxxxxxxxx
>-  foo.bar@xxxxxxxxxxxxx
>-
>-If the failed build candidate is for a PPA where mark is a member,
>-he will be notified.
>-
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
>-  >>> team = factory.makeTeam(owner=cprov, email="team@xxxxxxxxxxx")
>-  >>> mark = failed_candidate.source_package_release.creator
>-  >>> ignored = team.addMember(mark, mark)
>-  >>> discard = pop_notifications() # Discard team join email.
>-  >>> team_ppa = factory.makeArchive(owner=team)
>-  >>> naked_candidate = removeSecurityProxy(failed_candidate)
>-  >>> naked_candidate.archive = team_ppa
>-  >>> naked_candidate.source_package_release.upload_archive = team_ppa
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
>-
>-  >>> failed_candidate.notify()
>-
>-This notification will be sent to the package uploader
>-(foo.bar@xxxxxxxxxxxxx), the package creator (mark@xxxxxxx) and the archive
>-team's contact address (team@xxxxxxxxxxx).
>-
>-  >>> notifications = pop_notifications()
>-  >>> len(notifications)
>-  3
>-
>-  >>> for notification in notifications:
>-  ...     print notification['To']
>-  foo.bar@xxxxxxxxxxxxx
>-  mark@xxxxxxxxxxx
>-  team@xxxxxxxxxxx
>-
>-
>-Named PPA notifications
>-=======================
>-
>-Named PPA build notifications contain a specific reference to the PPA
>-in context. We will override the testing build to be in the context of
>-a just created named-ppa for Celso.
>-
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
>-
>-  >>> from lp.soyuz.enums import ArchivePurpose
>-  >>> from lp.soyuz.interfaces.archive import IArchiveSet
>-  >>> named_ppa = getUtility(IArchiveSet).new(
>-  ...     owner=cprov, name='testing', purpose=ArchivePurpose.PPA)
>-
>-  >>> naked_candidate = removeSecurityProxy(failed_candidate)
>-  >>> naked_candidate.archive = named_ppa
>-
>-  >>> commit()
>-  >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser)
>-
>-As described before, copied sources result in one build notification
>-only, for the archive owner.
>-
>-  >>> failed_candidate.notify()
>-
>-  >>> notifications = pop_notifications()
>-  >>> for notification in notifications:
>-  ...     print notification['To']
>-  celso.providelo@xxxxxxxxxxxxx
>-
>-The build-notification subject and headers correctly point
>-to the named-ppa, 'cprov-testing'.
>-
>-  >>> build_notification = notifications.pop(0)
>-  >>> dump_build_notification(build_notification)
>-  Subject: [Build #26] i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE (cprov-testing PPA)
>-  X-Creator-Recipient: mark@xxxxxxxxxxx
>-  X-Launchpad-Build-State: FAILEDTOBUILD
>-  X-Launchpad-Build-Component: main
>-  X-Launchpad-Build-Arch: i386
>-  X-Launchpad-PPA: cprov-testing
>-
>-The build notification body contains a reference to the named PPA, and
>-the correct links to it the build in files in its context.
>-
>-  >>> notification_body = build_notification.get_payload(decode=True)
>-  >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
>-  <BLANKLINE>
>-   * Source Package: cdrkit
>-   * Version: 1.0
>-   * Architecture: i386
>-   * Archive: cprov-testing PPA
>-   * Component: main
>-   * State: Failed to build
>-   * Duration: a minute
>-   * Build Log: http://launchpad.dev/~cprov/+archive/testing/+buildjob/26/+files/netapplet-1.0.0.tar.gz
>-   * Builder: http://launchpad.dev/builders/bob
>-   * Source: not available
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  <BLANKLINE>
>-  If you want further information about this situation, feel free to
>-  contact a member of the Launchpad Buildd Administrators team.
>-  <BLANKLINE>
>-  --
>-  i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE
>-  http://launchpad.dev/~cprov/+archive/testing/+buildjob/26
>-  <BLANKLINE>
>
>=== added file 'lib/lp/soyuz/tests/test_build_notify.py'
>--- lib/lp/soyuz/tests/test_build_notify.py	1970-01-01 00:00:00 +0000
>+++ lib/lp/soyuz/tests/test_build_notify.py	2011-01-20 17:58:44 +0000
>@@ -0,0 +1,304 @@
>+# 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 textwrap import dedent
>+from zope.component import getUtility
>+
>+from canonical.launchpad.webapp import canonical_url
>+from canonical.testing.layers import LaunchpadFunctionalLayer
>+from lp.app.browser.tales import DurationFormatterAPI
>+from lp.archivepublisher.utils import get_ppa_reference
>+from lp.buildmaster.enums import BuildStatus
>+from lp.registry.interfaces.person import IPersonSet
>+from lp.soyuz.enums import ArchivePurpose
>+from lp.soyuz.interfaces.publishing import PackagePublishingPocket
>+from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
>+from lp.testing import (
>+    person_logged_in,
>+    TestCaseWithFactory,
>+    )
>+from lp.testing.mail_helpers import pop_notifications
>+from lp.testing.sampledata import ADMIN_EMAIL
>+
>+
>+class TestBuildNotify(TestCaseWithFactory):
>+
>+    layer = LaunchpadFunctionalLayer
>+
>+    def setUp(self):
>+        super(TestBuildNotify, self).setUp()
>+        self.admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
>+        # Create all of the items we need to create builds
>+        self.pf = self.factory.makeProcessorFamily()
>+        pf_proc = self.pf.addProcessor(self.factory.getUniqueString(), '', '')
>+        self.distroseries = self.factory.makeDistroSeries()
>+        self.das = self.factory.makeDistroArchSeries(
>+            distroseries=self.distroseries, processorfamily=self.pf,
>+            supports_virtualized=True)
>+        self.creator = self.factory.makePerson(email='test@xxxxxxxxxxx')
>+        self.archive = self.factory.makeArchive(
>+            distribution=self.distroseries.distribution,
>+            purpose=ArchivePurpose.PRIMARY)
>+        self.ppa = self.factory.makeArchive()
>+        with person_logged_in(self.admin):
>+            self.publisher = SoyuzTestPublisher()
>+            self.publisher.prepareBreezyAutotest()
>+            self.distroseries.nominatedarchindep = self.das
>+            self.publisher.addFakeChroots(distroseries=self.distroseries)
>+            self.builder = self.factory.makeBuilder(processor=pf_proc)
>+        self.builds = []
>+
>+    def create_builds(self, archive):
>+        for status in BuildStatus.items:
>+            spph = self.publisher.getPubSource(
>+                sourcename=self.factory.getUniqueString(),
>+                version="%s.%s" % (
>+                    self.factory.getUniqueInteger(), status.value),
>+                distroseries=self.distroseries, architecturehintlist='any',
>+                creator=self.creator, archive=archive)
>+            [build] = spph.createMissingBuilds()
>+            with person_logged_in(self.admin):
>+                build.status = status
>+                build.builder = self.builder
>+                if status != BuildStatus.BUILDING:
>+                    build.buildqueue_record.destroySelf()
>+                else:
>+                    build.buildqueue_record.builder = self.builder
>+                build.date_started = datetime.now(pytz.UTC)
>+                build.date_finished = build.date_started + timedelta(
>+                    minutes=5 * (status.value + 1))
>+            self.builds.append(build)
>+
>+    def _assert_mail_is_correct(self, build, notification, ppa=False):


A docstring would be helpful.


>+        self.assertEquals('test@xxxxxxxxxxx',
>+            notification['X-Creator-Recipient'])
>+        self.assertEquals(
>+            self.das.architecturetag, notification['X-Launchpad-Build-Arch'])
>+        self.assertEquals(
>+            'main', notification['X-Launchpad-Build-Component'])
>+        if ppa is True:
>+            self.assertEquals(
>+                get_ppa_reference(self.ppa), notification['X-Launchpad-PPA'])


This has a lots of separate assertions. This could be painful if
several of them are broken, and you have to rerun the test to find the
next error. It would be easier to understand how broken the headers are
if you put all the headers from the notification in a single sorted list
or string and compare them with the expected values.


>+        body = notification.get_payload(decode=True)
>+        duration = DurationFormatterAPI(build.duration).approximateduration()
>+        build_log = 'None'
>+        if ppa is True:
>+            archive = '%s PPA' % get_ppa_reference(build.archive)
>+            source = 'not available'
>+        else:
>+            archive = '%s primary archive' % (
>+                self.distroseries.distribution.name)
>+            source = canonical_url(build.distributionsourcepackagerelease)
>+        builder = canonical_url(build.builder)
>+        if build.status == BuildStatus.BUILDING:
>+            duration = 'not finished'
>+            build_log = 'see builder page'
>+        elif (
>+            build.status == BuildStatus.SUPERSEDED or 
>+            build.status == BuildStatus.NEEDSBUILD):
>+            duration = 'not available'
>+            build_log = 'not available'
>+            builder = 'not available'
>+        elif build.status == BuildStatus.UPLOADING:
>+            duration = 'uploading'
>+            build_log = 'see builder page'
>+            builder = 'not available'
>+        expected_body = dedent("""
>+         * Source Package: %s
>+         * Version: %s
>+         * Architecture: %s
>+         * Archive: %s
>+         * Component: main
>+         * State: %s
>+         * Duration: %s
>+         * Build Log: %s
>+         * Builder: %s
>+         * Source: %s
>+
>+
>+
>+        If you want further information about this situation, feel free to
>+        contact a member of the Launchpad Buildd Administrators team.
>+
>+        --
>+        %s
>+        %s
>+        """ % (
>+            build.source_package_release.sourcepackagename.name,
>+            build.source_package_release.version, self.das.architecturetag,
>+            archive, build.status.title, duration, build_log, builder,
>+            source, build.title, canonical_url(build)))
>+        self.assertEquals(expected_body, body)
>+
>+    def test_notify_buildd_admins(self):
>+        # A build will cause an e-mail to be sent out to the buildd-admins,
>+        # for primary archive builds.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.FAILEDTOBUILD.value]
>+        build.notify()
>+        notifications = pop_notifications()
>+        # There are 2 buildd-admins in the sample data, as well as the creator


End comment with a period, so that it doesn't look like something could
be missing.


>+        self.assertEquals(3, len(notifications))


It seems like it would be a good idea to test the actual
recipients of the notification. Something like this.
        notification_emails = [
            notification['To'] for notification in notifications]
        for email in self.buildd_admin_emails:
            self.assertIn(email, notification_emails)
        self.assertIn(build.creator.preferredemail.email, notification_emails)

It shouldn't be too hard to do this for most of the following tests.


>+
>+    def test_ppa_does_not_notify_buildd_admins(self):
>+        # A build for a PPA does not notify the buildd admins.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.FAILEDTOBUILD.value]
>+        build.notify()
>+        notifications = pop_notifications()
>+        # An e-mail is sent to the archive owner, as well as the creator
>+        self.assertEquals(2, len(notifications))
>+
>+    def test_notify_failed_to_build(self):
>+        # An e-mail is sent to the source package creator on build failures.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.FAILEDTOBUILD.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_failed_to_build_ppa(self):
>+        # An e-mail is sent to the source package creator on build failures.
>+        self.create_builds(archive=self.ppa)
>+        build = self.builds[BuildStatus.FAILEDTOBUILD.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_needs_building(self):
>+        # We can notify the creator when the build is needing to be built.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.NEEDSBUILD.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_needs_building_ppa(self):
>+        # We can notify the creator when the build is needing to be built.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.NEEDSBUILD.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_successfully_built(self):
>+        # We can notify the creator when the build is sucessful.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.FULLYBUILT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_successfully_built_ppa(self):
>+        # We can notify the creator when the build is sucessful.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.FULLYBUILT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_dependency_wait(self):
>+        # We can notify the creator when the build can't find a dependency.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.MANUALDEPWAIT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_dependency_wait_ppa(self):
>+        # We can notify the creator when the build can't find a dependency.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.MANUALDEPWAIT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_chroot_problem(self):
>+        # We can notify the creator when the builder the build attempted to
>+        # be built on has an internal problem.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.CHROOTWAIT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_chroot_problem_ppa(self):
>+        # We can notify the creator when the builder the build attempted to
>+        # be built on has an internal problem.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.CHROOTWAIT.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_build_for_superseded_source(self):
>+        # We can notify the creator when the source package had a newer
>+        # version uploaded before this build had a chance to be dispatched.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.SUPERSEDED.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_build_for_superseded_source_ppa(self):
>+        # We can notify the creator when the source package had a newer
>+        # version uploaded before this build had a chance to be dispatched.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.SUPERSEDED.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_currently_building(self):
>+        # We can notify the creator when the build is currently building.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.BUILDING.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_currently_building_ppa(self):
>+        # We can notify the creator when the build is currently building.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.BUILDING.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_notify_uploading_build(self):
>+        # We can notify the creator when the build has completed, and binary
>+        # packages are being uploaded by the builder.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.UPLOADING.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification)
>+
>+    def test_notify_uploading_build_ppa(self):
>+        # We can notify the creator when the build has completed, and binary
>+        # packages are being uploaded by the builder.
>+        self.create_builds(self.ppa)
>+        build = self.builds[BuildStatus.UPLOADING.value]
>+        build.notify()
>+        notification = pop_notifications()[1]
>+        self._assert_mail_is_correct(build, notification, ppa=True)
>+
>+    def test_copied_into_ppa_does_not_spam(self):
>+        # When a package is copied into a PPA, we don't send mail to the
>+        # original creator of the source package.
>+        self.create_builds(self.archive)
>+        build = self.builds[BuildStatus.FULLYBUILT.value]
>+        spph = build.current_source_publication
>+        ppa_spph = spph.copyTo(
>+            self.distroseries, PackagePublishingPocket.RELEASE, self.ppa)
>+        [ppa_build] = ppa_spph.createMissingBuilds()
>+        ppa_build.notify()
>+        notifications = pop_notifications()
>+        self.assertEquals(1, len(notifications))
-- 
https://code.launchpad.net/~stevenk/launchpad/bpb-currentcomponent-assertion-part-5/+merge/46852
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bpb-currentcomponent-assertion-part-5 into lp:launchpad.



References