~ubuntu-branches/ubuntu/trusty/buildbot/trusty-proposed

« back to all changes in this revision

Viewing changes to buildbot/test/unit/test_process_builder.py

  • Committer: Package Import Robot
  • Author(s): Andriy Senkovych
  • Date: 2013-10-10 13:22:47 UTC
  • mfrom: (1.2.10)
  • Revision ID: package-import@ubuntu.com-20131010132247-m622rpa3yemt62te
Tags: 0.8.8-1
* New upstream release
* Remove text-client.patch (applied upstream)
* Add bash-completion. Thanks to Elmir Jagudin
* debian/control: add Vcs-* fields

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
import mock
17
17
import random
18
18
from twisted.trial import unittest
19
 
from twisted.python import failure
20
19
from twisted.internet import defer
21
20
from buildbot import config
22
 
from buildbot.status import master
23
21
from buildbot.test.fake import fakedb, fakemaster
24
22
from buildbot.process import builder, factory
25
 
from buildbot.db import buildrequests
26
23
from buildbot.util import epoch2datetime
27
24
 
28
 
class TestBuilderBuildCreation(unittest.TestCase):
29
 
 
30
 
    def setUp(self):
31
 
        # a collection of rows that would otherwise clutter up every test
32
 
        self.base_rows = [
33
 
            fakedb.SourceStampSet(id=21),
34
 
            fakedb.SourceStamp(id=21, sourcestampsetid=21),
35
 
            fakedb.Buildset(id=11, reason='because', sourcestampsetid=21),
36
 
        ]
37
 
 
38
 
    def makeBuilder(self, patch_random=False, **config_kwargs):
 
25
class BuilderMixin(object):
 
26
    def makeBuilder(self, name="bldr", patch_random=False, **config_kwargs):
39
27
        """Set up C{self.bldr}"""
40
 
        self.bstatus = mock.Mock()
41
28
        self.factory = factory.BuildFactory()
42
29
        self.master = fakemaster.make_master()
43
30
        # only include the necessary required config, plus user-requested
