← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/composeBuildRequest-deferred into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/composeBuildRequest-deferred into lp:launchpad with lp:~cjwatson/launchpad/archive-dependencies-unittest as a prerequisite.

Commit message:
Prepare for get_sources_list_for_building returning a Deferred.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/composeBuildRequest-deferred/+merge/323401

get_sources_list_for_building will soon need to return a Deferred so that it can asynchronously fetch archive signing keys from the keyserver.

composeBuildRequest and friends already returned a Deferred in the SnapBuildBehaviour case, so this mainly just extends that to all build types.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/composeBuildRequest-deferred into lp:launchpad.
=== modified file 'lib/lp/code/model/recipebuilder.py'
--- lib/lp/code/model/recipebuilder.py	2016-04-04 12:34:35 +0000
+++ lib/lp/code/model/recipebuilder.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Code to build recipes on the buildfarm."""
@@ -8,6 +8,7 @@
     'RecipeBuildBehaviour',
     ]
 
+from twisted.internet import defer
 from zope.component import adapter
 from zope.interface import implementer
 from zope.security.proxy import removeSecurityProxy
@@ -40,6 +41,7 @@
     # in this list.
     ALLOWED_STATUS_NOTIFICATIONS = ['PACKAGEFAIL', 'DEPFAIL', 'CHROOTFAIL']
 
+    @defer.inlineCallbacks
     def _extraBuildArgs(self, distroarchseries, logger=None):
         """
         Return the extra arguments required by the slave for the given build.
@@ -65,7 +67,7 @@
         args["ogrecomponent"] = get_primary_current_component(
             self.build.archive, self.build.distroseries,
             None).name
-        args['archives'] = get_sources_list_for_building(
+        args['archives'] = yield get_sources_list_for_building(
             self.build, distroarchseries, None,
             tools_source=config.builddmaster.bzr_builder_sources_list,
             logger=logger)
@@ -73,8 +75,9 @@
         args['distroseries_name'] = self.build.distroseries.name
         if self.build.recipe.base_git_repository is not None:
             args['git'] = True
-        return args
+        defer.returnValue(args)
 
+    @defer.inlineCallbacks
     def composeBuildRequest(self, logger):
         das = self.build.distroseries.getDistroArchSeriesByProcessor(
             self._builder.processor)
@@ -83,8 +86,8 @@
                 "Unable to find distroarchseries for %s in %s" %
                 (self._builder.processor.name,
                  self.build.distroseries.displayname))
-        args = self._extraBuildArgs(das, logger=logger)
-        return ("sourcepackagerecipe", das, {}, args)
+        args = yield self._extraBuildArgs(das, logger=logger)
+        defer.returnValue(("sourcepackagerecipe", das, {}, args))
 
     def verifyBuildRequest(self, logger):
         """Assert some pre-build checks.

=== modified file 'lib/lp/code/model/tests/test_recipebuilder.py'
--- lib/lp/code/model/tests/test_recipebuilder.py	2016-10-14 16:16:18 +0000
+++ lib/lp/code/model/tests/test_recipebuilder.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test RecipeBuildBehaviour."""
@@ -8,7 +8,9 @@
 import shutil
 import tempfile
 
+from testtools.deferredruntest import AsynchronousDeferredRunTest
 import transaction
+from twisted.internet import defer
 from twisted.trial.unittest import TestCase as TrialTestCase
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
@@ -49,7 +51,7 @@
 from lp.testing.mail_helpers import pop_notifications
 
 
-class TestRecipeBuilder(TestCaseWithFactory):
+class TestRecipeBuilderBase(TestCaseWithFactory):
 
     layer = LaunchpadZopelessLayer
 
@@ -88,6 +90,9 @@
         job = IBuildFarmJobBehaviour(spb)
         return job
 
