launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #16858
[Merge] lp:~wgrant/launchpad/b-m-integration-test into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/b-m-integration-test into lp:launchpad.
Commit message:
Add an end-to-end integration test for buildd-manager's SlaveScanner, testing from candidate acquisition to post-build cleanup, mocking out just the clock and slave.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/b-m-integration-test/+merge/222308
Add an end-to-end integration test for buildd-manager's SlaveScanner, testing from candidate acquisition to post-build cleanup, mocking out just the clock and slave.
I believe this is the most complete test of core buildd-manager functionality that we have.
--
https://code.launchpad.net/~wgrant/launchpad/b-m-integration-test/+merge/222308
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/b-m-integration-test into lp:launchpad.
=== modified file 'lib/lp/buildmaster/tests/mock_slaves.py'
--- lib/lp/buildmaster/tests/mock_slaves.py 2014-05-10 18:40:36 +0000
+++ lib/lp/buildmaster/tests/mock_slaves.py 2014-06-06 11:05:48 +0000
@@ -76,7 +76,12 @@
self.arch_tag = arch_tag
self.version = version
+ @property
+ def method_log(self):
+ return [(x[0] if isinstance(x, tuple) else x) for x in self.call_log]
+
def status(self):
+ self.call_log.append('status')
slave_status = {'builder_status': 'BuilderStatus.IDLE'}
if self.version is not None:
slave_status['builder_version'] = self.version
@@ -138,10 +143,13 @@
def __init__(self, build_id='1-1'):
super(BuildingSlave, self).__init__()
self.build_id = build_id
+ self.status_count = 0
def status(self):
self.call_log.append('status')
- buildlog = xmlrpclib.Binary("This is a build log")
+ buildlog = xmlrpclib.Binary(
+ "This is a build log: %d" % self.status_count)
+ self.status_count += 1
return defer.succeed({
'builder_status': 'BuilderStatus.BUILDING',
'build_id': self.build_id,
=== modified file 'lib/lp/buildmaster/tests/test_manager.py'
--- lib/lp/buildmaster/tests/test_manager.py 2014-02-05 23:22:30 +0000
+++ lib/lp/buildmaster/tests/test_manager.py 2014-06-06 11:05:48 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for the renovated slave scanner aka BuilddManager."""
@@ -56,11 +56,15 @@
MockBuilder,
OkSlave,
TrivialBehaviour,
+ WaitingSlave,
)
from lp.registry.interfaces.distribution import IDistributionSet
from lp.services.config import config
from lp.services.log.logger import BufferLogger
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
+from lp.soyuz.model.binarypackagebuildbehaviour import (
+ BinaryPackageBuildBehaviour,
+ )
from lp.testing import (
ANONYMOUS,
login,
@@ -80,7 +84,7 @@
from lp.testing.sampledata import BOB_THE_BUILDER_NAME
-class TestSlaveScannerScan(TestCase):
+class TestSlaveScannerScan(TestCaseWithFactory):
"""Tests `SlaveScanner.scan` method.
This method uses the old framework for scanning and dispatching builds.
@@ -227,7 +231,7 @@
self.assertTrue(builder.builderok)
job = getUtility(IBuildQueueSet).get(job.id)
- self.assertBuildingJob(job, builder, logtail='This is a build log')
+ self.assertBuildingJob(job, builder, logtail='This is a build log: 0')
def testScanUpdatesBuildingJobs(self):
# Enable sampledata builder attached to an appropriate testing
@@ -530,6 +534,84 @@
self.assertEqual(1, slave.call_log.count("resume"))
self.assertEqual(BuildStatus.CANCELLED, build.status)
+ @defer.inlineCallbacks
+ def test_end_to_end(self):
+ # Test that SlaveScanner.scan() successfully finds, dispatches,
+ # collects and cleans a build.
+ build = self.factory.makeBinaryPackageBuild()
+ build.distro_arch_series.addOrUpdateChroot(
+ self.factory.makeLibraryFileAlias(db_only=True))
+ bq = build.queueBuild()
+ bq.manualScore(9000)
+
+ builder = self.factory.makeBuilder(
+ processors=[bq.processor], manual=False, vm_host='VMHOST')
+ transaction.commit()
+
+ # Mock out the build behaviour's _handleStatus_OK so it doesn't
+ # try to upload things to the librarian or queue.
+ @defer.inlineCallbacks
+ def handleStatus_OK(self, slave_status, logger, notify):
+ build.updateStatus(
+ BuildStatus.UPLOADING, builder, slave_status=slave_status)
+ transaction.commit()
+ yield self._slave.clean()
+ bq.destroySelf()
+ transaction.commit()
+ self.patch(
+ BinaryPackageBuildBehaviour, '_handleStatus_OK', handleStatus_OK)
+
+ # And create a SlaveScanner with a slave and a clock that we
+ # control.
+ get_slave = FakeMethod(OkSlave())
+ clock = task.Clock()
+ scanner = SlaveScanner(
+ builder.name, BuilderFactory(), BufferLogger(),
+ slave_factory=get_slave, clock=clock)
+
+ # The slave is idle and there's a build candidate, so the first
+ # scan will reset the builder and dispatch the build.
+ yield scanner.scan()
+ self.assertEqual(
+ ['status', 'resume', 'echo', 'ensurepresent', 'build'],
+ get_slave.result.method_log)
+ self.assertEqual(bq, builder.currentjob)
+ self.assertEqual(BuildQueueStatus.RUNNING, bq.status)
+ self.assertEqual(BuildStatus.BUILDING, build.status)
+
+ # build() has been called, so switch in a BUILDING slave.
+ # Scans will now just do a status() each, as the logtail is
+ # updated.
+ get_slave.result = BuildingSlave(
+ IBuildFarmJobBehaviour(build).getBuildCookie())
+ yield scanner.scan()
+ self.assertEqual("This is a build log: 0", bq.logtail)
+ yield scanner.scan()
+ self.assertEqual("This is a build log: 1", bq.logtail)
+ yield scanner.scan()
+ self.assertEqual("This is a build log: 2", bq.logtail)
+ self.assertEqual(
+ ['status', 'status', 'status'], get_slave.result.method_log)
+
+ # When the build finishes, the scanner will notice, call
+ # handleStatus(), and then clean the builder. Our fake
+ # _handleStatus_OK doesn't do anything special, but there'd
+ # usually be file retrievals in the middle.
+ get_slave.result = WaitingSlave(
+ build_id=IBuildFarmJobBehaviour(build).getBuildCookie())
+ yield scanner.scan()
+ self.assertEqual(['status', 'clean'], get_slave.result.method_log)
+ self.assertIs(None, builder.currentjob)
+ self.assertEqual(BuildStatus.UPLOADING, build.status)
+ self.assertEqual(builder, build.builder)
+
+ # We're clean, so let's flip back to an idle slave and
+ # confirm that a scan does nothing special.
+ get_slave.result = OkSlave()
+ yield scanner.scan()
+ self.assertEqual(['status'], get_slave.result.method_log)
+ self.assertIs(None, builder.currentjob)
+
class TestPrefetchedBuilderFactory(TestCaseWithFactory):
=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py'
--- lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py 2014-02-03 14:43:08 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py 2014-06-06 11:05:48 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2014 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for BinaryPackageBuildBehaviour."""
@@ -403,7 +403,7 @@
# The builder is still building the package.
def got_update(ignored):
# The fake log is returned from the BuildingSlave() mock.
- self.assertEqual("This is a build log", self.candidate.logtail)
+ self.assertEqual("This is a build log: 0", self.candidate.logtail)
d = self.updateBuild(self.candidate, BuildingSlave())
return d.addCallback(got_update)
Follow ups