44
 
        config_args = dict(name="bldr", slavename="slv", builddir="bdir",
 
31
        config_args = dict(name=name, slavename="slv", builddir="bdir",
45
32
                     slavebuilddir="sbdir", factory=self.factory)
46
33
        config_args.update(config_kwargs)
47
 
        builder_config = config.BuilderConfig(**config_args)
48
 
        self.bldr = builder.Builder(builder_config.name, _addServices=False)
 
34
        self.builder_config = config.BuilderConfig(**config_args)
 
35
        self.bldr = builder.Builder(self.builder_config.name, _addServices=False)
49
36
        self.master.db = self.db = fakedb.FakeDBConnector(self)
50
37
        self.bldr.master = self.master
51
38
        self.bldr.botmaster = self.master.botmaster
66
53
        self.bldr.startService()
67
54
 
68
55
        mastercfg = config.MasterConfig()
69
 
        mastercfg.builders = [ builder_config ]
 
56
        mastercfg.builders = [ self.builder_config ]
70
57
        return self.bldr.reconfigService(mastercfg)
71
58
 
 
59
class TestBuilderBuildCreation(BuilderMixin, unittest.TestCase):
 
60
 
 
61
    def setUp(self):
 
62
        # a collection of rows that would otherwise clutter up every test
 
63
        self.base_rows = [
 
64
            fakedb.SourceStampSet(id=21),
 
65
            fakedb.SourceStamp(id=21, sourcestampsetid=21),
 
66
            fakedb.Buildset(id=11, reason='because', sourcestampsetid=21),
 
67
        ]
 
68
 
 
69
    def makeBuilder(self, patch_random=False, startBuildsForSucceeds=True, **config_kwargs):
 
70
        d = BuilderMixin.makeBuilder(self, patch_random=patch_random, **config_kwargs)
 
71
        @d.addCallback
 
72
        def patch_startBuildsFor(_):
 
73
            # patch into the _startBuildsFor method
 
74
            self.builds_started = []
 
75
            def _startBuildFor(slavebuilder, buildrequests):
 
76
                self.builds_started.append((slavebuilder, buildrequests))
 
77
                return defer.succeed(startBuildsForSucceeds)
 
78
            self.bldr._startBuildFor = _startBuildFor
 
79
        return d
 
80
 
72
81
    def assertBuildsStarted(self, exp):
73
82
        # munge builds_started into a list of (slave, [brids])
74
83
        builds_started = [
88
97
    # services
89
98
 
90
99
    @defer.inlineCallbacks
91
 
    def test_stopService_flushes(self):
92
 
        yield self.makeBuilder()
93
 
 
94
 
        # just check that stopService calls this and waits
95
 
        # for the deferred to fire
96
 
        events = []
97
 
 
98
 
        long_d = defer.Deferred()
99
 
        long_d.addCallback(lambda _ : events.append('long_d'))
100
 
        self.bldr.maybeStartBuild = lambda : long_d
101
 
 
102
 
        stop_d = self.bldr.stopService()
103
 
        stop_d.addCallback(lambda _ : events.append('stop_d'))
104
 
 
105
 
        # nothing should have happened yet
106
 
        self.assertEqual(events, [])
107
 
 
108
 
        # finish the maybeStartBuild invocation..
109
 
        long_d.callback(None)
110
 
 
111
 
        yield stop_d
112
 
 
113
 
        # and then check that things happened in the right order
114
 
        self.assertEqual(events, [ 'long_d', 'stop_d' ])
115
 
 
116
 
    # maybeStartBuild
117
 
 
118
 
    def do_test_maybeStartBuild(self, rows=[], exp_claims=[], exp_builds=[],
119
 
                exp_fail=None):
120
 
        d = self.db.insertTestData(rows)
121
 
        d.addCallback(lambda _ :
122
 
                self.bldr.maybeStartBuild())
123
 
        def check(_):
124
 
            self.failIf(exp_fail)
125
 
            self.db.buildrequests.assertMyClaims(exp_claims)
126
 
            self.assertBuildsStarted(exp_builds)
127
 
        d.addCallback(check)
128
 
        def eb(f):
129
 
            f.trap(exp_fail)
130
 
        d.addErrback(eb)
131
 
        return d
132
 
 
133
 
    @defer.inlineCallbacks
134
 
    def test_maybeStartBuild_no_buildreqests(self):
135
 
        yield self.makeBuilder()
136
 
        self.setSlaveBuilders({'test-slave11':1})
137
 
        yield self.do_test_maybeStartBuild(exp_claims=[], exp_builds=[])
138
 
 
139
 
    @defer.inlineCallbacks
140
 
    def test_maybeStartBuild_no_slavebuilders(self):
141
 
        yield self.makeBuilder()
142
 
        rows = [
143
 
            fakedb.BuildRequest(id=11, buildsetid=10, buildername="bldr"),
144
 
        ]
145
 
        yield self.do_test_maybeStartBuild(rows=rows,
146
 
                exp_claims=[], exp_builds=[])
147
 
 
148
 
    @defer.inlineCallbacks
149
 
    def test_maybeStartBuild_limited_by_slaves(self):
150
 
        yield self.makeBuilder(mergeRequests=False)
151
 
 
152
 
        self.setSlaveBuilders({'test-slave1':1})
153
 
        rows = self.base_rows + [
154
 
            fakedb.BuildRequest(id=10, buildsetid=11, buildername="bldr",
155
 
                submitted_at=130000),
156
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr",
157
 
                submitted_at=135000),
158
 
        ]
159
 
        yield self.do_test_maybeStartBuild(rows=rows,
160
 
                exp_claims=[10], exp_builds=[('test-slave1', [10])])
161
 
 
162
 
    @defer.inlineCallbacks
163
 
    def test_maybeStartBuild_limited_by_available_slaves(self):
164
 
        yield self.makeBuilder(mergeRequests=False)
165
 
 
166
 
        self.setSlaveBuilders({'test-slave1':0, 'test-slave2':1})
167
 
        rows = self.base_rows + [
168
 
            fakedb.BuildRequest(id=10, buildsetid=11, buildername="bldr",
169
 
                submitted_at=130000),
170
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr",
171
 
                submitted_at=135000),
172
 
        ]
173
 
        yield self.do_test_maybeStartBuild(rows=rows,
174
 
                exp_claims=[10], exp_builds=[('test-slave2', [10])])
175
 
 
176
 
    @defer.inlineCallbacks
177
 
    def test_maybeStartBuild_unlimited(self):
178
 
        yield self.makeBuilder(mergeRequests=False, patch_random=True)
179
 
 
180
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
181
 
        rows = self.base_rows + [
182
 
            fakedb.BuildRequest(id=10, buildsetid=11, buildername="bldr",
183
 
                submitted_at=130000),
184
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr",
185
 
                submitted_at=135000),
186
 
        ]
187
 
        yield self.do_test_maybeStartBuild(rows=rows,
188
 
                exp_claims=[10, 11],
189
 
                exp_builds=[('test-slave2', [10]), ('test-slave1', [11])])
190
 
 
191
 
    @defer.inlineCallbacks
192
 
    def test_maybeStartBuild_limited_by_requests(self):
193
 
        yield self.makeBuilder(mergeRequests=False, patch_random=True)
194
 
 
195
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
196
 
        rows = self.base_rows + [
197
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
198
 
        ]
199
 
        yield self.do_test_maybeStartBuild(rows=rows,
200
 
                exp_claims=[11], exp_builds=[('test-slave2', [11])])
201
 
 
202
 
    @defer.inlineCallbacks
203
 
    def test_maybeStartBuild_chooseSlave_None(self):
204
 
        yield self.makeBuilder()
205
 
 
206
 
        self.bldr._chooseSlave = lambda avail : defer.succeed(None)
207
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
208
 
        rows = self.base_rows + [
209
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
210
 
        ]
211
 
        yield self.do_test_maybeStartBuild(rows=rows,
212
 
                exp_claims=[], exp_builds=[])
213
 
 
214
 
    @defer.inlineCallbacks
215
 
    def test_maybeStartBuild_chooseSlave_bogus(self):
216
 
        yield self.makeBuilder()
