~launchpad-pqm/launchpad/devel

14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.16 by Karl Fogel
Add the copyright header block to files under lib/lp/buildmaster/.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
7813.2.1 by Celso Providelo
re-basing slave-scanner-ng changes.
3
4
"""Tests for the renovated slave scanner aka BuilddManager."""
5
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
6
from collections import namedtuple
7813.2.15 by Celso Providelo
applying review comments, r=bigjools.
7
import os
10724.2.3 by Julian Edwards
tests all pass \o/
8
import signal
11121.2.3 by Henning Eggers
Added test for logging behavior.
9
import time
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
10
import xmlrpclib
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
11
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
12
from lpbuildd.tests import BuilddSlaveTestSetup
11705.2.25 by Jonathan Lange
Easier than I thought.
13
from testtools.deferredruntest import (
14
    assert_fails_with,
15
    AsynchronousDeferredRunTest,
16
    )
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
17
from twisted.internet import (
18
    defer,
19
    reactor,
20
    task,
21
    )
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
22
from twisted.internet.task import deferLater
7856.1.1 by Celso Providelo
Fixing remaining issues with BuilddManager, specially the dispatch-error-handler part.
23
from twisted.python.failure import Failure
7813.2.1 by Celso Providelo
re-basing slave-scanner-ng changes.
24
from zope.component import getUtility
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
25
from zope.security.proxy import removeSecurityProxy
7813.2.1 by Celso Providelo
re-basing slave-scanner-ng changes.
26
11458.1.1 by Jelmer Vernooij
Move enums of buildmaster.
27
from lp.buildmaster.enums import BuildStatus
7675.509.139 by William Grant
Move (I)BuildQueue(Set) to lp.buildmaster.
28
from lp.buildmaster.interfaces.builder import IBuilderSet
29
from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
8426.7.3 by Julian Edwards
Migrate buildmaster to the lp tree.
30
from lp.buildmaster.manager import (
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
31
    assessFailureCounts,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
32
    BuilddManager,
33
    NewBuildersScanner,
34
    SlaveScanner,
35
    )
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
36
from lp.buildmaster.model.builder import Builder
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
37
from lp.buildmaster.model.packagebuild import PackageBuild
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
38
from lp.buildmaster.testing import BuilddManagerTestFixture
8426.7.9 by Julian Edwards
Fix bad import in a test change merged from trunk.
39
from lp.buildmaster.tests.harness import BuilddManagerTestSetup
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
40
from lp.buildmaster.tests.mock_slaves import (
41
    BrokenSlave,
42
    BuildingSlave,
11705.2.26 by Jonathan Lange
Factor out SoyuzTestPublisher construction so as to avoid circular imports.
43
    make_publisher,
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
44
    OkSlave,
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
45
    WaitingSlave,
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
46
    )
7675.509.139 by William Grant
Move (I)BuildQueue(Set) to lp.buildmaster.
47
from lp.registry.interfaces.distribution import IDistributionSet
14612.2.1 by William Grant
format-imports on lib/. So many imports.
48
from lp.services.config import config
14542.2.33 by Gavin Panella
TestSlaveScannerScan needs TestCaseWithFactory after all, and fix a missing import.
49
from lp.services.database.constants import UTC_NOW
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
50
from lp.services.log.logger import BufferLogger
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
51
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
11705.2.25 by Jonathan Lange
Easier than I thought.
52
from lp.testing import (
14612.2.1 by William Grant
format-imports on lib/. So many imports.
53
    ANONYMOUS,
54
    login,
11705.2.25 by Jonathan Lange
Easier than I thought.
55
    TestCase,
56
    TestCaseWithFactory,
57
    )
10888.6.14 by Julian Edwards
checkForNewBuilders returns builders if they're new
58
from lp.testing.factory import LaunchpadObjectFactory
10888.6.19 by Julian Edwards
fix a test isolation issue
59
from lp.testing.fakemethod import FakeMethod
14612.2.1 by William Grant
format-imports on lib/. So many imports.
60
from lp.testing.layers import (
61
    LaunchpadScriptLayer,
62
    LaunchpadZopelessLayer,
63
    ZopelessDatabaseLayer,
64
    )
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
65
from lp.testing.sampledata import (
66
    BOB_THE_BUILDER_NAME,
67
    FROG_THE_BUILDER_NAME,
68
    )
69
70
14542.2.33 by Gavin Panella
TestSlaveScannerScan needs TestCaseWithFactory after all, and fix a missing import.
71
class TestSlaveScannerScan(TestCaseWithFactory):
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
72
    """Tests `SlaveScanner.scan` method.
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
73
74
    This method uses the old framework for scanning and dispatching builds.
75
    """
11705.2.25 by Jonathan Lange
Easier than I thought.
76
    layer = LaunchpadZopelessLayer
77
    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=20)
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
78
79
    def setUp(self):
11705.2.25 by Jonathan Lange
Easier than I thought.
80
        """Set up BuilddSlaveTest.
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
81
82
        Also adjust the sampledata in a way a build can be dispatched to
83
        'bob' builder.
84
        """
11705.2.25 by Jonathan Lange
Easier than I thought.
85
        super(TestSlaveScannerScan, self).setUp()
8137.17.24 by Barry Warsaw
thread merge
86
        # Creating the required chroots needed for dispatching.
11705.2.26 by Jonathan Lange
Factor out SoyuzTestPublisher construction so as to avoid circular imports.
87
        test_publisher = make_publisher()
8137.17.24 by Barry Warsaw
thread merge
88
        ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
89
        hoary = ubuntu.getSeries('hoary')
7675.509.141 by William Grant
Fix lint.
90
        test_publisher.setUpDefaultDistroSeries(hoary)
8137.17.24 by Barry Warsaw
thread merge
91
        test_publisher.addFakeChroots()
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
92
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
93
        self.useFixture(BuilddManagerTestFixture())
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
94
8137.17.24 by Barry Warsaw
thread merge
95
    def _resetBuilder(self, builder):
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
96
        """Reset the given builder and its job."""
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
97
        builder.builderok = True
98
        job = builder.currentjob
99
        if job is not None:
8137.17.24 by Barry Warsaw
thread merge
100
            job.reset()
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
101
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
102
    def getFreshBuilder(self, slave=None, name=BOB_THE_BUILDER_NAME,
103
                        failure_count=0):
