← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/ttb-not-ttbj into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/ttb-not-ttbj into lp:launchpad with lp:~wgrant/launchpad/no-bfjo-pls as a prerequisite.

Commit message:
Flip TranslationTemplatesBuild(Job) creation on its head; everything is now build-driven like the other BuildFarmJobs.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/ttb-not-ttbj/+merge/195195

Flip TTB(J) creation on its head. Rather than having TranslationTemplatesBuildJobSource.create() implicitly create a TTB and then a TTBJ and BQ to wrap it, we instead call TranslationTemplatesBuildSource.create().queueBuild() to match the BPB and SPRB API. This lets most code ignore TTBJs, which is handy because they'll soon cease to exist.
-- 
https://code.launchpad.net/~wgrant/launchpad/ttb-not-ttbj/+merge/195195
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/ttb-not-ttbj into lp:launchpad.
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py	2013-11-12 00:12:53 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py	2013-11-14 10:19:29 +0000
@@ -228,6 +228,16 @@
     def calculateScore():
         """Calculate the build queue priority for this job."""
 
+    def estimateDuration():
+        """Estimate the build duration."""
+
+    def queueBuild(suspended=False):
+        """Create a BuildQueue entry for this build.
+
+        :param suspended: Whether the associated `Job` instance should be
+            created in a suspended state.
+        """
+
     title = exported(TextLine(title=_("Title"), required=False),
                      as_of="beta")
 

=== modified file 'lib/lp/buildmaster/interfaces/packagebuild.py'
--- lib/lp/buildmaster/interfaces/packagebuild.py	2013-02-04 06:58:14 +0000
+++ lib/lp/buildmaster/interfaces/packagebuild.py	2013-11-14 10:19:29 +0000
@@ -69,9 +69,6 @@
             title=_("Distribution series"), required=True,
             description=_("Shortcut for its distribution series.")))
 
-    def estimateDuration():
-        """Estimate the build duration."""
-
     def verifySuccessfulUpload():
         """Verify that the upload of this build completed succesfully."""
 
@@ -91,13 +88,6 @@
             upload log.
         """
 
-    def queueBuild(suspended=False):
-        """Create a BuildQueue entry for this build.
-
-        :param suspended: Whether the associated `Job` instance should be
-            created in a suspended state.
-        """
-
     def getUploader(changes):
         """Return the person responsible for the upload.
 

=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py	2013-11-12 00:12:53 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py	2013-11-14 10:19:29 +0000
@@ -39,6 +39,7 @@
     IBuildFarmJobSet,
     IBuildFarmJobSource,
     )