217
 
 
218
 
        self.bldr._chooseSlave = lambda avail : defer.succeed(mock.Mock())
219
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
220
 
        rows = self.base_rows + [
221
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
222
 
        ]
223
 
        yield self.do_test_maybeStartBuild(rows=rows,
224
 
                exp_claims=[], exp_builds=[])
225
 
 
226
 
    @defer.inlineCallbacks
227
 
    def test_maybeStartBuild_chooseSlave_fails(self):
228
 
        yield self.makeBuilder()
229
 
 
230
 
        self.bldr._chooseSlave = lambda avail : defer.fail(RuntimeError("xx"))
231
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
232
 
        rows = self.base_rows + [
233
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
234
 
        ]
235
 
        yield self.do_test_maybeStartBuild(rows=rows,
236
 
                exp_claims=[], exp_builds=[], exp_fail=RuntimeError)
237
 
 
238
 
    @defer.inlineCallbacks
239
 
    def test_maybeStartBuild_chooseBuild_None(self):
240
 
        yield self.makeBuilder()
241
 
 
242
 
        self.bldr._chooseBuild = lambda reqs : defer.succeed(None)
243
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
244
 
        rows = self.base_rows + [
245
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
246
 
        ]
247
 
        yield self.do_test_maybeStartBuild(rows=rows,
248
 
                exp_claims=[], exp_builds=[])
249
 
 
250
 
    @defer.inlineCallbacks
251
 
    def test_maybeStartBuild_chooseBuild_bogus(self):
252
 
        yield self.makeBuilder()
253
 
 
254
 
        self.bldr._chooseBuild = lambda reqs : defer.succeed(mock.Mock())
255
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
256
 
        rows = self.base_rows + [
257
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
258
 
        ]
259
 
        yield self.do_test_maybeStartBuild(rows=rows,
260
 
                exp_claims=[], exp_builds=[])
261
 
 
262
 
    @defer.inlineCallbacks
263
 
    def test_maybeStartBuild_chooseBuild_fails(self):
264
 
        yield self.makeBuilder(patch_random=True)
265
 
 
266
 
        self.bldr._chooseBuild = lambda reqs : defer.fail(RuntimeError("xx"))
267
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
268
 
        rows = self.base_rows + [
269
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
270
 
        ]
271
 
        yield self.do_test_maybeStartBuild(rows=rows,
272
 
                exp_claims=[], exp_builds=[], exp_fail=RuntimeError)
273
 
 
274
 
    @defer.inlineCallbacks
275
 
    def test_maybeStartBuild_mergeRequests_fails(self):
276
 
        yield self.makeBuilder(patch_random=True)
277
 
 
278
 
        def _mergeRequests(breq, unclaimed_requests, mergeRequests_fn):
279
 
            return defer.fail(RuntimeError("xx"))
280
 
        self.bldr._mergeRequests = _mergeRequests
281
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
282
 
        rows = self.base_rows + [
283
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr"),
284
 
        ]
285
 
        yield self.do_test_maybeStartBuild(rows=rows,
286
 
                exp_claims=[], exp_builds=[], exp_fail=RuntimeError)
287
 
 
288
 
    @defer.inlineCallbacks
289
 
    def test_maybeStartBuild_claim_race(self):
290
 
        yield self.makeBuilder(patch_random=True)
291
 
 
292
 
        # fake a race condition on the buildrequests table
293
 
        old_claimBuildRequests = self.db.buildrequests.claimBuildRequests
294
 
        def claimBuildRequests(brids):
295
 
            # first, ensure this only happens the first time
296
 
            self.db.buildrequests.claimBuildRequests = old_claimBuildRequests
297
 
            # claim brid 10 for some other master
298
 
            assert 10 in brids
299
 
            self.db.buildrequests.fakeClaimBuildRequest(10, 136000,
300
 
                    objectid=9999) # some other objectid
301
 
            # ..and fail
302
 
            return defer.fail(buildrequests.AlreadyClaimedError())
303
 
        self.db.buildrequests.claimBuildRequests = claimBuildRequests
304
 
 
305
 
        self.setSlaveBuilders({'test-slave1':1, 'test-slave2':1})
306
 
        rows = self.base_rows + [
307
 
            fakedb.BuildRequest(id=10, buildsetid=11, buildername="bldr",
308
 
                submitted_at=130000), # will turn out to be claimed!
309
 
            fakedb.BuildRequest(id=11, buildsetid=11, buildername="bldr",
310
 
                submitted_at=135000),
311
 
        ]
312
 
        yield self.do_test_maybeStartBuild(rows=rows,
313
 
                exp_claims=[11], exp_builds=[('test-slave2', [11])])
314
 
 
315
 
    @defer.inlineCallbacks
316
100
    def test_maybeStartBuild_builder_stopped(self):
317
101
        yield self.makeBuilder()
318
102
 
321
105
 
322
106
        # so we just hope this does not fail
323
107
        yield self.bldr.stopService()
324
 
        yield self.bldr.maybeStartBuild()
325
 
 
326
 
    @defer.inlineCallbacks
327
 
    def test_maybeStartBuild_merge_ordering(self):