104
        """Return a builder.
105
106
        The builder is taken from sample data, but reset to a usable state.
107
        Be careful: this is not a proper factory method.  Identical calls
108
        return (and reset) the same builder.  Don't rely on that though;
109
        maybe someday we'll have a proper factory here.
110
        """
111
        if slave is None:
112
            slave = OkSlave()
113
        builder = getUtility(IBuilderSet)[name]
114
        self._resetBuilder(builder)
115
        builder.setSlaveForTesting(slave)
116
        builder.failure_count = failure_count
117
        return builder
118
8137.17.24 by Barry Warsaw
thread merge
119
    def assertBuildingJob(self, job, builder, logtail=None):
120
        """Assert the given job is building on the given builder."""
7675.461.4 by Muharem Hrnjadovic
testScanUpdatesBuildingJobs passes
121
        from lp.services.job.interfaces.job import JobStatus
8137.17.24 by Barry Warsaw
thread merge
122
        if logtail is None:
123
            logtail = 'Dummy sampledata entry, not processing'
124
125
        self.assertTrue(job is not None)
126
        self.assertEqual(job.builder, builder)
7675.390.5 by Muharem Hrnjadovic
Review changes, round 1.
127
        self.assertTrue(job.date_started is not None)
7675.461.4 by Muharem Hrnjadovic
testScanUpdatesBuildingJobs passes
128
        self.assertEqual(job.job.status, JobStatus.RUNNING)
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
129
        build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
7675.687.129 by Michael Nelson
Fixed test_manager.py
130
        self.assertEqual(build.status, BuildStatus.BUILDING)
8137.17.24 by Barry Warsaw
thread merge
131
        self.assertEqual(job.logtail, logtail)
132
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
133
    def _getScanner(self, builder_name=None, clock=None):
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
134
        """Instantiate a SlaveScanner object.
8137.17.24 by Barry Warsaw
thread merge
135
136
        Replace its default logging handler by a testing version.
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
137
        """
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
138
        if builder_name is None:
139
            builder_name = BOB_THE_BUILDER_NAME
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
140
        scanner = SlaveScanner(builder_name, BufferLogger(), clock=clock)
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
141
        scanner.logger.name = 'slave-scanner'
7813.2.14 by Celso Providelo
applying review comments, r=bigjools.
142
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
143
        return scanner
8137.17.24 by Barry Warsaw
thread merge
144
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
145
    def _checkDispatch(self, slave, builder):
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
146
        # SlaveScanner.scan returns a slave when a dispatch was
147
        # successful.  We also check that the builder has a job on it.
148
149
        self.assertTrue(slave is not None, "Expected a slave.")
10888.7.22 by Julian Edwards
move the builder failure_count reset to a point in the manager where we can be sure the dispatch was successful.
150
        self.assertEqual(0, builder.failure_count)
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
151
        self.assertTrue(builder.currentjob is not None)
8137.17.24 by Barry Warsaw
thread merge
152
153
    def testScanDispatchForResetBuilder(self):
154
        # A job gets dispatched to the sampledata builder after it's reset.
155
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
156
        # Obtain a builder.   Initialize failure count to 1 so that
157
        # _checkDispatch can make sure that a successful dispatch resets
158
        # the count to 0.
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
159
        with BuilddManagerTestFixture.extraSetUp():
160
            builder = self.getFreshBuilder(failure_count=1)
8137.17.24 by Barry Warsaw
thread merge
161
162
        # Run 'scan' and check its result.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
163
        self.layer.switchDbUser(config.builddmaster.dbuser)
164
        scanner = self._getScanner()
165
        d = defer.maybeDeferred(scanner.scan)
8137.17.24 by Barry Warsaw
thread merge
166
        d.addCallback(self._checkDispatch, builder)
167
        return d
168
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
169
    def _checkNoDispatch(self, slave, builder):
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
170
        """Assert that no dispatch has occurred.
171
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
172
        'slave' is None, so no interations would be passed
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
173
        to the asynchonous dispatcher and the builder remained active
174
        and IDLE.
175
        """
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
176
        self.assertIs(None, slave, "Unexpected slave.")
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
177
178
        builder = getUtility(IBuilderSet).get(builder.id)
179
        self.assertTrue(builder.builderok)
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
180
        self.assertIs(None, builder.currentjob)
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
181
182
    def testNoDispatchForMissingChroots(self):
183
        # When a required chroot is not present the `scan` method
184
        # should not return any `RecordingSlaves` to be processed
185
        # and the builder used should remain active and IDLE.
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
186
        with BuilddManagerTestFixture.extraSetUp():
187
            builder = self.getFreshBuilder()
188
            # Remove hoary/i386 chroot.
189
            login('foo.bar@canonical.com')
190
            ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
191
            hoary = ubuntu.getSeries('hoary')
192
            pocket_chroot = hoary.getDistroArchSeries('i386').getPocketChroot()
193
            removeSecurityProxy(pocket_chroot).chroot = None
194
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
195
        login(ANONYMOUS)
196
197
        # Run 'scan' and check its result.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
198
        self.layer.switchDbUser(config.builddmaster.dbuser)
199
        scanner = self._getScanner()
200
        d = defer.maybeDeferred(scanner.singleCycle)
8533.1.3 by Celso Providelo
Fixing the slip on buildd-manager that blocks the dispatcher on jobs with missing chroots.
201
        d.addCallback(self._checkNoDispatch, builder)
202
        return d
203
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
204
    def _checkJobRescued(self, slave, builder, job):
205
        """`SlaveScanner.scan` rescued the job.
8137.17.24 by Barry Warsaw
thread merge
206
207
        Nothing gets dispatched,  the 'broken' builder remained disabled
208
        and the 'rescued' job is ready to be dispatched.
209
        """
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
210
        self.assertTrue(
211
            slave is None, "Unexpected slave.")
8137.17.24 by Barry Warsaw
thread merge
212
213
        builder = getUtility(IBuilderSet).get(builder.id)
214
        self.assertFalse(builder.builderok)
215
216
        job = getUtility(IBuildQueueSet).get(job.id)
217
        self.assertTrue(job.builder is None)
7675.390.5 by Muharem Hrnjadovic
Review changes, round 1.
218
        self.assertTrue(job.date_started is None)
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
219
        build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
7675.687.129 by Michael Nelson
Fixed test_manager.py
220
        self.assertEqual(build.status, BuildStatus.NEEDSBUILD)