+from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import (
     IMasterStore,
@@ -223,6 +224,28 @@
         """See `IBuildFarmJob`."""
         raise NotImplementedError
 
+    def estimateDuration(self):
+        """See `IBuildFarmJob`."""
+        raise NotImplementedError
+
+    def queueBuild(self, suspended=False):
+        """See `IBuildFarmJob`."""
+        specific_job = self.makeJob()
+
+        # This build queue job is to be created in a suspended state.
+        if suspended:
+            specific_job.job.suspend()
+
+        duration_estimate = self.estimateDuration()
+        job = specific_job.job
+        queue_entry = BuildQueue(
+            estimated_duration=duration_estimate,
+            job_type=self.job_type,
+            job=job, processor=self.processor,
+            virtualized=self.virtualized)
+        Store.of(self).add(queue_entry)
+        return queue_entry
+
 
 class SpecificBuildFarmJobSourceMixin:
 

=== modified file 'lib/lp/buildmaster/model/packagebuild.py'
--- lib/lp/buildmaster/model/packagebuild.py	2013-11-11 07:17:29 +0000
+++ lib/lp/buildmaster/model/packagebuild.py	2013-11-14 10:19:29 +0000
@@ -9,12 +9,10 @@
 
 from cStringIO import StringIO
 
-from storm.locals import Store
 from zope.component import getUtility
 
 from lp.buildmaster.enums import BuildStatus
 from lp.buildmaster.model.buildfarmjob import BuildFarmJobMixin
-from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.services.helpers import filenameToContentType
 from lp.services.librarian.browser import ProxiedLibraryFileAlias
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
@@ -50,10 +48,6 @@
         """See `IBuildFarmJob`"""
         return self.archive.private
 
-    def estimateDuration(self):
-        """See `IPackageBuild`."""
-        raise NotImplementedError
-
     def updateStatus(self, status, builder=None, slave_status=None,
                      date_started=None, date_finished=None):
         super(PackageBuildMixin, self).updateStatus(
@@ -109,21 +103,3 @@
     def getUploader(self, changes):
         """See `IPackageBuild`."""
         raise NotImplementedError
-
-    def queueBuild(self, suspended=False):
-        """See `IPackageBuild`."""
-        specific_job = self.makeJob()
-
-        # This build queue job is to be created in a suspended state.
-        if suspended:
-            specific_job.job.suspend()
-
-        duration_estimate = self.estimateDuration()
-        job = specific_job.job
-        queue_entry = BuildQueue(
-            estimated_duration=duration_estimate,
-            job_type=self.job_type,
-            job=job, processor=self.processor,
-            virtualized=self.virtualized)
-        Store.of(self).add(queue_entry)
-        return queue_entry

=== modified file 'lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py'
--- lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py	2013-11-12 09:07:01 +0000
+++ lib/lp/buildmaster/tests/test_buildfarmjobbehavior.py	2013-11-14 10:19:29 +0000
@@ -69,7 +69,7 @@
             distroarchseries=distroarchseries, pocket=pocket, archive=archive)
 
     def test_getBuildCookie(self):
-        build = self.factory.makeTranslationTemplatesBuildJob().build
+        build = self.factory.makeTranslationTemplatesBuild()
         behavior = self._makeBehavior(build)
         self.assertEqual(
             '%s-%s' % (build.job_type.name, build.id),

=== modified file 'lib/lp/codehosting/scanner/bzrsync.py'
--- lib/lp/codehosting/scanner/bzrsync.py	2012-06-26 10:23:26 +0000
+++ lib/lp/codehosting/scanner/bzrsync.py	2013-11-14 10:19:29 +0000
@@ -35,8 +35,8 @@
 from lp.codehosting.scanner import events
 from lp.services.config import config
 from lp.services.utils import iter_list_chunks
-from lp.translations.interfaces.translationtemplatesbuildjob import (
-    ITranslationTemplatesBuildJobSource,
+from lp.translations.interfaces.translationtemplatesbuild import (
+    ITranslationTemplatesBuildSource,
     )
 
 
@@ -313,7 +313,7 @@
 
 
 def schedule_translation_templates_build(tip_changed):
-    utility = getUtility(ITranslationTemplatesBuildJobSource)
+    utility = getUtility(ITranslationTemplatesBuildSource)
     utility.scheduleTranslationTemplatesBuild(tip_changed.db_branch)
 
 

=== modified file 'lib/lp/soyuz/browser/tests/test_builder.py'
--- lib/lp/soyuz/browser/tests/test_builder.py	2013-11-14 07:36:26 +0000
+++ lib/lp/soyuz/browser/tests/test_builder.py	2013-11-14 10:19:29 +0000
@@ -9,8 +9,6 @@
 from zope.component import getUtility
 
 from lp.buildmaster.interfaces.builder import IBuilderSet
-from lp.buildmaster.model.buildqueue import BuildQueue
-from lp.services.database.interfaces import IStore
 from lp.services.job.model.job import Job
 from lp.soyuz.browser.tests.test_builder_views import BuildCreationMixin
 from lp.testing import (
@@ -20,9 +18,6 @@
 from lp.testing.layers import LaunchpadFunctionalLayer
 from lp.testing.matchers import HasQueryCount
 from lp.testing.views import create_initialized_view
-from lp.translations.interfaces.translationtemplatesbuildjob import (
-    ITranslationTemplatesBuildJobSource,
-    )
 
 
 def builders_homepage_render():
@@ -43,7 +38,7 @@
         # even further, detecting more preloading issues.
         self.factory.makeBinaryPackageBuild().queueBuild()
         self.factory.makeSourcePackageRecipeBuild().queueBuild()
-        self.factory.makeTranslationTemplatesBuildJob()
+        self.factory.makeTranslationTemplatesBuild().queueBuild()
 
     def test_builders_binary_package_build_query_count(self):
         def create_build():
@@ -69,11 +64,7 @@
 
     def test_builders_translation_template_build_query_count(self):
         def create_build():
-            jobset = getUtility(ITranslationTemplatesBuildJobSource)
-            branch = self.factory.makeBranch()
-            specific_job = jobset.create(branch)
-            queue = IStore(BuildQueue).find(
-                BuildQueue, job=specific_job.job).one()
+            queue = self.factory.makeTranslationTemplatesBuild().queueBuild()
             queue.markAsBuilding(self.factory.makeBuilder())
 
         nb_objects = 2

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2013-11-14 07:36:26 +0000
+++ lib/lp/testing/factory.py	2013-11-14 10:19:29 +0000
@@ -96,10 +96,7 @@
     ICveSet,
     )
 from lp.bugs.model.bug import FileBugData
-from lp.buildmaster.enums import (
-    BuildFarmJobType,
-    BuildStatus,
-    )
+from lp.buildmaster.enums import BuildStatus
 from lp.buildmaster.interfaces.builder import IBuilderSet
 from lp.code.enums import (
     BranchMergeProposalStatus,
@@ -333,8 +330,8 @@
     RosettaTranslationOrigin,
     )
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
-from lp.translations.interfaces.translationtemplatesbuildjob import (
-    ITranslationTemplatesBuildJobSource,
+from lp.translations.interfaces.translationtemplatesbuild import (
+    ITranslationTemplatesBuildSource,
     )
 from lp.translations.interfaces.translator import ITranslatorSet
 from lp.translations.model.translationtemplateitem import (
@@ -2866,16 +2863,16 @@
         IStore(spr_build).flush()
         return spr_build
 
-    def makeTranslationTemplatesBuildJob(self, branch=None):
-        """Make a new `TranslationTemplatesBuildJob`.
+    def makeTranslationTemplatesBuild(self, branch=None):
+        """Make a new `TranslationTemplatesBuild`.
 
-        :param branch: The branch that the job should be for.  If none
+        :param branch: The branch that the build should be for.  If none
             is given, one will be created.
         """
         if branch is None:
             branch = self.makeBranch()
 
-        jobset = getUtility(ITranslationTemplatesBuildJobSource)
+        jobset = getUtility(ITranslationTemplatesBuildSource)
         return jobset.create(branch)
 
     def makePOTemplate(self, productseries=None, distroseries=None,

=== modified file 'lib/lp/translations/interfaces/translationtemplatesbuild.py'
--- lib/lp/translations/interfaces/translationtemplatesbuild.py	2013-01-31 10:38:23 +0000
+++ lib/lp/translations/interfaces/translationtemplatesbuild.py	2013-11-14 10:19:29 +0000
@@ -35,3 +35,13 @@
 
     def findByBranch(branch, store=None):
         """Find `ITranslationTemplatesBuild`s for `branch`."""
+
+    def generatesTemplates(branch):
+        """Can this branch usefully generate translation templates?
+
+        If yes, then use `create` to schedule a build-farm job to
+        generate the templates based on the source code in the branch.
+        """
+
+    def scheduleTranslationTemplatesBuild(branch):
+        """Schedule a translation templates build job, if appropriate."""

=== modified file 'lib/lp/translations/interfaces/translationtemplatesbuildjob.py'
--- lib/lp/translations/interfaces/translationtemplatesbuildjob.py	2013-01-07 02:40:55 +0000
+++ lib/lp/translations/interfaces/translationtemplatesbuildjob.py	2013-11-14 10:19:29 +0000
@@ -13,25 +13,5 @@
 class ITranslationTemplatesBuildJobSource(Interface):
     """Container for `TranslationTemplatesBuildJob`s."""
 
-    def generatesTemplates(branch):
-        """Can this branch usefully generate translation templates?
-
-        If yes, then use `create` to schedule a build-farm job to
-        generate the templates based on the source code in the branch.
-        """
-
-    def create(branch):
-        """Create new `TranslationTemplatesBuildJob`.
-
-        Also creates the matching `IBuildQueue` and `IJob`.
-
-        :param branch: A `Branch` that this job will check out and
-            generate templates for.
-        :return: A new `TranslationTemplatesBuildJob`.
-        """
-
-    def scheduleTranslationTemplatesBuild(branch):
-        """Schedule a translation templates build job, if appropriate."""
-
     def getByBranch(branch):
         """Find `TranslationTemplatesBuildJob` for given `Branch`."""

=== modified file 'lib/lp/translations/model/translationtemplatesbuild.py'
--- lib/lp/translations/model/translationtemplatesbuild.py	2013-11-12 00:12:53 +0000
+++ lib/lp/translations/model/translationtemplatesbuild.py	2013-11-14 10:19:29 +0000
@@ -9,12 +9,16 @@
     'TranslationTemplatesBuild',
     ]
 
+from datetime import timedelta
+import logging
+
 import pytz
 from storm.locals import (
     Bool,
     DateTime,
     Int,
     Reference,
+    Store,
     Storm,
     )
 from zope.component import getUtility
@@ -22,6 +26,7 @@
     classProvides,
     implements,
     )
+from zope.security.proxy import removeSecurityProxy
 
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.buildmaster.enums import (
@@ -33,6 +38,7 @@
     BuildFarmJobMixin,
     SpecificBuildFarmJobSourceMixin,
     )
+from lp.code.interfaces.branchjob import IRosettaUploadJobSource
 from lp.code.model.branch import Branch
 from lp.code.model.branchcollection import GenericBranchCollection
 from lp.code.model.branchjob import (
@@ -40,6 +46,7 @@
     BranchJobType,
     )
 from lp.registry.model.product import Product
+from lp.services.config import config
 from lp.services.database.bulk import load_related
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
@@ -51,6 +58,7 @@
 from lp.translations.model.translationtemplatesbuildjob import (
     TranslationTemplatesBuildJob,
     )
+from lp.translations.pottery.detect_intltool import is_intltool_structure
 
 
 HARDCODED_TRANSLATIONTEMPLATESBUILD_SCORE = 2510
@@ -105,11 +113,14 @@
         self.branch = branch
         self.status = BuildStatus.NEEDSBUILD
         self.processor = processor
+        self.virtualized = True
+
+    def estimateDuration(self):
+        """See `IBuildFarmJob`."""
+        return timedelta(seconds=10)
 
     def makeJob(self):
-        """See `IBuildFarmJobOld`."""
-        store = IStore(BranchJob)
-
+        """See `IBuildFarmJob`."""
         # Pass public HTTP URL for the branch.
         metadata = {
             'branch_url': self.branch.composePublicURL(),
@@ -117,7 +128,7 @@
             }
         branch_job = BranchJob(
             self.branch, BranchJobType.TRANSLATION_TEMPLATES_BUILD, metadata)
-        store.add(branch_job)
+        Store.of(self).add(branch_job)
         return TranslationTemplatesBuildJob(branch_job)
 
     @classmethod
@@ -138,6 +149,42 @@
         return ubuntu.currentseries.nominatedarchindep.processor
 
     @classmethod
+    def _hasPotteryCompatibleSetup(cls, branch):
+        """Does `branch` look as if pottery can generate templates for it?
+
+        :param branch: A `Branch` object.
+        """
+        bzr_branch = removeSecurityProxy(branch).getBzrBranch()
+        return is_intltool_structure(bzr_branch.basis_tree())
+
+    @classmethod
+    def generatesTemplates(cls, branch):
+        """See `ITranslationTemplatesBuildJobSource`."""
+        logger = logging.getLogger('translation-templates-build')
+        if branch.private:
+            # We don't support generating template from private branches
+            # at the moment.
+            logger.debug("Branch %s is private.", branch.unique_name)
+            return False
+
+        utility = getUtility(IRosettaUploadJobSource)
+        if not utility.providesTranslationFiles(branch):
+            # Nobody asked for templates generated from this branch.
+            logger.debug(
+                    "No templates requested for branch %s.",
+                    branch.unique_name)
+            return False
+
+        if not cls._hasPotteryCompatibleSetup(branch):
+            # Nothing we could do with this branch if we wanted to.
+            logger.debug(
+                "Branch %s is not pottery-compatible.", branch.unique_name)
+            return False
+
+        # Yay!  We made it.
+        return True
+
+    @classmethod
     def create(cls, branch):
         """See `ITranslationTemplatesBuildSource`."""
         processor = cls._getBuildArch()
@@ -150,6 +197,26 @@
         return build
 
     @classmethod
+    def scheduleTranslationTemplatesBuild(cls, branch):
+        """See `ITranslationTemplatesBuildJobSource`."""
+        logger = logging.getLogger('translation-templates-build')
+        if not config.rosetta.generate_templates:
+            # This feature is disabled by default.
+            logging.debug("Templates generation is disabled.")
+            return
+
+        try:
+            if cls.generatesTemplates(branch):
+                # This branch is used for generating templates.
+                logger.info(
+                    "Requesting templates build for branch %s.",
+                    branch.unique_name)
+                cls.create(branch).queueBuild()
+        except Exception as e:
+            logger.error(e)
+            raise
+
+    @classmethod
     def getByID(cls, build_id, store=None):
         """See `ITranslationTemplatesBuildSource`."""
         store = cls._getStore(store)

=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
--- lib/lp/translations/model/translationtemplatesbuildjob.py	2013-11-12 00:12:53 +0000
+++ lib/lp/translations/model/translationtemplatesbuildjob.py	2013-11-14 10:19:29 +0000
@@ -6,40 +6,28 @@
     'TranslationTemplatesBuildJob',
     ]
 
-from datetime import timedelta
-import logging
-
 from storm.store import Store
 from zope.component import getUtility
 from zope.interface import (
     classProvides,
     implements,
     )
-from zope.security.proxy import removeSecurityProxy
 
-from lp.buildmaster.enums import BuildFarmJobType
 from lp.buildmaster.interfaces.buildfarmbranchjob import IBuildFarmBranchJob
 from lp.buildmaster.model.buildfarmjob import BuildFarmJobOld
-from lp.buildmaster.model.buildqueue import BuildQueue
-from lp.code.interfaces.branchjob import IRosettaUploadJobSource
 from lp.code.model.branchjob import (
     BranchJob,
     BranchJobDerived,
     BranchJobType,
     )
-from lp.services.config import config
 from lp.services.database.bulk import load_related
-from lp.services.database.interfaces import (
-    IMasterStore,
-    IStore,
-    )
+from lp.services.database.interfaces import IStore
 from lp.translations.interfaces.translationtemplatesbuild import (
     ITranslationTemplatesBuildSource,
     )
 from lp.translations.interfaces.translationtemplatesbuildjob import (
     ITranslationTemplatesBuildJobSource,
     )
-from lp.translations.pottery.detect_intltool import is_intltool_structure
 
 
 class TranslationTemplatesBuildJob(BuildFarmJobOld, BranchJobDerived):
@@ -52,8 +40,6 @@
 
     classProvides(ITranslationTemplatesBuildJobSource)
 
-    duration_estimate = timedelta(seconds=10)
-
     def cleanUp(self):
         """See `IBuildFarmJob`."""
         # This class is not itself database-backed.  But it delegates to
@@ -73,88 +59,6 @@
                 int(build_id))
 
     @classmethod
-    def _hasPotteryCompatibleSetup(cls, branch):
-        """Does `branch` look as if pottery can generate templates for it?
-
-        :param branch: A `Branch` object.
-        """
-        bzr_branch = removeSecurityProxy(branch).getBzrBranch()
-        return is_intltool_structure(bzr_branch.basis_tree())
-
-    @classmethod
-    def generatesTemplates(cls, branch):
-        """See `ITranslationTemplatesBuildJobSource`."""
-        logger = logging.getLogger('translation-templates-build')
-        if branch.private:
-            # We don't support generating template from private branches
-            # at the moment.
-            logger.debug("Branch %s is private.", branch.unique_name)
-            return False
-
-        utility = getUtility(IRosettaUploadJobSource)
-        if not utility.providesTranslationFiles(branch):
-            # Nobody asked for templates generated from this branch.
-            logger.debug(
-                    "No templates requested for branch %s.",
-                    branch.unique_name)
-            return False
-
-        if not cls._hasPotteryCompatibleSetup(branch):
-            # Nothing we could do with this branch if we wanted to.
-            logger.debug(
-                "Branch %s is not pottery-compatible.", branch.unique_name)
-            return False
-
-        # Yay!  We made it.
-        return True
-
-    @classmethod
-    def create(cls, branch, testing=False):
-        """See `ITranslationTemplatesBuildJobSource`."""
-        logger = logging.getLogger('translation-templates-build')
-
-        build = getUtility(ITranslationTemplatesBuildSource).create(
-            branch)
-        logger.debug("Made TranslationTemplatesBuild %s.", build.id)
-
-        specific_job = build.makeJob()
-        if testing:
-            removeSecurityProxy(specific_job)._constructed_build = build
-        logger.debug("Made %s.", specific_job)
-
-        duration_estimate = cls.duration_estimate
-
-        build_queue_entry = BuildQueue(
-            estimated_duration=duration_estimate,
-            job_type=BuildFarmJobType.TRANSLATIONTEMPLATESBUILD,
-            job=specific_job.job, processor=build.processor)
-        IMasterStore(BuildQueue).add(build_queue_entry)
-
-        logger.debug("Made BuildQueue %s.", build_queue_entry.id)
-
-        return specific_job
-
-    @classmethod
-    def scheduleTranslationTemplatesBuild(cls, branch):
-        """See `ITranslationTemplatesBuildJobSource`."""
-        logger = logging.getLogger('translation-templates-build')
-        if not config.rosetta.generate_templates:
-            # This feature is disabled by default.
-            logging.debug("Templates generation is disabled.")
-            return
-
-        try:
-            if cls.generatesTemplates(branch):
-                # This branch is used for generating templates.
-                logger.info(
-                    "Requesting templates build for branch %s.",
-                    branch.unique_name)
-                cls.create(branch)
-        except Exception as e:
-            logger.error(e)
-            raise
-
-    @classmethod
     def getByJob(cls, job):
         """See `IBuildFarmJob`.
 

=== modified file 'lib/lp/translations/stories/buildfarm/xx-build-summary.txt'
--- lib/lp/translations/stories/buildfarm/xx-build-summary.txt	2013-09-02 08:11:21 +0000
+++ lib/lp/translations/stories/buildfarm/xx-build-summary.txt	2013-11-14 10:19:29 +0000
@@ -12,10 +12,8 @@
     >>> from testtools.monkey import patch
     >>> from zope.component import getUtility
     >>> from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-    >>> from lp.buildmaster.model.buildqueue import BuildQueue
     >>> from lp.app.enums import ServiceUsage
     >>> from lp.buildmaster.interactor import BuilderSlave
-    >>> from lp.services.database.interfaces import IStore
     >>> from lp.services.librarian.interfaces import (
     ...     ILibraryFileAliasSet)
     >>> from lp.testing.factory import (
@@ -45,9 +43,8 @@
     >>> naked_productseries.branch = factory.makeBranch()
     >>> naked_productseries.translations_autoimport_mode = (
     ...     TranslationsBranchImportMode.IMPORT_TEMPLATES)
-    >>> specific_job = factory.makeTranslationTemplatesBuildJob(branch=branch)
-    >>> buildqueue = IStore(BuildQueue).find(
-    ...     BuildQueue, job=specific_job.job).one()
+    >>> build = factory.makeTranslationTemplatesBuild(branch=branch)
+    >>> buildqueue = build.queueBuild()
 
     >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1]
     >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu

=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuild.py'
--- lib/lp/translations/tests/test_translationtemplatesbuild.py	2013-11-12 07:39:51 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuild.py	2013-11-14 10:19:29 +0000
@@ -7,12 +7,23 @@
 
 from storm.store import Store
 from zope.component import getUtility
+from zope.event import notify
 from zope.interface.verify import verifyObject
+from zope.security.proxy import removeSecurityProxy
 
+from lp.app.enums import InformationType
+from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
+from lp.code.model.branchjob import BranchJob
+from lp.code.model.directbranchcommit import DirectBranchCommit
+from lp.codehosting.scanner import events
+from lp.services.database.interfaces import IStore
 from lp.testing import TestCaseWithFactory
 from lp.testing.dbuser import switch_dbuser
 from lp.testing.layers import LaunchpadZopelessLayer
+from lp.translations.interfaces.translations import (
+    TranslationsBranchImportMode,
+    )
 from lp.translations.interfaces.translationtemplatesbuild import (
     ITranslationTemplatesBuild,
     ITranslationTemplatesBuildSource,
@@ -20,12 +31,76 @@
 from lp.translations.model.translationtemplatesbuild import (
     TranslationTemplatesBuild,
     )
+from lp.translations.model.translationtemplatesbuildjob import (
+    TranslationTemplatesBuildJob,
+    )
+
+
+class FakeTranslationTemplatesSource(TranslationTemplatesBuild):
+    """Fake utility class.
+
+    Allows overriding of _hasPotteryCompatibleSetup.
+
+    How do you fake a utility that is implemented as a class, not a
+    factory?  By inheriting from `TranslationTemplatesBuild`, this class
+    "copies" the utility.  But you can make it fake the utility's
+    behavior by setting an attribute of the class (not an object!) at
+    the beginning of every test.
+    """
+    # Fake _hasPotteryCompatibleSetup, and if so, make it give what
+    # answer?
+    fake_pottery_compatibility = None
+
+    @classmethod
+    def _hasPotteryCompatibleSetup(cls, branch):
+        if cls.fake_pottery_compatibility is None:
+            # No fake compatibility setting call the real method.
+            return TranslationTemplatesBuild._hasPotteryCompatibleSetup(
+                branch)
+        else:
+            # Fake pottery compatibility.
+            return cls.fake_pottery_compatibility
 
 
 class TestTranslationTemplatesBuild(TestCaseWithFactory):
 
     layer = LaunchpadZopelessLayer
 
+    def setUp(self):
+        super(TestTranslationTemplatesBuild, self).setUp()
+        self.jobsource = FakeTranslationTemplatesSource
+        self.jobsource.fake_pottery_compabitility = None
+
+    def tearDown(self):
+        self._fakePotteryCompatibleSetup(compatible=None)
+        super(TestTranslationTemplatesBuild, self).tearDown()
+
+    def _makeTranslationBranch(self, fake_pottery_compatible=None):
+        """Create a branch that provides translations for a productseries."""
+        if fake_pottery_compatible is None:
+            self.useBzrBranches(direct_database=True)
+            branch, tree = self.create_branch_and_tree()
+        else:
+            branch = self.factory.makeAnyBranch()
+        product = removeSecurityProxy(branch.product)
+        trunk = product.getSeries('trunk')
+        trunk.branch = branch
+        trunk.translations_autoimport_mode = (
+            TranslationsBranchImportMode.IMPORT_TEMPLATES)
+
+        self._fakePotteryCompatibleSetup(fake_pottery_compatible)
+
+        return branch
+
+    def _fakePotteryCompatibleSetup(self, compatible=True):
+        """Mock up branch compatibility check.
+
+        :param compatible: Whether the mock check should say that
+            branches have a pottery-compatible setup, or that they
+            don't.
+        """
+        self.jobsource.fake_pottery_compatibility = compatible
+
     def test_baseline(self):
         branch = self.factory.makeBranch()
         build = getUtility(ITranslationTemplatesBuildSource).create(branch)
@@ -45,23 +120,95 @@
         # restrictions.
         Store.of(build).flush()
 
-    def test_created_by_buildjobsource(self):
-        # ITranslationTemplatesBuildJobSource.create also creates a
-        # TranslationTemplatesBuild.  This utility will become obsolete
-        # later.
-        source = getUtility(ITranslationTemplatesBuildSource)
-        branch = self.factory.makeBranch()
-        source.create(branch)
+    def test_queueBuild(self):
+        build = self.factory.makeTranslationTemplatesBuild()
+        bq = build.queueBuild()
+        self.assertEqual(build, bq.specific_job.build)
+        self.assertEqual(build, bq.specific_build)
+        ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
+        self.assertEquals(
+            ubuntu.currentseries.nominatedarchindep.processor, bq.processor)
 
-        builds = list(source.findByBranch(branch))
-        self.assertEqual(1, len(builds))
-        self.assertIsInstance(builds[0], TranslationTemplatesBuild)
+        # A job is created with the branch URL in its metadata.
+        metadata = bq.specific_job.metadata
+        self.assertIn('branch_url', metadata)
+        url = metadata['branch_url']
+        head = 'http://'
+        self.assertEqual(head, url[:len(head)])
+        tail = build.branch.name
+        self.assertEqual(tail, url[-len(tail):])
 
     def test_score(self):
         # For now, these jobs always score themselves at 2510.  In the
         # future however the scoring system is to be revisited.
-        job = self.factory.makeTranslationTemplatesBuildJob()
-        self.assertEqual(2510, job.build.calculateScore())
+        build = self.factory.makeTranslationTemplatesBuild()
+        self.assertEqual(2510, build.calculateScore())
+
+    def test_generatesTemplates(self):
+        # A branch "generates templates" if it is a translation branch
+        # for a productseries that imports templates from it; is not
+        # private; and has a pottery compatible setup.
+        # For convenience we fake the pottery compatibility here.
+        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
+        self.assertTrue(self.jobsource.generatesTemplates(branch))
+
+    def test_not_pottery_compatible(self):
+        # If pottery does not see any files it can work with in the
+        # branch, generatesTemplates returns False.
+        branch = self._makeTranslationBranch()
+        self.assertFalse(self.jobsource.generatesTemplates(branch))
+
+    def test_branch_not_used(self):
+        # We don't generate templates branches not attached to series.
+        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
+
+        trunk = branch.product.getSeries('trunk')
+        removeSecurityProxy(trunk).branch = None
+
+        self.assertFalse(self.jobsource.generatesTemplates(branch))
+
+    def test_not_importing_templates(self):
+        # We don't generate templates when imports are disabled.
+        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
+
+        trunk = branch.product.getSeries('trunk')
+        removeSecurityProxy(trunk).translations_autoimport_mode = (
+            TranslationsBranchImportMode.NO_IMPORT)
+
+        self.assertFalse(self.jobsource.generatesTemplates(branch))
+
+    def test_private_branch(self):
+        # We don't generate templates for private branches.
+        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
+        removeSecurityProxy(branch).information_type = (
+            InformationType.USERDATA)
+        self.assertFalse(self.jobsource.generatesTemplates(branch))
+
+    def test_scheduleTranslationTemplatesBuild_subscribed(self):
+        # If the feature is enabled, a TipChanged event for a branch that
+        # generates templates will schedule a templates build.
+        branch = self._makeTranslationBranch()
+        removeSecurityProxy(branch).last_scanned_id = 'null:'
+        commit = DirectBranchCommit(branch)
+        commit.writeFile('POTFILES.in', 'foo')
+        commit.commit('message')
+        notify(events.TipChanged(branch, None, False))
+        branchjobs = list(TranslationTemplatesBuildJob.iterReady())
+        self.assertEqual(1, len(branchjobs))
+        self.assertEqual(branch, branchjobs[0].branch)
+
+    def test_scheduleTranslationTemplatesBuild(self):
+        # If the feature is enabled, scheduleTranslationTemplatesBuild
+        # will schedule a templates build whenever a change is pushed to
+        # a branch that generates templates.
+        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
+
+        self.jobsource.scheduleTranslationTemplatesBuild(branch)
+
+        store = IStore(BranchJob)
+        branchjobs = list(store.find(BranchJob, BranchJob.branch == branch))
+        self.assertEqual(1, len(branchjobs))
+        self.assertEqual(branch, branchjobs[0].branch)
 
     def test_findByBranch(self):
         source = getUtility(ITranslationTemplatesBuildSource)

=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py'
--- lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py	2013-11-12 06:03:14 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuildbehavior.py	2013-11-14 10:19:29 +0000
@@ -63,9 +63,8 @@
         Anything that might communicate with build slaves and such
         (which we can't really do here) is mocked up.
         """
-        specific_job = self.factory.makeTranslationTemplatesBuildJob(
-            branch=branch)
-        behavior = IBuildFarmJobBehavior(specific_job.build)
+        build = self.factory.makeTranslationTemplatesBuild(branch=branch)
+        behavior = IBuildFarmJobBehavior(build)
         slave = WaitingSlave(**kwargs)
         behavior.setBuilder(self.factory.makeBuilder(), slave)
         if use_fake_chroot:
@@ -73,7 +72,8 @@
             self.layer.txn.commit()
             behavior._getChroot = lambda: lf
         if want_bfjo:
-            return behavior, specific_job
+            bq = build.queueBuild()
+            return behavior, bq.specific_job
         else:
             return behavior
 

=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py	2013-11-12 07:39:51 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py	2013-11-14 10:19:29 +0000
@@ -5,19 +5,12 @@
 
 from storm.store import Store
 from zope.component import getUtility
-from zope.event import notify
 from zope.security.proxy import removeSecurityProxy
 
-from lp.app.enums import InformationType
-from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobOld
-from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
 from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.code.interfaces.branch import IBranchSet
 from lp.code.interfaces.branchjob import IBranchJob
-from lp.code.model.branchjob import BranchJob
-from lp.code.model.directbranchcommit import DirectBranchCommit
-from lp.codehosting.scanner import events
 from lp.services.database.interfaces import IStore
 from lp.services.job.model.job import Job
 from lp.testing import (
@@ -28,9 +21,6 @@
     LaunchpadZopelessLayer,
     ZopelessDatabaseLayer,
     )
-from lp.translations.interfaces.translations import (
-    TranslationsBranchImportMode,
-    )
 from lp.translations.interfaces.translationtemplatesbuildjob import (
     ITranslationTemplatesBuildJobSource,
     )
@@ -52,8 +42,9 @@
     def setUp(self):
         super(TestTranslationTemplatesBuildJob, self).setUp()
         self.jobset = getUtility(ITranslationTemplatesBuildJobSource)
-        self.branch = self.factory.makeBranch()
-        self.specific_job = self.jobset.create(self.branch)
+        self.build = self.factory.makeTranslationTemplatesBuild()
+        self.build.queueBuild()
+        self.specific_job = self.jobset.getByBranch(self.build.branch)
 
     def test_new_TranslationTemplatesBuildJob(self):
         # TranslationTemplateBuildJob implements IBuildFarmJobOld,
@@ -62,7 +53,7 @@
         verifyObject(IBuildFarmJobOld, self.specific_job)
 
         # Each of these jobs knows the branch it will operate on.
-        self.assertEqual(self.branch, self.specific_job.branch)
+        self.assertEqual(self.build.branch, self.specific_job.branch)
 
     def test_has_Job(self):
         # Associated with each TranslationTemplateBuildJob is a Job.
@@ -75,26 +66,6 @@
             TranslationTemplatesBuildJob.getByJob(base_job))
         self.assertEqual(self.specific_job, specific_job_for_base_job)
 
-    def test_has_BuildQueue(self):
-        # There's also a BuildQueue item associated with the job.
-        queueset = getUtility(IBuildQueueSet)
-        job_id = get_job_id(self.specific_job.job)
-        buildqueue = queueset.get(job_id)
-
-        self.assertIsInstance(buildqueue, BuildQueue)
-        self.assertEqual(job_id, get_job_id(buildqueue.job))
-
-    def test_BuildQueue_for_arch(self):
-        # BuildQueue entry is for i386 (default Ubuntu) architecture.
-        queueset = getUtility(IBuildQueueSet)
-        job_id = get_job_id(self.specific_job.job)
-        buildqueue = queueset.get(job_id)
-
-        ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
-        self.assertEquals(
-            ubuntu.currentseries.nominatedarchindep.processor,
-            buildqueue.processor)
-
     def test_cleanUp(self):
         # TranslationTemplatesBuildJob has its own customized cleanup
         # behaviour, since it's actually a BranchJob.
@@ -103,7 +74,7 @@
 
         job_id = job.id
         store = Store.of(job)
-        branch_name = self.branch.unique_name
+        branch_name = self.build.branch.unique_name
 
         buildqueue.destroySelf()
 
@@ -116,33 +87,8 @@
         self.assertIs(None, TranslationTemplatesBuildJob.getByJob(job_id))
         # Branch is still here.
         branch_set = getUtility(IBranchSet)
-        self.assertEqual(self.branch, branch_set.getByUniqueName(branch_name))
-
-
-class FakeTranslationTemplatesJobSource(TranslationTemplatesBuildJob):
-    """Fake utility class.
-
-    Allows overriding of _hasPotteryCompatibleSetup.
-
-    How do you fake a utility that is implemented as a class, not a
-    factory?  By inheriting from `TranslationTemplatesJob`, this class
-    "copies" the utility.  But you can make it fake the utility's
-    behavior by setting an attribute of the class (not an object!) at
-    the beginning of every test.
-    """
-    # Fake _hasPotteryCompatibleSetup, and if so, make it give what
-    # answer?
-    fake_pottery_compatibility = None
-
-    @classmethod
-    def _hasPotteryCompatibleSetup(cls, branch):
-        if cls.fake_pottery_compatibility is None:
-            # No fake compatibility setting call the real method.
-            return TranslationTemplatesBuildJob._hasPotteryCompatibleSetup(
-                branch)
-        else:
-            # Fake pottery compatibility.
-            return cls.fake_pottery_compatibility
+        self.assertEqual(
+            self.build.branch, branch_set.getByUniqueName(branch_name))
 
 
 class TestTranslationTemplatesBuildJobSource(TestCaseWithFactory):
@@ -150,127 +96,7 @@
 
     layer = LaunchpadZopelessLayer
 
-    def setUp(self):
-        super(TestTranslationTemplatesBuildJobSource, self).setUp()
-        self.jobsource = FakeTranslationTemplatesJobSource
-        self.jobsource.fake_pottery_compabitility = None
-
-    def tearDown(self):
-        self._fakePotteryCompatibleSetup(compatible=None)
-        super(TestTranslationTemplatesBuildJobSource, self).tearDown()
-
-    def _makeTranslationBranch(self, fake_pottery_compatible=None):
-        """Create a branch that provides translations for a productseries."""
-        if fake_pottery_compatible is None:
-            self.useBzrBranches(direct_database=True)
-            branch, tree = self.create_branch_and_tree()
-        else:
-            branch = self.factory.makeAnyBranch()
-        product = removeSecurityProxy(branch.product)
-        trunk = product.getSeries('trunk')
-        trunk.branch = branch
-        trunk.translations_autoimport_mode = (
-            TranslationsBranchImportMode.IMPORT_TEMPLATES)
-
-        self._fakePotteryCompatibleSetup(fake_pottery_compatible)
-
-        return branch
-
-    def _fakePotteryCompatibleSetup(self, compatible=True):
-        """Mock up branch compatibility check.
-
-        :param compatible: Whether the mock check should say that
-            branches have a pottery-compatible setup, or that they
-            don't.
-        """
-        self.jobsource.fake_pottery_compatibility = compatible
-
     def test_baseline(self):
         utility = getUtility(ITranslationTemplatesBuildJobSource)
         verifyObject(ITranslationTemplatesBuildJobSource, utility)
 
-    def test_generatesTemplates(self):
-        # A branch "generates templates" if it is a translation branch
-        # for a productseries that imports templates from it; is not
-        # private; and has a pottery compatible setup.
-        # For convenience we fake the pottery compatibility here.
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-        self.assertTrue(self.jobsource.generatesTemplates(branch))
-
-    def test_not_pottery_compatible(self):
-        # If pottery does not see any files it can work with in the
-        # branch, generatesTemplates returns False.
-        branch = self._makeTranslationBranch()
-        self.assertFalse(self.jobsource.generatesTemplates(branch))
-
-    def test_branch_not_used(self):
-        # We don't generate templates branches not attached to series.
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-
-        trunk = branch.product.getSeries('trunk')
-        removeSecurityProxy(trunk).branch = None
-
-        self.assertFalse(self.jobsource.generatesTemplates(branch))
-
-    def test_not_importing_templates(self):
-        # We don't generate templates when imports are disabled.
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-
-        trunk = branch.product.getSeries('trunk')
-        removeSecurityProxy(trunk).translations_autoimport_mode = (
-            TranslationsBranchImportMode.NO_IMPORT)
-
-        self.assertFalse(self.jobsource.generatesTemplates(branch))
-
-    def test_private_branch(self):
-        # We don't generate templates for private branches.
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-        removeSecurityProxy(branch).information_type = (
-            InformationType.USERDATA)
-        self.assertFalse(self.jobsource.generatesTemplates(branch))
-
-    def test_scheduleTranslationTemplatesBuild_subscribed(self):
-        # If the feature is enabled, a TipChanged event for a branch that
-        # generates templates will schedule a templates build.
-        branch = self._makeTranslationBranch()
-        removeSecurityProxy(branch).last_scanned_id = 'null:'
-        commit = DirectBranchCommit(branch)
-        commit.writeFile('POTFILES.in', 'foo')
-        commit.commit('message')
-        notify(events.TipChanged(branch, None, False))
-        branchjobs = list(TranslationTemplatesBuildJob.iterReady())
-        self.assertEqual(1, len(branchjobs))
-        self.assertEqual(branch, branchjobs[0].branch)
-
-    def test_scheduleTranslationTemplatesBuild(self):
-        # If the feature is enabled, scheduleTranslationTemplatesBuild
-        # will schedule a templates build whenever a change is pushed to
-        # a branch that generates templates.
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-
-        self.jobsource.scheduleTranslationTemplatesBuild(branch)
-
-        store = IStore(BranchJob)
-        branchjobs = list(store.find(BranchJob, BranchJob.branch == branch))
-        self.assertEqual(1, len(branchjobs))
-        self.assertEqual(branch, branchjobs[0].branch)
-
-    def test_create(self):
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-
-        specific_job = self.jobsource.create(branch)
-
-        # A job is created with the branch URL in its metadata.
-        metadata = specific_job.metadata
-        self.assertIn('branch_url', metadata)
-        url = metadata['branch_url']
-        head = 'http://'
-        self.assertEqual(head, url[:len(head)])
-        tail = branch.name
-        self.assertEqual(tail, url[-len(tail):])
-
-    def test_create_with_build(self):
-        branch = self._makeTranslationBranch(fake_pottery_compatible=True)
-        specific_job = self.jobsource.create(branch, testing=True)
-        naked_job = removeSecurityProxy(specific_job)
-        self.assertEquals(naked_job._constructed_build, specific_job.build)


Follow ups