+
+class TestRecipeBuilder(TestRecipeBuilderBase):
+
     def test_providesInterface(self):
         # RecipeBuildBehaviour provides IBuildFarmJobBehaviour.
         recipe_builder = RecipeBuildBehaviour(None)
@@ -130,22 +135,34 @@
             AssertionError, job.verifyBuildRequest, BufferLogger())
         self.assertIn('invalid pocket due to the series status of', str(e))
 
+    def test_getByID(self):
+        job = self.makeJob()
+        transaction.commit()
+        self.assertEqual(
+            job.build, SourcePackageRecipeBuild.getByID(job.build.id))
+
+
+class TestAsyncRecipeBuilder(TestRecipeBuilderBase):
+
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
+
     def _setBuilderConfig(self):
         """Setup a temporary builder config."""
         self.pushConfig(
             "builddmaster",
             bzr_builder_sources_list="deb http://foo %(series)s main")
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs(self):
         # _extraBuildArgs will return a sane set of additional arguments
         self._setBuilderConfig()
         job = self.makeJob()
         distroarchseries = job.build.distroseries.architectures[0]
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, distroarchseries, None)
         expected_archives.insert(
             0, "deb http://foo %s main" % job.build.distroseries.name)
-        args = job._extraBuildArgs(distroarchseries)
+        args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual({
             'archive_private': False,
             'arch_tag': 'i386',
@@ -161,6 +178,7 @@
             'distroseries_name': job.build.distroseries.name,
         }, args)
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_private_archive(self):
         # If the build archive is private, the archive_private flag is
         # True. This tells launchpad-buildd to redact credentials from
@@ -169,10 +187,11 @@
         archive = self.factory.makeArchive(private=True)
         job = self.makeJob(archive=archive)
         distroarchseries = job.build.distroseries.architectures[0]
-        extra_args = job._extraBuildArgs(distroarchseries)
+        extra_args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual(
             True, extra_args['archive_private'])
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_team_owner_no_email(self):
         # If the owner of the recipe is a team without a preferred email, the
         # registrant is used.
@@ -185,11 +204,12 @@
 
         job = self.makeJob(recipe_registrant, recipe_owner)
         distroarchseries = job.build.distroseries.architectures[0]
-        extra_args = job._extraBuildArgs(distroarchseries)
+        extra_args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual(
             "Launchpad Package Builder", extra_args['author_name'])
         self.assertEqual("noreply@xxxxxxxxxxxxx", extra_args['author_email'])
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_team_owner_with_email(self):
         # If the owner of the recipe is a team that has an email set, we use
         # that.
@@ -201,10 +221,11 @@
 
         job = self.makeJob(recipe_registrant, recipe_owner)
         distroarchseries = job.build.distroseries.architectures[0]
-        extra_args = job._extraBuildArgs(distroarchseries)
+        extra_args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual("Vikings", extra_args['author_name'])
         self.assertEqual("everyone@xxxxxxxxxxxx", extra_args['author_email'])
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_owner_deactivated(self):
         # If the owner is deactivated, they have no preferred email.
         self._setBuilderConfig()
@@ -213,11 +234,12 @@
             owner.deactivate(comment='deactivating')
         job = self.makeJob(owner)
         distroarchseries = job.build.distroseries.architectures[0]
-        extra_args = job._extraBuildArgs(distroarchseries)
+        extra_args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual(
             "Launchpad Package Builder", extra_args['author_name'])
         self.assertEqual("noreply@xxxxxxxxxxxxx", extra_args['author_email'])
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_withBadConfigForBzrBuilderPPA(self):
         # Ensure _extraBuildArgs doesn't blow up with a badly formatted
         # bzr_builder_sources_list in the config.
@@ -227,9 +249,10 @@
         # (note the missing 's' in %(series)
         job = self.makeJob()
         distroarchseries = job.build.distroseries.architectures[0]
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, distroarchseries, None)
         logger = BufferLogger()