8137.17.24 by Barry Warsaw
thread merge
221
222
    def testScanRescuesJobFromBrokenBuilder(self):
223
        # The job assigned to a broken builder is rescued.
14047.3.37 by Jeroen Vermeulen
Review change: only set up BuilddSlaveTestSetup fixture where it's needed.
224
        self.useFixture(BuilddSlaveTestSetup())
8137.17.24 by Barry Warsaw
thread merge
225
9353.2.1 by Celso Providelo
Fixing bug #424797 (swalloed test failure in buildd-manager suite).
226
        # Sampledata builder is enabled and is assigned to an active job.
10888.7.23 by Julian Edwards
jml's review comments
227
        builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]
9353.2.1 by Celso Providelo
Fixing bug #424797 (swalloed test failure in buildd-manager suite).
228
        self.assertTrue(builder.builderok)
229
        job = builder.currentjob
230
        self.assertBuildingJob(job, builder)
231
232
        # Disable the sampledata builder
233
        login('foo.bar@canonical.com')
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
234
        with BuilddManagerTestFixture.extraSetUp():
235
            builder.builderok = False
9353.2.1 by Celso Providelo
Fixing bug #424797 (swalloed test failure in buildd-manager suite).
236
        login(ANONYMOUS)
8137.17.24 by Barry Warsaw
thread merge
237
238
        # Run 'scan' and check its result.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
239
        self.layer.switchDbUser(config.builddmaster.dbuser)
240
        scanner = self._getScanner()
241
        d = defer.maybeDeferred(scanner.scan)
9353.2.1 by Celso Providelo
Fixing bug #424797 (swalloed test failure in buildd-manager suite).
242
        d.addCallback(self._checkJobRescued, builder, job)
8137.17.24 by Barry Warsaw
thread merge
243
        return d
244
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
245
    def _checkJobUpdated(self, slave, builder, job):
246
        """`SlaveScanner.scan` updates legitimate jobs.
8137.17.24 by Barry Warsaw
thread merge
247
248
        Job is kept assigned to the active builder and its 'logtail' is
249
        updated.
250
        """
10888.6.6 by Julian Edwards
loads of tests fixed, only 2 left. yay
251
        self.assertTrue(slave is None, "Unexpected slave.")
8137.17.24 by Barry Warsaw
thread merge
252
253
        builder = getUtility(IBuilderSet).get(builder.id)
254
        self.assertTrue(builder.builderok)
255
256
        job = getUtility(IBuildQueueSet).get(job.id)
10430.8.5 by William Grant
Drop all the rescueIfLost-test-specific mock slaves, use a special build behavior in the rIL test, and fix other tests that used the late mocks.
257
        self.assertBuildingJob(job, builder, logtail='This is a build log')
8137.17.24 by Barry Warsaw
thread merge
258
259
    def testScanUpdatesBuildingJobs(self):
260
        # Enable sampledata builder attached to an appropriate testing
261
        # slave. It will respond as if it was building the sampledata job.
10888.7.23 by Julian Edwards
jml's review comments
262
        builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]
8137.17.24 by Barry Warsaw
thread merge
263
264
        login('foo.bar@canonical.com')
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
265
        with BuilddManagerTestFixture.extraSetUp():
266
            builder.builderok = True
267
            builder.setSlaveForTesting(BuildingSlave(build_id='8-1'))
8137.17.24 by Barry Warsaw
thread merge
268
        login(ANONYMOUS)
269
7675.461.6 by Muharem Hrnjadovic
took back unneeded change
270
        job = builder.currentjob
8137.17.24 by Barry Warsaw
thread merge
271
        self.assertBuildingJob(job, builder)
272
273
        # Run 'scan' and check its result.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
274
        self.layer.switchDbUser(config.builddmaster.dbuser)
275
        scanner = self._getScanner()
276
        d = defer.maybeDeferred(scanner.scan)
8137.17.24 by Barry Warsaw
thread merge
277
        d.addCallback(self._checkJobUpdated, builder, job)
8294.3.1 by Celso Providelo
Re-fixing bug #343683 (legitimate building jobs were being erroneously reset).
278
        return d
279
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
280
    def test_scan_with_nothing_to_dispatch(self):
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
281
        with BuilddManagerTestFixture.extraSetUp():
282
            builder = self.factory.makeBuilder()
283
            builder.setSlaveForTesting(OkSlave())
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
284
        scanner = self._getScanner(builder_name=builder.name)
285
        d = scanner.scan()
286
        return d.addCallback(self._checkNoDispatch, builder)
287
288
    def test_scan_with_manual_builder(self):
289
        # Reset sampledata builder.
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
290
        with BuilddManagerTestFixture.extraSetUp():
291
            builder = self.getFreshBuilder()
292
            builder.manual = True
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
293
        scanner = self._getScanner()
294
        d = scanner.scan()
295
        d.addCallback(self._checkNoDispatch, builder)
296
        return d
297
298
    def test_scan_with_not_ok_builder(self):
299
        # Reset sampledata builder.
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
300
        with BuilddManagerTestFixture.extraSetUp():
301
            builder = self.getFreshBuilder()
302
            builder.builderok = False
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
303
        scanner = self._getScanner()
304
        d = scanner.scan()
305
        # Because the builder is not ok, we can't use _checkNoDispatch.
306
        d.addCallback(
11705.2.25 by Jonathan Lange
Easier than I thought.
307
            lambda ignored: self.assertIs(None, builder.currentjob))
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
308
        return d
309
310
    def test_scan_of_broken_slave(self):
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
311
        with BuilddManagerTestFixture.extraSetUp():
312
            builder = self.getFreshBuilder(slave=BrokenSlave())
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
313
        scanner = self._getScanner(builder_name=builder.name)
314
        d = scanner.scan()
11705.2.25 by Jonathan Lange
Easier than I thought.
315
        return assert_fails_with(d, xmlrpclib.Fault)
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
316
317
    def _assertFailureCounting(self, builder_count, job_count,
318
                               expected_builder_count, expected_job_count):
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
319
        # Avoid circular imports.
320
        from lp.buildmaster import manager as manager_module
321
10888.7.20 by Julian Edwards
Now also deal with exception failures as well as the dispatch failures.
322
        # If scan() fails with an exception, failure_counts should be
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
323
        # incremented.  What we do with the results of the failure
324
        # counts is tested below separately, this test just makes sure that
325
        # scan() is setting the counts.