328
 
        yield self.makeBuilder(patch_random=True)
329
 
 
330
 
        self.setSlaveBuilders({'bldr':1})
331
 
 
332
 
        # based on the build in bug #2249
333
 
        rows = [
334
 
            fakedb.SourceStampSet(id=1976),
335
 
            fakedb.SourceStamp(id=1976, sourcestampsetid=1976),
336
 
            fakedb.Buildset(id=1980, reason='scheduler', sourcestampsetid=1976,
337
 
                submitted_at=1332024020.67792),
338
 
            fakedb.BuildRequest(id=42880, buildsetid=1980,
339
 
                submitted_at=1332024020.67792, buildername="bldr"),
340
 
 
341
 
            fakedb.SourceStampSet(id=1977),
342
 
            fakedb.SourceStamp(id=1977, sourcestampsetid=1977),
343
 
            fakedb.Buildset(id=1981, reason='scheduler', sourcestampsetid=1977,
344
 
                submitted_at=1332025495.19141),
345
 
            fakedb.BuildRequest(id=42922, buildsetid=1981,
346
 
                buildername="bldr", submitted_at=1332025495.19141),
347
 
        ]
348
 
        yield self.do_test_maybeStartBuild(rows=rows,
349
 
                exp_claims=[42880, 42922],
350
 
                exp_builds=[('bldr', [42880, 42922])])
351
 
 
352
 
    # _chooseSlave
353
 
 
354
 
    def do_test_chooseSlave(self, nextSlave, exp_choice=None, exp_fail=None):
355
 
        slavebuilders = [ mock.Mock(name='sb%d' % i) for i in range(4) ]
356
 
 
357
 
        d = self.makeBuilder(nextSlave=nextSlave)
358
 
        d.addCallback(lambda _ : self.bldr._chooseSlave(slavebuilders))
359
 
        def check(sb):
360
 
            self.assertIdentical(sb, slavebuilders[exp_choice])
361
 
        def failed(f):
362
 
            f.trap(exp_fail)
363
 
        d.addCallbacks(check, failed)
364
 
        return d
365
 
 
366
 
    def test_chooseSlave_default(self):
367
 
        self.patch(random, "choice", lambda lst : lst[2])
368
 
        return self.do_test_chooseSlave(None, exp_choice=2)
369
 
 
370
 
    def test_chooseSlave_nextSlave_simple(self):
371
 
        def nextSlave(bldr, lst):
372
 
            self.assertIdentical(bldr, self.bldr)
373
 
            return lst[1]
374
 
        return self.do_test_chooseSlave(nextSlave, exp_choice=1)
375
 
 
376
 
    def test_chooseSlave_nextSlave_deferred(self):
377
 
        def nextSlave(bldr, lst):
378
 
            self.assertIdentical(bldr, self.bldr)
379
 
            return defer.succeed(lst[1])
380
 
        return self.do_test_chooseSlave(nextSlave, exp_choice=1)
381
 
 
382
 
    def test_chooseSlave_nextSlave_exception(self):
383
 
        def nextSlave(bldr, lst):
384
 
            raise RuntimeError
385
 
        return self.do_test_chooseSlave(nextSlave, exp_fail=RuntimeError)
386
 
 
387
 
    def test_chooseSlave_nextSlave_failure(self):
388
 
        def nextSlave(bldr, lst):
389
 
            return defer.fail(failure.Failure(RuntimeError()))
390
 
        return self.do_test_chooseSlave(nextSlave, exp_fail=RuntimeError)
391
 
 
392
 
    # _chooseBuild
393
 
 
394
 
    def do_test_chooseBuild(self, nextBuild, exp_choice=None, exp_fail=None):
395
 
 
396
 
        def mkrq(n):
397
 
            brdict = dict(brobj=mock.Mock(name='br%d' % n))
398
 
            brdict['brobj'].brdict = brdict
399
 
            return brdict
400
 
        requests = [ mkrq(i) for i in range(4) ]
401
 
 
402
 
        d = self.makeBuilder(nextBuild=nextBuild)
403
 
        d.addCallback(lambda _ : self.bldr._chooseBuild(requests))
404
 
        def check(sb):
405
 
            self.assertIdentical(sb, requests[exp_choice])
406
 
        def failed(f):
407
 
            f.trap(exp_fail)
408
 
        d.addCallbacks(check, failed)
409
 
        return d
410
 
 
411
 
    def test_chooseBuild_default(self):
412
 
        "default chooses the first in the list, which should be the earliest"
413
 
        return self.do_test_chooseBuild(None, exp_choice=0)
414
 
 
415
 
    def test_chooseBuild_nextBuild_simple(self):
416
 
        def nextBuild(bldr, lst):
417
 
            self.assertIdentical(bldr, self.bldr)
418
 
            return lst[3]
419
 
        return self.do_test_chooseBuild(nextBuild, exp_choice=3)
420
 
 
421
 
    def test_chooseBuild_nextBuild_deferred(self):
422
 
        def nextBuild(bldr, lst):
423
 
            self.assertIdentical(bldr, self.bldr)
424
 
            return defer.succeed(lst[2])