+        extra_args = yield job._extraBuildArgs(distroarchseries, logger)
         self.assertEqual({
             'archive_private': False,
             'arch_tag': 'i386',
@@ -243,26 +266,29 @@
             'lp://dev/~joe/someapp/pkg\n',
             'archives': expected_archives,
             'distroseries_name': job.build.distroseries.name,
-        }, job._extraBuildArgs(distroarchseries, logger))
+            }, extra_args)
         self.assertIn(
             "Exception processing build tools sources.list entry:",
             logger.getLogBuffer())
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_withNoBZrBuilderConfigSet(self):
         # Ensure _extraBuildArgs doesn't blow up when
         # bzr_builder_sources_list isn't set.
         job = self.makeJob()
         distroarchseries = job.build.distroseries.architectures[0]
-        args = job._extraBuildArgs(distroarchseries)
-        expected_archives = get_sources_list_for_building(
+        args = yield job._extraBuildArgs(distroarchseries)
+        expected_archives = yield get_sources_list_for_building(
             job.build, distroarchseries, None)
         self.assertEqual(args["archives"], expected_archives)
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_git(self):
         job = self.makeJob(git=True)
         distroarchseries = job.build.distroseries.architectures[0]
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, distroarchseries, None)
+        extra_args = yield job._extraBuildArgs(distroarchseries)
         self.assertEqual({
             'archive_private': False,
             'arch_tag': 'i386',
@@ -278,14 +304,9 @@
             'archives': expected_archives,
             'distroseries_name': job.build.distroseries.name,
             'git': True,
-            }, job._extraBuildArgs(distroarchseries))
-
-    def test_getByID(self):
-        job = self.makeJob()
-        transaction.commit()
-        self.assertEquals(
-            job.build, SourcePackageRecipeBuild.getByID(job.build.id))
-
+            }, extra_args)
+
+    @defer.inlineCallbacks
     def test_composeBuildRequest(self):
         job = self.makeJob()
         test_publisher = SoyuzTestPublisher()
@@ -295,9 +316,9 @@
         builder.processor = das.processor
         job.setBuilder(builder, None)
         build_request = yield job.composeBuildRequest(None)
+        extra_args = yield job._extraBuildArgs(das)
         self.assertEqual(
-            ('sourcepackagerecipe', das, {}, job._extraBuildArgs(das)),
-            build_request)
+            ('sourcepackagerecipe', das, {}, extra_args), build_request)
 
 
 class TestBuildNotifications(TrialTestCase):

=== modified file 'lib/lp/snappy/model/snapbuildbehaviour.py'
--- lib/lp/snappy/model/snapbuildbehaviour.py	2016-12-05 23:11:57 +0000
+++ lib/lp/snappy/model/snapbuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2015-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """An `IBuildFarmJobBehaviour` for `SnapBuild`.
@@ -99,7 +99,7 @@
         args["arch_tag"] = build.distro_arch_series.architecturetag
         # XXX cjwatson 2015-08-03: Allow tools_source to be overridden at
         # some more fine-grained level.
-        args["archives"] = get_sources_list_for_building(
+        args["archives"] = yield get_sources_list_for_building(
             build, build.distro_arch_series, None,
             tools_source=config.snappy.tools_source, logger=logger)
         args["archive_private"] = build.archive.private

=== modified file 'lib/lp/snappy/tests/test_snapbuildbehaviour.py'
--- lib/lp/snappy/tests/test_snapbuildbehaviour.py	2017-01-27 12:44:41 +0000
+++ lib/lp/snappy/tests/test_snapbuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -168,7 +168,7 @@
 
 
 class TestAsyncSnapBuildBehaviour(TestSnapBuildBehaviourBase):
-    run_tests_with = AsynchronousDeferredRunTest
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
 
     def setUp(self):
         super(TestAsyncSnapBuildBehaviour, self).setUp()
@@ -211,7 +211,7 @@
         # job for a Bazaar branch.
         branch = self.factory.makeBranch()
         job = self.makeJob(branch=branch)
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, job.build.distro_arch_series, None)
         args = yield job._extraBuildArgs()
         self.assertEqual({
@@ -230,7 +230,7 @@
         # job for a Git branch.
         [ref] = self.factory.makeGitRefs()
         job = self.makeJob(git_ref=ref)
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, job.build.distro_arch_series, None)
         args = yield job._extraBuildArgs()
         self.assertEqual({
@@ -252,7 +252,7 @@
         ref = self.factory.makeGitRefRemote(
             repository_url=url, path=u"refs/heads/master")
         job = self.makeJob(git_ref=ref)
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, job.build.distro_arch_series, None)
         args = yield job._extraBuildArgs()
         self.assertEqual({

=== modified file 'lib/lp/soyuz/model/binarypackagebuildbehaviour.py'
--- lib/lp/soyuz/model/binarypackagebuildbehaviour.py	2016-04-04 12:34:35 +0000
+++ lib/lp/soyuz/model/binarypackagebuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Builder behaviour for binary package builds."""
@@ -9,6 +9,7 @@
     'BinaryPackageBuildBehaviour',
     ]
 