10888.7.23 by Julian Edwards
jml's review comments
326
        def failing_scan():
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
327
            return defer.fail(Exception("fake exception"))
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
328
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
329
        with BuilddManagerTestFixture.extraSetUp():
330
            scanner = self._getScanner()
331
            scanner.scan = failing_scan
332
            self.patch(manager_module, 'assessFailureCounts', FakeMethod())
333
            builder = getUtility(IBuilderSet)[scanner.builder_name]
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
334
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
335
            builder.failure_count = builder_count
336
            builder.currentjob.specific_job.build.failure_count = job_count
337
            # The _scanFailed() calls abort, so make sure our existing failure
338
            # counts are persisted by exiting the extraSetUp() context (which
339
            # commits).
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
340
341
        # singleCycle() calls scan() which is our fake one that throws an
10888.7.20 by Julian Edwards
Now also deal with exception failures as well as the dispatch failures.
342
        # exception.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
343
        d = scanner.singleCycle()
10888.7.20 by Julian Edwards
Now also deal with exception failures as well as the dispatch failures.
344
345
        # Failure counts should be updated, and the assessment method
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
346
        # should have been called.  The actual behaviour is tested below
347
        # in TestFailureAssessments.
348
        def got_scan(ignored):
349
            self.assertEqual(expected_builder_count, builder.failure_count)
350
            self.assertEqual(
351
                expected_job_count,
352
                builder.currentjob.specific_job.build.failure_count)
353
            self.assertEqual(
354
                1, manager_module.assessFailureCounts.call_count)
355
356
        return d.addCallback(got_scan)
357
358
    def test_scan_first_fail(self):
359
        # The first failure of a job should result in the failure_count
360
        # on the job and the builder both being incremented.
361
        self._assertFailureCounting(
362
            builder_count=0, job_count=0, expected_builder_count=1,
363
            expected_job_count=1)
364
365
    def test_scan_second_builder_fail(self):
366
        # The first failure of a job should result in the failure_count
367
        # on the job and the builder both being incremented.
368
        self._assertFailureCounting(
369
            builder_count=1, job_count=0, expected_builder_count=2,
370
            expected_job_count=1)
371
372
    def test_scan_second_job_fail(self):
373
        # The first failure of a job should result in the failure_count
374
        # on the job and the builder both being incremented.
375
        self._assertFailureCounting(
376
            builder_count=0, job_count=1, expected_builder_count=1,
377
            expected_job_count=2)
378
379
    def test_scanFailed_handles_lack_of_a_job_on_the_builder(self):
380
        def failing_scan():
381
            return defer.fail(Exception("fake exception"))
382
        scanner = self._getScanner()
383
        scanner.scan = failing_scan
384
        builder = getUtility(IBuilderSet)[scanner.builder_name]
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
385
        with BuilddManagerTestFixture.extraSetUp():
386
            builder.failure_count = Builder.FAILURE_THRESHOLD
387
            builder.currentjob.reset()
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
388
389
        d = scanner.singleCycle()
390
391
        def scan_finished(ignored):
392
            self.assertFalse(builder.builderok)
393
394
        return d.addCallback(scan_finished)
395
396
    def test_fail_to_resume_slave_resets_job(self):
397
        # If an attempt to resume and dispatch a slave fails, it should
398
        # reset the job via job.reset()
399
400
        # Make a slave with a failing resume() method.
401
        slave = OkSlave()
402
        slave.resume = lambda: deferLater(
403
            reactor, 0, defer.fail, Failure(('out', 'err', 1)))
404
405
        # Reset sampledata builder.
406
        builder = removeSecurityProxy(
407
            getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME])
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
408
        with BuilddManagerTestFixture.extraSetUp():
409
            self._resetBuilder(builder)
410
            self.assertEqual(0, builder.failure_count)
411
            builder.setSlaveForTesting(slave)
412
            builder.vm_host = "fake_vm_host"
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
413
414
        scanner = self._getScanner()
415
416
        # Get the next job that will be dispatched.
417
        job = removeSecurityProxy(builder._findBuildCandidate())
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
418
        with BuilddManagerTestFixture.extraSetUp():
419
            job.virtualized = True
420
            builder.virtualized = True
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
421
        d = scanner.singleCycle()
422
423
        def check(ignored):
424
            # The failure_count will have been incremented on the
425
            # builder, we can check that to see that a dispatch attempt
426
            # did indeed occur.
427
            self.assertEqual(1, builder.failure_count)
428
            # There should also be no builder set on the job.
429
            self.assertTrue(job.builder is None)
430
            build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
431
            self.assertEqual(build.status, BuildStatus.NEEDSBUILD)
432
433
        return d.addCallback(check)
11593.3.48 by Julian Edwards
1. Split startCycle in two so that we have separate methods for a single cycle and one that also schedules the next one. This makes testing easier.
434
14206.2.2 by Julian Edwards
merge remainder of backed out branch
435
    def test_cancelling_a_build(self):
436
        # When scanning an in-progress build, if its state is CANCELLING
437
        # then the build should be stopped and moved to the CANCELLED state.
438
439
        # Set up a building slave with a fake resume method so we can see
440
        # if it got called later.
441
        slave = BuildingSlave(build_id="8-1")
442
        call_counter = FakeMethod()
14206.2.11 by Julian Edwards
fix lint
443
14206.2.2 by Julian Edwards
merge remainder of backed out branch
444
        def fake_resume():
445
            call_counter()
446
            return defer.succeed((None, None, 0))
447
        slave.resume = fake_resume
448
449
        # Set the sample data builder building with the slave from above.
450
        builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]
451
        login('foo.bar@canonical.com')
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
452
        with BuilddManagerTestFixture.extraSetUp():
453
            builder.builderok = True
454
            # For now, we can only cancel virtual builds.
455
            builder.virtualized = True
456
            builder.vm_host = "fake_vm_host"
457
            builder.setSlaveForTesting(slave)
14206.2.2 by Julian Edwards
merge remainder of backed out branch
458
        login(ANONYMOUS)
459
        buildqueue = builder.currentjob
460
        self.assertBuildingJob(buildqueue, builder)
461
462
        # Now set the build to CANCELLING.
463
        build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(buildqueue)
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
464
        with BuilddManagerTestFixture.extraSetUp():
465
            build.status = BuildStatus.CANCELLING
14206.2.2 by Julian Edwards
merge remainder of backed out branch
466
467
        # Run 'scan' and check its results.