425
 
        return self.do_test_chooseBuild(nextBuild, exp_choice=2)
426
 
 
427
 
    def test_chooseBuild_nextBuild_exception(self):
428
 
        def nextBuild(bldr, lst):
429
 
            raise RuntimeError
430
 
        return self.do_test_chooseBuild(nextBuild, exp_fail=RuntimeError)
431
 
 
432
 
    def test_chooseBuild_nextBuild_failure(self):
433
 
        def nextBuild(bldr, lst):
434
 
            return defer.fail(failure.Failure(RuntimeError()))
435
 
        return self.do_test_chooseBuild(nextBuild, exp_fail=RuntimeError)
436
 
 
437
 
    # _brdictToBuildRequest
438
 
 
439
 
    @defer.inlineCallbacks
440
 
    def test_brdictToBuildRequest(self):
 
108
        started = yield self.bldr.maybeStartBuild(None, [])
 
109
        self.assertEquals(started, False)
 
110
 
 
111
 
 
112
    # maybeStartBuild
 
113
 
 
114
    def _makeMocks(self):
 
115
        slave = mock.Mock()
 
116
        slave.name = 'slave'
 
117
        buildrequest = mock.Mock()
 
118
        buildrequest.id = 10
 
119
        buildrequests = [buildrequest]
 
120
        return slave, buildrequests
 
121
 
 
122
    @defer.inlineCallbacks
 
123
    def test_maybeStartBuild(self):
441
124
        yield self.makeBuilder()
442
125
 
443
 
        # set up all of the data required for a BuildRequest object
444
 
        yield self.db.insertTestData([
445
 
                fakedb.SourceStampSet(id=234),
446
 
                fakedb.SourceStamp(id=234,sourcestampsetid=234),
447
 
                fakedb.Buildset(id=30, sourcestampsetid=234, reason='foo',
448
 
                    submitted_at=1300305712, results=-1),
449
 
                fakedb.BuildRequest(id=19, buildsetid=30, buildername='bldr',
450
 
                    priority=13, submitted_at=1300305712, results=-1),
451
 
            ])
452
 
 
453
 
        brdict = yield self.db.buildrequests.getBuildRequest(19)
454
 
        br = yield self.bldr._brdictToBuildRequest(brdict)
455
 
 
456
 
        # just check that the BuildRequest looks reasonable -
457
 
        # test_process_buildrequest checks the whole thing
458
 
        self.assertEqual(br.reason, 'foo')
459
 
 
460
 
        # and check that the cross-pointers are correct
461
 
        self.assertIdentical(br.brdict, brdict)
462
 
        self.assertIdentical(brdict['brobj'], br)
463
 
 
464
 
        self.bldr._breakBrdictRefloops([brdict])
465
 
 
466
 
    # _getMergeRequestsFn
 
126
        slave, buildrequests = self._makeMocks()
 
127
 
 
128
        started = yield self.bldr.maybeStartBuild(slave, buildrequests)
 
129
        self.assertEqual(started, True)
 
130
        self.assertBuildsStarted([('slave', [10])])
 
131
 
 
132
    @defer.inlineCallbacks
 
133
    def test_maybeStartBuild_failsToStart(self):
 
134
        yield self.makeBuilder(startBuildsForSucceeds=False)
 
135
 
 
136
        slave, buildrequests = self._makeMocks()
 
137
 
 
138
        started = yield self.bldr.maybeStartBuild(slave, buildrequests)
 
139
        self.assertEqual(started, False)
 
140
        self.assertBuildsStarted([('slave', [10])])
467
141
 
468
142
    @defer.inlineCallbacks