+from twisted.internet import defer
 from zope.interface import implementer
 
 from lp.buildmaster.interfaces.builder import CannotBuild
@@ -81,10 +82,12 @@
                     'password': self.build.archive.buildd_secret}
         return filemap
 
+    @defer.inlineCallbacks
     def composeBuildRequest(self, logger):
-        return (
-            "binarypackage", self.build.distro_arch_series,
-            self.determineFilesToSend(), self._extraBuildArgs(self.build))
+        args = yield self._extraBuildArgs(self.build, logger=logger)
+        defer.returnValue(
+            ("binarypackage", self.build.distro_arch_series,
+             self.determineFilesToSend(), args))
 
     def verifyBuildRequest(self, logger):
         """Assert some pre-build checks.
@@ -130,7 +133,8 @@
                     (build.title, build.id, build.pocket.name,
                      build.distro_series.name))
 
-    def _extraBuildArgs(self, build):
+    @defer.inlineCallbacks
+    def _extraBuildArgs(self, build, logger=None):
         """
         Return the extra arguments required by the slave for the given build.
         """
@@ -160,9 +164,9 @@
             args["ogrecomponent"] = (
                 build.current_component.name)
 
-        args['archives'] = get_sources_list_for_building(
-            build, das, build.source_package_release.name)
+        args['archives'] = yield get_sources_list_for_building(
+            build, das, build.source_package_release.name, logger=logger)
         args['archive_private'] = build.archive.private
         args['build_debug_symbols'] = build.archive.build_debug_symbols
 
-        return args
+        defer.returnValue(args)

=== modified file 'lib/lp/soyuz/model/livefsbuildbehaviour.py'
--- lib/lp/soyuz/model/livefsbuildbehaviour.py	2016-03-31 14:58:46 +0000
+++ lib/lp/soyuz/model/livefsbuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2014-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """An `IBuildFarmJobBehaviour` for `LiveFSBuild`.
@@ -11,6 +11,7 @@
     'LiveFSBuildBehaviour',
     ]
 
+from twisted.internet import defer
 from zope.component import adapter
 from zope.interface import implementer
 from zope.security.proxy import removeSecurityProxy
@@ -73,7 +74,8 @@
             raise CannotBuild(
                 "Missing chroot for %s" % build.distro_arch_series.displayname)
 
-    def _extraBuildArgs(self):
+    @defer.inlineCallbacks
+    def _extraBuildArgs(self, logger=None):
         """
         Return the extra arguments required by the slave for the given build.
         """
@@ -88,15 +90,15 @@
         args["pocket"] = build.pocket.name.lower()
         args["arch_tag"] = build.distro_arch_series.architecturetag
         args["datestamp"] = build.version