468
        self.layer.switchDbUser(config.builddmaster.dbuser)
469
        scanner = self._getScanner()
470
        d = scanner.scan()
471
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
472
        # The build state should be cancelled and we should have also
473
        # called the resume() method on the slave that resets the virtual
474
        # machine.
14206.2.2 by Julian Edwards
merge remainder of backed out branch
475
        def check_cancelled(ignore, builder, buildqueue):
476
            self.assertEqual(1, call_counter.call_count)
477
            self.assertEqual(BuildStatus.CANCELLED, build.status)
478
479
        d.addCallback(check_cancelled, builder, buildqueue)
480
        return d
481
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
482
    def makeFakeFailure(self):
483
        """Produce a fake failure for use with SlaveScanner._scanFailed."""
484
        FakeFailure = namedtuple('FakeFailure', ['getErrorMessage', 'check'])
485
        return FakeFailure(
486
            FakeMethod(self.factory.getUniqueString()),
487
            FakeMethod(True))
488
489
    def test_interleaved_success_and_failure_do_not_interfere(self):
490
        # It's possible for one builder to fail while another continues
491
        # to function properly.  When that happens, the failed builder
492
        # may cause database changes to be rolled back.  But that does
493
        # not affect the functioning builder.
494
        clock = task.Clock()
495
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
496
        with BuilddManagerTestFixture.extraSetUp():
497
            broken_builder = self.getFreshBuilder(
498
                slave=BrokenSlave(), name=BOB_THE_BUILDER_NAME)
499
            broken_scanner = self._getScanner(
500
                builder_name=broken_builder.name)
501
            good_builder = self.getFreshBuilder(
502
                slave=WaitingSlave(), name=FROG_THE_BUILDER_NAME)
503
            good_build = self.factory.makeBinaryPackageBuild(
504
                distroarchseries=self.factory.makeDistroArchSeries())
505
506
            # The good build is being handled by the good builder.
507
            buildqueue = good_build.queueBuild()
508
            buildqueue.builder = good_builder
509
510
            removeSecurityProxy(
511
                good_build.build_farm_job).date_started = UTC_NOW
14557.2.1 by Gavin Panella
Revert r14552, thus unreverting r14499 and r14459, to bring back read-only transactions in buildmaster.
512
513
        # The good builder requests information from a successful build,
514
        # and up receiving it, updates the build's metadata.
515
        # Our dependencies string goes into the build, and its
516
        # date_finished will be set.
517
        dependencies = self.factory.getUniqueString()
518
        PackageBuild.storeBuildInfo(
519
            good_build, None, {'dependencies': dependencies})
520
        clock.advance(1)
521
522
        # The broken scanner experiences a failure before the good
523
        # scanner is receiving its data.  This aborts the ongoing
524
        # transaction.
525
        # As a somewhat weird example, if the builder changed its own
526
        # title, that change will be rolled back.
527
        original_broken_builder_title = broken_builder.title
528
        broken_builder.title = self.factory.getUniqueString()
529
        broken_scanner._scanFailed(self.makeFakeFailure())
530
531
        # The work done by the good scanner is retained.  The
532
        # storeBuildInfo code committed it.
533
        self.assertEqual(dependencies, good_build.dependencies)
534
        self.assertIsNot(None, good_build.date_finished)
535
536
        # The work done by the broken scanner is rolled back.
537
        self.assertEqual(original_broken_builder_title, broken_builder.title)
538
10888.7.23 by Julian Edwards
jml's review comments
539
14206.2.5 by Julian Edwards
Check that non-cancelling build is ignored
540
class TestCancellationChecking(TestCaseWithFactory):
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
541
    """Unit tests for the checkCancellation method."""
542
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
543
    layer = ZopelessDatabaseLayer
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
544
    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=20)
545
546
    def setUp(self):
547
        super(TestCancellationChecking, self).setUp()
548
        builder_name = BOB_THE_BUILDER_NAME
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
549
        self.builder = getUtility(IBuilderSet)[builder_name]
14206.2.5 by Julian Edwards
Check that non-cancelling build is ignored
550
        self.builder.virtualized = True
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
551
        self.scanner = SlaveScanner(builder_name, BufferLogger())
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
552
        self.scanner.builder = self.builder
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
553
        self.scanner.logger.name = 'slave-scanner'
554
14542.2.28 by Gavin Panella
Use BuilddManagerTestFixture in TestCancellationChecking.
555
        self.useFixture(BuilddManagerTestFixture())
14542.2.27 by Gavin Panella
Use BuilddManagerTestFixture in TestSlaveScannerScan.
556
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
557
    def test_ignores_nonvirtual(self):
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
558
        # If the builder is nonvirtual make sure we return False.
14542.2.28 by Gavin Panella
Use BuilddManagerTestFixture in TestCancellationChecking.
559
        with BuilddManagerTestFixture.extraSetUp():
560
            self.builder.virtualized = False
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
561
        d = self.scanner.checkCancellation(self.builder)
14206.2.13 by Julian Edwards
simplify assertions
562
        return d.addCallback(self.assertFalse)
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
563
564
    def test_ignores_no_buildqueue(self):
565
        # If the builder has no buildqueue associated,
566
        # make sure we return False.
14206.2.5 by Julian Edwards
Check that non-cancelling build is ignored
567
        buildqueue = self.builder.currentjob
14542.2.28 by Gavin Panella
Use BuilddManagerTestFixture in TestCancellationChecking.
568
        with BuilddManagerTestFixture.extraSetUp():
569
            buildqueue.reset()
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
570
        d = self.scanner.checkCancellation(self.builder)
14206.2.13 by Julian Edwards
simplify assertions
571
        return d.addCallback(self.assertFalse)
14206.2.4 by Julian Edwards
Check that inactive builder is ignored
572
14206.2.5 by Julian Edwards
Check that non-cancelling build is ignored
573
    def test_ignores_build_not_cancelling(self):
574
        # If the active build is not in a CANCELLING state, ignore it.
575
        buildqueue = self.builder.currentjob
576
        build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(buildqueue)
14542.2.28 by Gavin Panella
Use BuilddManagerTestFixture in TestCancellationChecking.
577
        with BuilddManagerTestFixture.extraSetUp():
578
            build.status = BuildStatus.BUILDING
14206.2.5 by Julian Edwards
Check that non-cancelling build is ignored
579
        d = self.scanner.checkCancellation(self.builder)