469
143
    def do_test_getMergeRequestsFn(self, builder_param=None,
480
154
 
481
155
        self.master.config.mergeRequests = global_param
482
156
 
483
 
        fn = self.bldr._getMergeRequestsFn()
 
157
        fn = self.bldr.getMergeRequestsFn()
484
158
 
485
159
        if fn == builder.Builder._defaultMergeRequestFn:
486
160
            fn = "default"
509
183
    def test_getMergeRequestsFn_builder_function(self):
510
184
        self.do_test_getMergeRequestsFn('callable', None, 'callable')
511
185
 
512
 
    # _mergeRequests
513
 
 
514
 
    @defer.inlineCallbacks
515
 
    def test_mergeRequests(self):
516
 
        yield self.makeBuilder()
517
 
 
518
 
        # set up all of the data required for a BuildRequest object
519
 
        yield self.db.insertTestData([
520
 
                fakedb.SourceStampSet(id=234),
521
 
                fakedb.SourceStamp(id=234, sourcestampsetid=234),
522
 
                fakedb.Buildset(id=30, sourcestampsetid=234, reason='foo',
523
 
                    submitted_at=1300305712, results=-1),
524
 
                fakedb.BuildRequest(id=19, buildsetid=30, buildername='bldr',
525
 
                    priority=13, submitted_at=1300305712, results=-1),
526
 
                fakedb.BuildRequest(id=20, buildsetid=30, buildername='bldr',
527
 
                    priority=13, submitted_at=1300305712, results=-1),
528
 
                fakedb.BuildRequest(id=21, buildsetid=30, buildername='bldr',
529
 
                    priority=13, submitted_at=1300305712, results=-1),
530
 
            ])
531
 
 
532
 
        brdicts = yield defer.gatherResults([
533
 
                self.db.buildrequests.getBuildRequest(id)
534
 
                for id in (19, 20, 21)
535
 
            ])
536
 
 
537
 
        def mergeRequests_fn(builder, breq, other):
538
 
            # merge evens with evens, odds with odds
539
 
            return breq.id % 2 == other.id % 2
540
 
 
541
 
        # check odds
542
 
        odds = yield self.bldr._mergeRequests(brdicts[0],
543
 
                                brdicts, mergeRequests_fn)
544
 
        self.assertEqual(odds, [ brdicts[0], brdicts[2] ])
545
 
 
546
 
        # check evens
547
 
        evens = yield self.bldr._mergeRequests(brdicts[1],
548
 
                                brdicts, mergeRequests_fn)
549
 
        self.assertEqual(evens, [ brdicts[1] ])
550
 
 
551
 
        # check original relative order of requests within brdicts is maintained
552
 
        merged = yield self.bldr._mergeRequests(brdicts[2],
553
 
                                                brdicts, mergeRequests_fn)
554
 
        self.assertEqual(merged, [brdicts[0], brdicts[2]],
555
 
                         'relative order of merged requests was not maintained')
556
 
 
557
 
    @defer.inlineCallbacks
558
 
    def test_mergeRequest_no_other_request(self):
559
 
        """ Test if builder test for codebases in requests """
560
 
        yield self.makeBuilder()
561
 
 
562
 
        # set up all of the data required for a BuildRequest object
563
 
        yield self.db.insertTestData([
564
 
                fakedb.SourceStampSet(id=234),
565
 
                fakedb.SourceStamp(id=234, sourcestampsetid=234, codebase='A'),
566
 
                fakedb.Change(changeid=14, codebase='A'),
567
 
                fakedb.SourceStampChange(sourcestampid=234, changeid=14),
568
 
                fakedb.Buildset(id=30, sourcestampsetid=234, reason='foo',
569
 
                    submitted_at=1300305712, results=-1),
570
 
                fakedb.BuildRequest(id=19, buildsetid=30, buildername='bldr',
571
 
                    priority=13, submitted_at=1300305712, results=-1),
572
 
            ])
573
 
 
574
 
        brdicts = yield defer.gatherResults([
575
 
                self.db.buildrequests.getBuildRequest(19)
576
 
            ])
577
 
 
578
 
        def mergeRequests_fn(builder, breq, other):
579
 
            # Allow all requests
580
 
            return True
581
 
 
582
 
        # check if the request remains the same
583
 
        res = yield self.bldr._mergeRequests(brdicts[0], brdicts,
584
 
                                            mergeRequests_fn)
585
 
        self.assertEqual(res, [ brdicts[0] ])
586
 
 
587
 
    @defer.inlineCallbacks
588
 
    def test_mergeRequests_codebases_equal(self):
589
 
        """ Test if builder test for codebases in requests """
590
 
        yield self.makeBuilder()
591
 
 
592
 
        # set up all of the data required for a BuildRequest object
593
 
        yield self.db.insertTestData([
594
 
                fakedb.SourceStampSet(id=234),
595
 
                fakedb.SourceStamp(id=234, sourcestampsetid=234, codebase='A'),
596
 
                fakedb.Buildset(id=30, sourcestampsetid=234, reason='foo',
597
 
                    submitted_at=1300305712, results=-1),
598
 
                fakedb.SourceStampSet(id=235),
599
 
                fakedb.SourceStamp(id=235, sourcestampsetid=235, codebase='A'),
600
 
                fakedb.Buildset(id=31, sourcestampsetid=235, reason='foo',
601
 
                    submitted_at=1300305712, results=-1),
602
 
                fakedb.SourceStampSet(id=236),
603
 
                fakedb.SourceStamp(id=236, sourcestampsetid=236, codebase='A'),
604
 
                fakedb.Buildset(id=32, sourcestampsetid=236, reason='foo',
605
 
                    submitted_at=1300305712, results=-1),
606
 
                fakedb.BuildRequest(id=19, buildsetid=30, buildername='bldr',
607
 
                    priority=13, submitted_at=1300305712, results=-1),
608
 
                fakedb.BuildRequest(id=20, buildsetid=31, buildername='bldr',
609
 
                    priority=13, submitted_at=1300305712, results=-1),
610
 
                fakedb.BuildRequest(id=21, buildsetid=32, buildername='bldr',
611
 
                    priority=13, submitted_at=1300305712, results=-1),
612
 
            ])
613
 
 
614
 
        brdicts = yield defer.gatherResults([
615
 
                self.db.buildrequests.getBuildRequest(id)
616
 
                for id in (19, 20, 21)
617
 
            ])
618
 
 
619
 
        def mergeRequests_fn(builder, breq, other):
620
 
            # Allow all requests to test builder functionality
621
 
            return True
622
 
 
623
 
        # check if all are merged
624
 
        res = yield self.bldr._mergeRequests(brdicts[0], brdicts,
625
 
                                             mergeRequests_fn)
626
 
        self.assertEqual(res, [ brdicts[0], brdicts[1], brdicts[2] ])
627
 
 
628
 
    @defer.inlineCallbacks
629
 
    def test_mergeRequests_no_merging(self):
630
 
        yield self.makeBuilder()
631
 
 
632
 
        breq = dict(dummy=1)
633
 
        merged = yield self.bldr._mergeRequests(breq, [ breq, breq ], None)
634
 
 
635
 
        self.assertEqual(merged, [breq])
636
 
 
637
 
    @defer.inlineCallbacks
638
 
    def test_mergeRequests_singleton_list(self):
639
 
        yield self.makeBuilder()
640
 
 
641
 
        breq = dict(dummy=1)
642
 
        def is_not_called(*args):
643
 
            self.fail("should not be called")
644
 
        self.bldr._brdictToBuildRequest = is_not_called
645
 
 
646
 
        merged = yield self.bldr._mergeRequests(breq, [ breq ],
647
 
                                        lambda x,y : None)
648
 
 
649
 
        self.assertEqual(merged, [breq])
650
186
 
651
187
    # other methods
652
188
 
685
221
 
686
222
        self.assertEqual(claims, [ (set([10,11,12,15]),) ])
687
223
 
688
 
class TestGetOldestRequestTime(unittest.TestCase):
 
224
    @defer.inlineCallbacks
 
225
    def test_canStartBuild(self):
 
226
        yield self.makeBuilder()
 
227
 
 
228
        # by default, it returns True
 
229
        startable = yield self.bldr.canStartBuild('slave', 100)
 
230
        self.assertEqual(startable, True)
 
231
 
 
232
        startable = yield self.bldr.canStartBuild('slave', 101)
 
233
        self.assertEqual(startable, True)
 
234
 
 
235
        # set a configurable one
 
236
        record = []
 
237
        def canStartBuild(bldr, slave, breq):
 
238
            record.append((bldr, slave, breq))
 
239
            return (slave,breq)==('slave',100)
 
240
        self.bldr.config.canStartBuild = canStartBuild
 
241
 
 
242
        startable = yield self.bldr.canStartBuild('slave', 100)
 
243
        self.assertEqual(startable, True)
 
244
        self.assertEqual(record, [(self.bldr, 'slave', 100)])
 
245
 
 
246
        startable = yield self.bldr.canStartBuild('slave', 101)
 
247
        self.assertEqual(startable, False)
 
248
        self.assertEqual(record, [(self.bldr, 'slave', 100), (self.bldr, 'slave', 101)])
 
249
 
 
250
        # set a configurable one to return Deferred
 
251
        record = []
 
252
        def canStartBuild_deferred(bldr, slave, breq):
 
253
            record.append((bldr, slave, breq))
 
254
            return (slave,breq)==('slave',100)
 
255
            return defer.succeed((slave,breq)==('slave',100))
 
256
        self.bldr.config.canStartBuild = canStartBuild_deferred
 
257
 
 
258
        startable = yield self.bldr.canStartBuild('slave', 100)
 
259
        self.assertEqual(startable, True)
 
260
        self.assertEqual(record, [(self.bldr, 'slave', 100)])
 
261
 
 
262
        startable = yield self.bldr.canStartBuild('slave', 101)
 
263
        self.assertEqual(startable, False)
 
264
        self.assertEqual(record, [(self.bldr, 'slave', 100), (self.bldr, 'slave', 101)])
 
265
 
 
266
    @defer.inlineCallbacks
 
267
    def test_enforceChosenSlave(self):
 
268
        """enforceChosenSlave rejects and accepts builds"""
 
269
        yield self.makeBuilder()
 
270
 
 
271
        self.bldr.config.canStartBuild = builder.enforceChosenSlave
 
272
 
 
273
        slave = mock.Mock()
 
274
        slave.slave.slavename = 'slave5'
 
275
 
 
276
        breq = mock.Mock()
 
277
 
 
278
        # no buildslave requested
 
279
        breq.properties = {}
 
280
        result = yield self.bldr.canStartBuild(slave, breq)
 
281
        self.assertIdentical(True, result)
 
282
 
 
283
        # buildslave requested as the right one
 
284
        breq.properties = { 'slavename': 'slave5' }
 
285
        result = yield self.bldr.canStartBuild(slave, breq)
 
286
        self.assertIdentical(True, result)
 
287
 
 
288
        # buildslave requested as the wrong one
 
289
        breq.properties = { 'slavename': 'slave4' }
 
290
        result = yield self.bldr.canStartBuild(slave, breq)
 
291
        self.assertIdentical(False, result)
 
292
 
 
293
        # buildslave set to non string value gets skipped
 
294
        breq.properties = { 'slavename': 0 }
 
295
        result = yield self.bldr.canStartBuild(slave, breq)
 
296
        self.assertIdentical(True, result)
 
297
 
 
298
 
 
299
 
 
300
 
 
301
class TestGetOldestRequestTime(BuilderMixin, unittest.TestCase):
689
302
 
690
303
    def setUp(self):
691
304
        # a collection of rows that would otherwise clutter up every test
708
321
                        claimed_at=2501),