-        args["archives"] = get_sources_list_for_building(
-            build, build.distro_arch_series, None)
+        args["archives"] = yield get_sources_list_for_building(
+            build, build.distro_arch_series, None, logger=logger)
         args["archive_private"] = build.archive.private
-        return args
+        defer.returnValue(args)
 
+    @defer.inlineCallbacks
     def composeBuildRequest(self, logger):
-        return (
-            "livefs", self.build.distro_arch_series, {},
-            self._extraBuildArgs())
+        args = yield self._extraBuildArgs(logger=logger)
+        defer.returnValue(("livefs", self.build.distro_arch_series, {}, args))
 
     def verifySuccessfulBuild(self):
         """See `IBuildFarmJobBehaviour`."""

=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py	2017-04-28 17:42:31 +0000
+++ lib/lp/soyuz/tests/test_archive.py	2017-04-28 17:42:31 +0000
@@ -11,6 +11,7 @@
 import doctest
 
 from pytz import UTC
+from testtools.deferredruntest import AsynchronousDeferredRunTest
 from testtools.matchers import (
     AllMatch,
     DocTestMatches,
@@ -21,6 +22,7 @@
     )
 from testtools.testcase import ExpectedException
 import transaction
+from twisted.internet import defer
 from zope.component import getUtility
 from zope.security.interfaces import Unauthorized
 from zope.security.proxy import removeSecurityProxy
@@ -1746,7 +1748,9 @@
 class TestArchiveDependencies(TestCaseWithFactory):
 
     layer = LaunchpadZopelessLayer
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
 
+    @defer.inlineCallbacks
     def test_private_sources_list(self):
         """Entries for private dependencies include credentials."""
         p3a = self.factory.makeArchive(name='p3a', private=True)
@@ -1760,7 +1764,7 @@
                 PackagePublishingPocket.RELEASE)
             build = self.factory.makeBinaryPackageBuild(archive=p3a,
                 distroarchseries=bpph.distroarchseries)