14206.2.13 by Julian Edwards
simplify assertions
580
        return d.addCallback(self.assertFalse)
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
581
14206.2.6 by Julian Edwards
Check that a cancelling build is actually cancelled.
582
    def test_cancelling_build_is_cancelled(self):
14206.2.7 by Julian Edwards
build cancellation check
583
        # If a build is CANCELLING, make sure True is returned and the
584
        # slave was resumed.
585
        call_counter = FakeMethod()
14206.2.11 by Julian Edwards
fix lint
586
14206.2.7 by Julian Edwards
build cancellation check
587
        def fake_resume():
588
            call_counter()
589
            return defer.succeed((None, None, 0))
590
        slave = OkSlave()
591
        slave.resume = fake_resume
14542.2.28 by Gavin Panella
Use BuilddManagerTestFixture in TestCancellationChecking.
592
593
        with BuilddManagerTestFixture.extraSetUp():
594
            self.builder.vm_host = "fake_vm_host"
595
            self.builder.setSlaveForTesting(slave)
596
            buildqueue = self.builder.currentjob
597
            build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(buildqueue)
598
            build.status = BuildStatus.CANCELLING
14206.2.7 by Julian Edwards
build cancellation check
599
600
        def check(result):
601
            self.assertEqual(1, call_counter.call_count)
602
            self.assertTrue(result)
603
            self.assertEqual(BuildStatus.CANCELLED, build.status)
604
14206.2.6 by Julian Edwards
Check that a cancelling build is actually cancelled.
605
        d = self.scanner.checkCancellation(self.builder)
14206.2.10 by Julian Edwards
Make tests return the deferred
606
        return d.addCallback(check)
14206.2.3 by Julian Edwards
Start of unit tests for new checkCancellation method
607
608
11705.2.25 by Jonathan Lange
Easier than I thought.
609
class TestBuilddManager(TestCase):
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
610
11705.2.25 by Jonathan Lange
Easier than I thought.
611
    layer = LaunchpadZopelessLayer
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
612
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
613
    def _stub_out_scheduleNextScanCycle(self):
10888.6.19 by Julian Edwards
fix a test isolation issue
614
        # stub out the code that adds a callLater, so that later tests
615
        # don't get surprises.
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
616
        self.patch(SlaveScanner, 'startCycle', FakeMethod())
10888.6.19 by Julian Edwards
fix a test isolation issue
617
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
618
    def test_addScanForBuilders(self):
619
        # Test that addScanForBuilders generates NewBuildersScanner objects.
620
        self._stub_out_scheduleNextScanCycle()
621
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
622
        manager = BuilddManager()
10888.6.26 by Julian Edwards
more cleanups
623
        builder_names = set(
624
            builder.name for builder in getUtility(IBuilderSet))
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
625
        scanners = manager.addScanForBuilders(builder_names)
10888.6.26 by Julian Edwards
more cleanups
626
        scanner_names = set(scanner.builder_name for scanner in scanners)
627
        self.assertEqual(builder_names, scanner_names)
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
628
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
629
    def test_startService_adds_NewBuildersScanner(self):
630
        # When startService is called, the manager will start up a
631
        # NewBuildersScanner object.
632
        self._stub_out_scheduleNextScanCycle()
10888.6.26 by Julian Edwards
more cleanups
633
        clock = task.Clock()
634
        manager = BuilddManager(clock=clock)
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
635
10888.6.21 by Julian Edwards
use FakeMethod instead of my own stubs
636
        # Replace scan() with FakeMethod so we can see if it was called.
10888.6.26 by Julian Edwards
more cleanups
637
        manager.new_builders_scanner.scan = FakeMethod()
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
638
639
        manager.startService()
10888.6.26 by Julian Edwards
more cleanups
640
        advance = NewBuildersScanner.SCAN_INTERVAL + 1
641
        clock.advance(advance)
642
        self.assertNotEqual(0, manager.new_builders_scanner.scan.call_count)
10888.6.20 by Julian Edwards
add code that starts up the scan for new builders and tests for it
643
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
644
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
645
class TestFailureAssessments(TestCaseWithFactory):
646
647
    layer = ZopelessDatabaseLayer
648
649
    def setUp(self):
650
        TestCaseWithFactory.setUp(self)
651
        self.builder = self.factory.makeBuilder()
652
        self.build = self.factory.makeSourcePackageRecipeBuild()
653
        self.buildqueue = self.build.queueBuild()
654
        self.buildqueue.markAsBuilding(self.builder)
655
656
    def test_equal_failures_reset_job(self):
657
        self.builder.gotFailure()
658
        self.builder.getCurrentBuildFarmJob().gotFailure()
659
660
        assessFailureCounts(self.builder, "failnotes")
661
        self.assertIs(None, self.builder.currentjob)
662
        self.assertEqual(self.build.status, BuildStatus.NEEDSBUILD)
663
664
    def test_job_failing_more_than_builder_fails_job(self):
665
        self.builder.getCurrentBuildFarmJob().gotFailure()
11983.2.1 by Julian Edwards
Ensure that builder failure_count is reset when deciding to fail a job
666
        self.builder.getCurrentBuildFarmJob().gotFailure()
667
        self.builder.gotFailure()
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
668
669
        assessFailureCounts(self.builder, "failnotes")
670
        self.assertIs(None, self.builder.currentjob)
671
        self.assertEqual(self.build.status, BuildStatus.FAILEDTOBUILD)
11983.2.1 by Julian Edwards
Ensure that builder failure_count is reset when deciding to fail a job
672
        self.assertEqual(0, self.builder.failure_count)
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
673
674
    def test_builder_failing_more_than_job_but_under_fail_threshold(self):
675
        self.builder.failure_count = Builder.FAILURE_THRESHOLD - 1
676
677
        assessFailureCounts(self.builder, "failnotes")
678
        self.assertIs(None, self.builder.currentjob)
679
        self.assertEqual(self.build.status, BuildStatus.NEEDSBUILD)
680
        self.assertTrue(self.builder.builderok)
681
682
    def test_builder_failing_more_than_job_but_over_fail_threshold(self):
683
        self.builder.failure_count = Builder.FAILURE_THRESHOLD
684
685
        assessFailureCounts(self.builder, "failnotes")
686
        self.assertIs(None, self.builder.currentjob)