709
322
        ]
710
323
 
711
 
    def makeBuilder(self, name):
712
 
        self.bstatus = mock.Mock()
713
 
        self.factory = factory.BuildFactory()
714
 
        self.master = fakemaster.make_master()
715
 
        self.master.status = master.Status(self.master)
716
 
        # only include the necessary required config
717
 
        builder_config = config.BuilderConfig(
718
 
                        name=name, slavename="slv", builddir="bdir",
719
 
                        slavebuilddir="sbdir", factory=self.factory)
720
 
        self.bldr = builder.Builder(builder_config.name, _addServices=False)
721
 
        self.master.db = self.db = fakedb.FakeDBConnector(self)
722
 
        self.bldr.master = self.master
723
 
 
724
 
        self.bldr.startService()
725
 
 
726
 
        mastercfg = config.MasterConfig()
727
 
        mastercfg.builders = [ builder_config ]
728
 
        return self.bldr.reconfigService(mastercfg)
729
 
 
730
324
    def test_gort_unclaimed(self):
731
325
        d = self.makeBuilder(name='bldr1')
732
326
        d.addCallback(lambda _ : self.db.insertTestData(self.base_rows))
745
339
        d.addCallback(check)
746
340
        return d
747
341
 
748
 
class TestRebuild(unittest.TestCase):
 