-            sources_list = get_sources_list_for_building(
+            sources_list = yield get_sources_list_for_building(
                 build, build.distro_arch_series,
                 build.source_package_release.name)
             matches = MatchesRegex(
@@ -1945,6 +1949,7 @@
 class TestOverlays(TestCaseWithFactory):
 
     layer = LaunchpadZopelessLayer
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
 
     def _createDep(self, test_publisher, derived_series, parent_series,
                    parent_distro, component_name=None, pocket=None,
@@ -1978,6 +1983,7 @@
             component=component)
         return depseries, depdistro
 
+    @defer.inlineCallbacks
     def test_overlay_dependencies(self):
         # sources.list is properly generated for a complex overlay structure.
         # Pocket dependencies and component dependencies are taken into
@@ -2012,8 +2018,8 @@
         self._createDep(
             test_publisher, series11, 'series12', 'depdistro4', 'multiverse',
             PackagePublishingPocket.UPDATES)
-        sources_list = get_sources_list_for_building(build,
-            build.distro_arch_series, build.source_package_release.name)
+        sources_list = yield get_sources_list_for_building(
+            build, build.distro_arch_series, build.source_package_release.name)
 
         self.assertThat(
             "\n".join(sources_list),

=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py'
--- lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py	2016-04-07 00:04:42 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for BinaryPackageBuildBehaviour."""
@@ -55,9 +55,6 @@
 from lp.soyuz.adapters.archivedependencies import (
     get_sources_list_for_building,
     )
-from lp.soyuz.model.binarypackagebuildbehaviour import (
-    BinaryPackageBuildBehaviour,
-    )
 from lp.soyuz.enums import ArchivePurpose
 from lp.testing import TestCaseWithFactory
 from lp.testing.dbuser import switch_dbuser
@@ -75,21 +72,22 @@
     """
 
     layer = LaunchpadZopelessLayer
-    run_tests_with = AsynchronousDeferredRunTest
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
 
     def setUp(self):
         super(TestBinaryBuildPackageBehaviour, self).setUp()
         switch_dbuser('testadmin')
 
-    def assertExpectedInteraction(self, ignored, call_log, builder, build,
-                                  chroot, archive, archive_purpose,
-                                  component=None, extra_uploads=None,
-                                  filemap_names=None):
-        expected = self.makeExpectedInteraction(
+    @defer.inlineCallbacks
+    def assertExpectedInteraction(self, call_log, builder, build, chroot,
+                                  archive, archive_purpose, component=None,
+                                  extra_uploads=None, filemap_names=None):
+        expected = yield self.makeExpectedInteraction(
             builder, build, chroot, archive, archive_purpose, component,
             extra_uploads, filemap_names)
         self.assertEqual(expected, call_log)
 
+    @defer.inlineCallbacks
     def makeExpectedInteraction(self, builder, build, chroot, archive,
                                 archive_purpose, component=None,
                                 extra_uploads=None, filemap_names=None):
@@ -109,7 +107,7 @@
         das = build.distro_arch_series
         ds_name = das.distroseries.name
         suite = ds_name + pocketsuffix[build.pocket]
-        archives = get_sources_list_for_building(
+        archives = yield get_sources_list_for_building(
             build, das, build.source_package_release.name)
         arch_indep = das.isNominatedArchIndep
         if component is None:
@@ -138,8 +136,9 @@
             ('build', build.build_cookie, 'binarypackage',
              chroot.content.sha1, filemap_names, extra_args)]
         result = upload_logs + build_log
-        return result
+        defer.returnValue(result)
 
+    @defer.inlineCallbacks
     def test_non_virtual_ppa_dispatch(self):
         # When the BinaryPackageBuildBehaviour dispatches PPA builds to
         # non-virtual builders, it stores the chroot on the server and
@@ -159,14 +158,14 @@
         bq = build.queueBuild()
         bq.markAsBuilding(builder)
         interactor = BuilderInteractor()
-        d = interactor._startBuild(
+        yield interactor._startBuild(
             bq, vitals, builder, slave,
             interactor.getBuildBehaviour(bq, builder, slave), BufferLogger())
-        d.addCallback(
-            self.assertExpectedInteraction, slave.call_log, builder, build,
-            lf, archive, ArchivePurpose.PRIMARY, 'universe')
-        return d
+        yield self.assertExpectedInteraction(
+            slave.call_log, builder, build, lf, archive,
+            ArchivePurpose.PRIMARY, 'universe')
 
+    @defer.inlineCallbacks
     def test_non_virtual_ppa_dispatch_with_primary_ancestry(self):
         # If there is a primary component override, it is honoured for
         # non-virtual PPA builds too.
@@ -188,14 +187,14 @@
         bq = build.queueBuild()
         bq.markAsBuilding(builder)
         interactor = BuilderInteractor()
-        d = interactor._startBuild(
+        yield interactor._startBuild(
             bq, vitals, builder, slave,
             interactor.getBuildBehaviour(bq, builder, slave), BufferLogger())
-        d.addCallback(
-            self.assertExpectedInteraction, slave.call_log, builder, build,
-            lf, archive, ArchivePurpose.PRIMARY, 'main')
-        return d
+        yield self.assertExpectedInteraction(
+            slave.call_log, builder, build, lf, archive,
+            ArchivePurpose.PRIMARY, 'main')
 
+    @defer.inlineCallbacks
     def test_virtual_ppa_dispatch(self):
         archive = self.factory.makeArchive(virtualized=True)
         slave = OkSlave()
@@ -211,14 +210,13 @@
         bq = build.queueBuild()
         bq.markAsBuilding(builder)
         interactor = BuilderInteractor()
-        d = interactor._startBuild(
+        yield interactor._startBuild(
             bq, vitals, builder, slave,
             interactor.getBuildBehaviour(bq, builder, slave), BufferLogger())
-        d.addCallback(
-            self.assertExpectedInteraction, slave.call_log, builder, build,
-            lf, archive, ArchivePurpose.PPA)
-        return d
+        yield self.assertExpectedInteraction(
+            slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA)
 
+    @defer.inlineCallbacks
     def test_private_source_dispatch(self):
         archive = self.factory.makeArchive(private=True)
         slave = OkSlave()
@@ -243,16 +241,15 @@
         bq = build.queueBuild()
         bq.markAsBuilding(builder)
         interactor = BuilderInteractor()
-        d = interactor._startBuild(
+        yield interactor._startBuild(
             bq, vitals, builder, slave,
             interactor.getBuildBehaviour(bq, builder, slave), BufferLogger())
-        d.addCallback(
-            self.assertExpectedInteraction, slave.call_log, builder, build,
-            lf, archive, ArchivePurpose.PPA,
+        yield self.assertExpectedInteraction(
+            slave.call_log, builder, build, lf, archive, ArchivePurpose.PPA,
             extra_uploads=[(sprf_url, 'buildd', u'sekrit')],
             filemap_names=[sprf.libraryfile.filename])
-        return d
 
+    @defer.inlineCallbacks
     def test_partner_dispatch_no_publishing_history(self):
         archive = self.factory.makeArchive(
             virtualized=False, purpose=ArchivePurpose.PARTNER)
@@ -268,13 +265,12 @@
         bq = build.queueBuild()
         bq.markAsBuilding(builder)
         interactor = BuilderInteractor()
-        d = interactor._startBuild(
+        yield interactor._startBuild(
             bq, vitals, builder, slave,
             interactor.getBuildBehaviour(bq, builder, slave), BufferLogger())
-        d.addCallback(
-            self.assertExpectedInteraction, slave.call_log, builder, build,
-            lf, archive, ArchivePurpose.PARTNER)
-        return d
+        yield self.assertExpectedInteraction(
+            slave.call_log, builder, build, lf, archive,
+            ArchivePurpose.PARTNER)
 
     def test_dont_dispatch_release_builds(self):
         archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
@@ -318,18 +314,15 @@
             'Soyuz is not yet capable of building SECURITY uploads.',
             str(e))
 
+    @defer.inlineCallbacks
     def test_arch_indep(self):
         # BinaryPackageBuild.arch_indep is passed through to the slave.
         build = self.factory.makeBinaryPackageBuild(arch_indep=False)
-        self.assertIs(
-            False,
-            BinaryPackageBuildBehaviour(build)._extraBuildArgs(build)[
-                'arch_indep'])
+        extra_args = yield IBuildFarmJobBehaviour(build)._extraBuildArgs(build)
+        self.assertFalse(extra_args['arch_indep'])
         build = self.factory.makeBinaryPackageBuild(arch_indep=True)
-        self.assertIs(
-            True,
-            BinaryPackageBuildBehaviour(build)._extraBuildArgs(build)[
-                'arch_indep'])
+        extra_args = yield IBuildFarmJobBehaviour(build)._extraBuildArgs(build)
+        self.assertTrue(extra_args['arch_indep'])
 
     def test_verifyBuildRequest(self):
         # Don't allow a virtual build on a non-virtual builder.

=== modified file 'lib/lp/soyuz/tests/test_livefsbuildbehaviour.py'
--- lib/lp/soyuz/tests/test_livefsbuildbehaviour.py	2016-03-31 14:07:33 +0000
+++ lib/lp/soyuz/tests/test_livefsbuildbehaviour.py	2017-04-28 17:42:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2014-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2014-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test live filesystem build behaviour."""
@@ -9,7 +9,9 @@
 
 import fixtures
 import pytz
+from testtools.deferredruntest import AsynchronousDeferredRunTest
 import transaction
+from twisted.internet import defer
 from twisted.trial.unittest import TestCase as TrialTestCase
 from zope.component import getUtility
 from zope.security.proxy import Proxy
@@ -46,12 +48,12 @@
 from lp.testing.layers import LaunchpadZopelessLayer
 
 
-class TestLiveFSBuildBehaviour(TestCaseWithFactory):
+class TestLiveFSBuildBehaviourBase(TestCaseWithFactory):
 
     layer = LaunchpadZopelessLayer
 
     def setUp(self):
-        super(TestLiveFSBuildBehaviour, self).setUp()
+        super(TestLiveFSBuildBehaviourBase, self).setUp()
         self.useFixture(FeatureFixture({LIVEFS_FEATURE_FLAG: u"on"}))
 
     def makeJob(self, pocket=PackagePublishingPocket.RELEASE, **kwargs):
@@ -68,6 +70,9 @@
             name=u"test-livefs", **kwargs)
         return IBuildFarmJobBehaviour(build)
 
+
+class TestLiveFSBuildBehaviour(TestLiveFSBuildBehaviourBase):
+
     def test_provides_interface(self):
         # LiveFSBuildBehaviour provides IBuildFarmJobBehaviour.
         job = LiveFSBuildBehaviour(None)
@@ -157,13 +162,20 @@
         e = self.assertRaises(CannotBuild, job.verifyBuildRequest, logger)
         self.assertIn("Missing chroot", str(e))
 
+
+class TestAsyncLiveFSBuildBehaviour(TestLiveFSBuildBehaviourBase):
+
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=30)
+
+    @defer.inlineCallbacks
     def test_extraBuildArgs(self):
         # _extraBuildArgs returns a reasonable set of additional arguments.
         job = self.makeJob(
             date_created=datetime(2014, 4, 25, 10, 38, 0, tzinfo=pytz.UTC),
             metadata={"project": "distro", "subproject": "special"})
-        expected_archives = get_sources_list_for_building(
+        expected_archives = yield get_sources_list_for_building(
             job.build, job.build.distro_arch_series, None)
+        extra_args = yield job._extraBuildArgs()
         self.assertEqual({
             "archive_private": False,
             "archives": expected_archives,
@@ -173,35 +185,38 @@
             "project": "distro",
             "subproject": "special",
             "series": "unstable",
-            }, job._extraBuildArgs())
+            }, extra_args)
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_proposed(self):
         # _extraBuildArgs returns appropriate arguments if asked to build a
         # job for -proposed.
         job = self.makeJob(
             pocket=PackagePublishingPocket.PROPOSED,
             metadata={"project": "distro"})
-        args = job._extraBuildArgs()
+        args = yield job._extraBuildArgs()
         self.assertEqual("unstable", args["series"])
         self.assertEqual("proposed", args["pocket"])
 
+    @defer.inlineCallbacks
     def test_extraBuildArgs_no_security_proxy(self):
         # _extraBuildArgs returns an object without security wrapping, even
         # if values in the metadata are (say) lists and hence get proxied by
         # Zope.
         job = self.makeJob(metadata={"lb_args": ["--option=value"]})
-        args = job._extraBuildArgs()
+        args = yield job._extraBuildArgs()
         self.assertEqual(["--option=value"], args["lb_args"])
         self.assertIsNot(Proxy, type(args["lb_args"]))
 
+    @defer.inlineCallbacks
     def test_composeBuildRequest(self):
         job = self.makeJob()
         lfa = self.factory.makeLibraryFileAlias(db_only=True)
         job.build.distro_arch_series.addOrUpdateChroot(lfa)
         build_request = yield job.composeBuildRequest(None)
+        args = yield job._extraBuildArgs()
         self.assertEqual(
-            ('livefs', job.build.distro_arch_series, {},
-             job._extraBuildArgs()), build_request)
+            ('livefs', job.build.distro_arch_series, {}, args), build_request)
 
 
 class MakeLiveFSBuildMixin:


Follow ups