687
        self.assertEqual(self.build.status, BuildStatus.NEEDSBUILD)
688
        self.assertFalse(self.builder.builderok)
689
        self.assertEqual("failnotes", self.builder.failnotes)
690
691
    def test_builder_failing_with_no_attached_job(self):
692
        self.buildqueue.reset()
693
        self.builder.failure_count = Builder.FAILURE_THRESHOLD
694
695
        assessFailureCounts(self.builder, "failnotes")
696
        self.assertFalse(self.builder.builderok)
697
        self.assertEqual("failnotes", self.builder.failnotes)
698
699
11705.2.25 by Jonathan Lange
Easier than I thought.
700
class TestNewBuilders(TestCase):
10888.6.11 by Julian Edwards
First part of detecting new builders
701
    """Test detecting of new builders."""
702
11705.2.25 by Jonathan Lange
Easier than I thought.
703
    layer = LaunchpadZopelessLayer
10888.6.11 by Julian Edwards
First part of detecting new builders
704
10888.6.26 by Julian Edwards
more cleanups
705
    def _getScanner(self, manager=None, clock=None):
706
        return NewBuildersScanner(manager=manager, clock=clock)
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
707
10888.6.11 by Julian Edwards
First part of detecting new builders
708
    def test_init_stores_existing_builders(self):
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
709
        # Make sure that NewBuildersScanner initializes itself properly
10888.6.12 by Julian Edwards
Add scheduleScan and a test
710
        # by storing a list of existing builders.
10888.6.11 by Julian Edwards
First part of detecting new builders
711
        all_builders = [builder.name for builder in getUtility(IBuilderSet)]
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
712
        builder_scanner = self._getScanner()
10888.6.11 by Julian Edwards
First part of detecting new builders
713
        self.assertEqual(all_builders, builder_scanner.current_builders)
714
10888.6.12 by Julian Edwards
Add scheduleScan and a test
715
    def test_scheduleScan(self):
716
        # Test that scheduleScan calls the "scan" method.
10888.6.26 by Julian Edwards
more cleanups
717
        clock = task.Clock()
718
        builder_scanner = self._getScanner(clock=clock)
10888.6.30 by Julian Edwards
woops, return instantiated FakeMethod when stubbing out methods in tests
719
        builder_scanner.scan = FakeMethod()
10888.6.12 by Julian Edwards
Add scheduleScan and a test
720
        builder_scanner.scheduleScan()
721
10888.6.26 by Julian Edwards
more cleanups
722
        advance = NewBuildersScanner.SCAN_INTERVAL + 1
723
        clock.advance(advance)
724
        self.assertNotEqual(
725
            0, builder_scanner.scan.call_count,
726
            "scheduleScan did not schedule anything")
10888.6.11 by Julian Edwards
First part of detecting new builders
727
10888.6.13 by Julian Edwards
basic case for checkForNewBuilders not returning anything
728
    def test_checkForNewBuilders(self):
729
        # Test that checkForNewBuilders() detects a new builder
10888.6.14 by Julian Edwards
checkForNewBuilders returns builders if they're new
730
731
        # The basic case, where no builders are added.
10888.6.15 by Julian Edwards
refactor code to add scanners and add a test for it
732
        builder_scanner = self._getScanner()
10888.6.26 by Julian Edwards
more cleanups
733
        self.assertEqual([], builder_scanner.checkForNewBuilders())
10888.6.13 by Julian Edwards
basic case for checkForNewBuilders not returning anything
734
10888.6.14 by Julian Edwards
checkForNewBuilders returns builders if they're new
735
        # Add two builders and ensure they're returned.
736
        new_builders = ["scooby", "lassie"]
737
        factory = LaunchpadObjectFactory()
738
        for builder_name in new_builders:
739
            factory.makeBuilder(name=builder_name)
10888.6.26 by Julian Edwards
more cleanups
740
        self.assertEqual(
10888.6.14 by Julian Edwards
checkForNewBuilders returns builders if they're new
741
            new_builders, builder_scanner.checkForNewBuilders())
742
12374.2.1 by Gavin Panella
Ensure that checkForNewBuilders() only detects a new builder once.
743
    def test_checkForNewBuilders_detects_builder_only_once(self):
744
        # checkForNewBuilders() only detects a new builder once.
745
        builder_scanner = self._getScanner()
746
        LaunchpadObjectFactory().makeBuilder(name="sammy")
747
        self.assertEqual(["sammy"], builder_scanner.checkForNewBuilders())
748
        self.assertEqual([], builder_scanner.checkForNewBuilders())
749
10888.6.16 by Julian Edwards
add scan() and a test
750
    def test_scan(self):
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
751
        # See if scan detects new builders.
10888.6.16 by Julian Edwards
add scan() and a test
752
753
        def fake_checkForNewBuilders():
754
            return "new_builders"
755
756
        def fake_addScanForBuilders(new_builders):
10888.6.27 by Julian Edwards
one more test cleanup
757
            self.assertEqual("new_builders", new_builders)
10888.6.16 by Julian Edwards
add scan() and a test
758
10888.6.26 by Julian Edwards
more cleanups
759
        clock = task.Clock()
760
        builder_scanner = self._getScanner(BuilddManager(), clock=clock)
10888.6.16 by Julian Edwards
add scan() and a test
761
        builder_scanner.checkForNewBuilders = fake_checkForNewBuilders
762
        builder_scanner.manager.addScanForBuilders = fake_addScanForBuilders
10888.6.30 by Julian Edwards
woops, return instantiated FakeMethod when stubbing out methods in tests
763
        builder_scanner.scheduleScan = FakeMethod()
10888.6.16 by Julian Edwards
add scan() and a test
764
10888.6.26 by Julian Edwards
more cleanups
765
        builder_scanner.scan()
766
        advance = NewBuildersScanner.SCAN_INTERVAL + 1
767
        clock.advance(advance)