342
class TestRebuild(BuilderMixin, unittest.TestCase):
749
343
 
750
344
    def makeBuilder(self, name, sourcestamps):
751
 
        self.bstatus = mock.Mock()
752
 
        bstatus_properties = mock.Mock()
753
 
        bstatus_properties.properties = {}
754
 
        self.bstatus.getProperties.return_value = bstatus_properties
755
 
        self.bstatus.getSourceStamps.return_value = sourcestamps
756
 
        self.factory = factory.BuildFactory()
757
 
        self.master = fakemaster.make_master()
758
 
        # only include the necessary required config
759
 
        builder_config = config.BuilderConfig(
760
 
                        name=name, slavename="slv", builddir="bdir",
761
 
                        slavebuilddir="sbdir", factory=self.factory)
762
 
        self.bldr = builder.Builder(builder_config.name)
763
 
        self.master.db = self.db = fakedb.FakeDBConnector(self)
764
 
        self.bldr.master = self.master
765
 
        self.master.addBuildset = addBuildset = mock.Mock()
766
 
        addBuildset.return_value = (1, [100])
 
345
        d = BuilderMixin.makeBuilder(self, name=name)
 
346
        @d.addCallback
 
347
        def setupBstatus(_):
 
348
            self.bstatus = mock.Mock()
 
349
            bstatus_properties = mock.Mock()
 
350
            bstatus_properties.properties = {}
 
351
            self.bstatus.getProperties.return_value = bstatus_properties
 
352
            self.bstatus.getSourceStamps.return_value = sourcestamps
 
353
            self.master.addBuildset = addBuildset = mock.Mock()
 
354
            addBuildset.return_value = (1, [100])
 
355
        return d
767
356
 
 
357
    @defer.inlineCallbacks
768
358
    def do_test_rebuild(self,
769
359
                        sourcestampsetid,
770
360
                        nr_of_sourcestamps):
786
376
            ssx.getSourceStampSetId = getSourceStampSetId
787
377
            sslist.append(ssx)
788
378
 
789
 
        self.makeBuilder(name='bldr1', sourcestamps = sslist)
 
379
        yield self.makeBuilder(name='bldr1', sourcestamps = sslist)
790
380
        control = mock.Mock(spec=['master'])
791
381
        control.master = self.master
792
382
        self.bldrctrl = builder.BuilderControl(self.bldr, control)
793
383
 
794
 
        d = self.bldrctrl.rebuildBuild(self.bstatus, reason = 'unit test', extraProperties = {})
795
 
 
796
 
        return d
 
384
        yield self.bldrctrl.rebuildBuild(self.bstatus, reason = 'unit test', extraProperties = {})
797
385
 
798
386
    @defer.inlineCallbacks
799
387
    def test_rebuild_with_no_sourcestamps(self):
820
408
                                                          properties = {})
821
409
 
822
410
 
 
411
class TestReconfig(BuilderMixin, unittest.TestCase):
 
412
    """Tests that a reconfig properly updates all attributes"""
 
413
 
 
414
    @defer.inlineCallbacks
 
415
    def test_reconfig(self):
 
416
        yield self.makeBuilder(description="Old", category="OldCat")
 
417
        self.builder_config.description = "New"
 
418
        self.builder_config.category = "NewCat"
 
419
 
 
420
        mastercfg = config.MasterConfig()
 
421
        mastercfg.builders = [ self.builder_config ]
 
422
        yield self.bldr.reconfigService(mastercfg)
 
423
        self.assertEqual(
 
424
                dict(description=self.bldr.builder_status.getDescription(),
 
425
                    category=self.bldr.builder_status.getCategory()),
 
426
                dict(description="New",
 
427
                    category="NewCat"))