10888.6.16 by Julian Edwards
add scan() and a test
768
10888.6.13 by Julian Edwards
basic case for checkForNewBuilders not returning anything
769
11121.2.7 by Henning Eggers
Reviewer suggestions.
770
def is_file_growing(filepath, poll_interval=1, poll_repeat=10):
771
    """Poll the file size to see if it grows.
772
773
    Checks the size of the file in given intervals and returns True as soon as
774
    it sees the size increase between two polls. If the size does not
775
    increase after a given number of polls, the function returns False.
776
    If the file does not exist, the function silently ignores that and waits
777
    for it to appear on the next pall. If it has not appeared by the last
778
    poll, the exception is propagated.
779
    Program execution is blocked during polling.
780
781
    :param filepath: The path to the file to be palled.
782
    :param poll_interval: The number of seconds in between two polls.
783
    :param poll_repeat: The number times to repeat the polling, so the size is
784
        polled a total of poll_repeat+1 times. The default values create a
785
        total poll time of 11 seconds. The BuilddManager logs
786
        "scanning cycles" every 5 seconds so these settings should see an
7675.767.10 by William Grant
Fix lint.
787
        increase if the process is logging to this file.
11121.2.7 by Henning Eggers
Reviewer suggestions.
788
    """
11121.2.3 by Henning Eggers
Added test for logging behavior.
789
    last_size = None
14206.2.11 by Julian Edwards
fix lint
790
    for poll in range(poll_repeat + 1):
11121.2.3 by Henning Eggers
Added test for logging behavior.
791
        try:
11121.2.7 by Henning Eggers
Reviewer suggestions.
792
            statinfo = os.stat(filepath)
11121.2.3 by Henning Eggers
Added test for logging behavior.
793
            if last_size is None:
794
                last_size = statinfo.st_size
795
            elif statinfo.st_size > last_size:
796
                return True
797
            else:
798
                # The file should not be shrinking.
799
                assert statinfo.st_size == last_size
800
        except OSError:
11121.2.5 by Henning Eggers
Removed some lint.
801
            if poll == poll_repeat:
11121.2.3 by Henning Eggers
Added test for logging behavior.
802
                # Propagate only on the last loop, i.e. give up.
803
                raise
11121.2.5 by Henning Eggers
Removed some lint.
804
        time.sleep(poll_interval)
11121.2.3 by Henning Eggers
Added test for logging behavior.
805
    return False
806
807
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
808
class TestBuilddManagerScript(TestCaseWithFactory):
8486.7.1 by Celso Providelo
Fixing bug #380848 (buildd-manager circular imports, also testing if the TAC file starts and stops correctly).
809
8486.7.3 by Celso Providelo
Fixing test failure.
810
    layer = LaunchpadScriptLayer
8486.7.1 by Celso Providelo
Fixing bug #380848 (buildd-manager circular imports, also testing if the TAC file starts and stops correctly).
811
812
    def testBuilddManagerRuns(self):
11121.2.3 by Henning Eggers
Added test for logging behavior.
813
        # The `buildd-manager.tac` starts and stops correctly.
11634.2.8 by Robert Collins
Fix test failures.
814
        fixture = BuilddManagerTestSetup()
815
        fixture.setUp()
816
        fixture.tearDown()
11593.3.120 by Julian Edwards
re-add revno 11801 which was backed out in devel due to test failures resulting from a twisted bug
817
        self.layer.force_dirty_database()
8486.7.1 by Celso Providelo
Fixing bug #380848 (buildd-manager circular imports, also testing if the TAC file starts and stops correctly).
818
10888.6.35 by Julian Edwards
disable the two logging tests which should be in lp.services.twistedsupport, not here. they are preventing me from landing this branch. see bug 614275
819
    # XXX Julian 2010-08-06 bug=614275
820
    # These next 2 tests are in the wrong place, they should be near the
821
    # implementation of RotatableFileLogObserver and not depend on the
822
    # behaviour of the buildd-manager.  I've disabled them here because
823
    # they prevented me from landing this branch which reduces the
824
    # logging output.
825
826
    def disabled_testBuilddManagerLogging(self):
11121.2.7 by Henning Eggers
Reviewer suggestions.
827
        # The twistd process logs as execpected.
11634.2.8 by Robert Collins
Fix test failures.
828
        test_setup = self.useFixture(BuilddManagerTestSetup())
11121.2.3 by Henning Eggers
Added test for logging behavior.
829
        logfilepath = test_setup.logfile
11121.2.7 by Henning Eggers
Reviewer suggestions.
830
        # The process logs to its logfile.
11121.2.3 by Henning Eggers
Added test for logging behavior.
831
        self.assertTrue(is_file_growing(logfilepath))
832
        # After rotating the log, the process keeps using the old file, no
833
        # new file is created.
14206.2.11 by Julian Edwards
fix lint
834
        rotated_logfilepath = logfilepath + '.1'
11121.2.3 by Henning Eggers
Added test for logging behavior.
835
        os.rename(logfilepath, rotated_logfilepath)
836
        self.assertTrue(is_file_growing(rotated_logfilepath))
837
        self.assertFalse(os.access(logfilepath, os.F_OK))
838
        # Upon receiving the USR1 signal, the process will re-open its log
839
        # file at the old location.
840
        test_setup.sendSignal(signal.SIGUSR1)
841
        self.assertTrue(is_file_growing(logfilepath))
842
        self.assertTrue(os.access(rotated_logfilepath, os.F_OK))
843
10888.6.35 by Julian Edwards
disable the two logging tests which should be in lp.services.twistedsupport, not here. they are preventing me from landing this branch. see bug 614275
844
    def disabled_testBuilddManagerLoggingNoRotation(self):
11121.2.4 by Henning Eggers
Added test for log file rotation not happening.
845
        # The twistd process does not perform its own rotation.
846
        # By default twistd will rotate log files that grow beyond
847
        # 1000000 bytes but this is deactivated for the buildd manager.
848
        test_setup = BuilddManagerTestSetup()
849
        logfilepath = test_setup.logfile
14206.2.11 by Julian Edwards
fix lint
850
        rotated_logfilepath = logfilepath + '.1'
11121.2.4 by Henning Eggers
Added test for log file rotation not happening.
851
        # Prefill the log file to just under 1000000 bytes.
852
        test_setup.precreateLogfile(
853
            "2010-07-27 12:36:54+0200 [-] Starting scanning cycle.\n", 18518)
11634.2.8 by Robert Collins
Fix test failures.
854
        self.useFixture(test_setup)
11121.2.7 by Henning Eggers
Reviewer suggestions.
855
        # The process logs to the logfile.
11121.2.4 by Henning Eggers
Added test for log file rotation not happening.
856
        self.assertTrue(is_file_growing(logfilepath))
857
        # No rotation occured.
858
        self.assertFalse(
859
            os.access(rotated_logfilepath, os.F_OK),
860
            "Twistd's log file was rotated by twistd.")