def test_release_calls_multiple_waiters_on_setMaxCount( self, count, maxCount): req = Requester() req_waiters = [Requester() for _ in range(5)] lock = BaseLock('test', maxCount=maxCount) access_counting = mock.Mock(spec=LockAccess) access_counting.mode = 'counting' access_counting.count = count lock.claim(req, access_counting) deferreds = [ lock.waitUntilMaybeAvailable(req_waiter, access_counting) for req_waiter in req_waiters ] self.assertEqual([d.called for d in deferreds], [False] * 5) lock.release(req, access_counting) yield flushEventualQueue() self.assertEqual([d.called for d in deferreds], [True] + [False] * 4) lock.setMaxCount(5) yield flushEventualQueue() self.assertEqual([d.called for d in deferreds], [True] * 5)
def assert_two_steps_created_one_after_another(self, stepcontrollers, builder_ids): # start two builds and verify that a second build starts after the # first is finished yield self.create_build_request([builder_ids[0]]) yield self.create_build_request([builder_ids[1]]) builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], None) self.assertEqual(builds[0]['builderid'], builder_ids[0]) self.assertEqual(builds[1]['results'], None) self.assertEqual(builds[1]['builderid'], builder_ids[1]) self.assertTrue(stepcontrollers[0].running) self.assertFalse(stepcontrollers[1].running) stepcontrollers[0].finish_step(SUCCESS) yield flushEventualQueue() self.assertFalse(stepcontrollers[0].running) self.assertTrue(stepcontrollers[1].running) builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], None) stepcontrollers[1].finish_step(SUCCESS) yield flushEventualQueue() builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], SUCCESS)
def test_changing_max_lock_count_does_not_break_step_locks( self, builder_count, lock_cls, mode, max_count_before, max_count_after, allowed_steps_before, allowed_steps_after): # TODO: the test currently demonstrates broken behavior ''' Check that Buildbot does not allow extra claims on a claimed lock after a reconfig that changed the maxCount of that lock. Some Buildbot versions created a completely separate real lock after each maxCount change, which allowed to e.g. take an exclusive lock twice. ''' stepcontrollers, master, config_dict, lock, builder_ids = \ yield self.create_single_worker_n_builder_step_lock_config( builder_count, lock_cls, max_count_before, mode) # create a number of builds and check that the expected number of them # start their steps for i in range(builder_count): yield self.createBuildrequest(master, [builder_ids[i]]) builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), builder_count) self.assertEqual(sum(sc.running for sc in stepcontrollers), allowed_steps_before) # update the config and reconfig the master lock = lock_cls(lock.name, maxCount=max_count_after) new_stepcontrollers = \ self.create_stepcontrollers(builder_count, lock, mode) self.update_builder_config(config_dict, new_stepcontrollers, lock, mode) yield master.reconfig() yield flushEventualQueue() # check that all builds are still running builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), builder_count) # check that the expected number of steps has been started and that # none of the new steps has been started self.assertEqual(sum(sc.running for sc in stepcontrollers), allowed_steps_before) self.assertEqual(sum(sc.running for sc in new_stepcontrollers), 0) # finish the steps and check that builds finished as expected for stepcontroller in stepcontrollers: stepcontroller.finish_step(SUCCESS) yield flushEventualQueue() builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), builder_count) for b in builds: self.assertEqual(b['results'], SUCCESS) self.assertEqual(sum(sc.running for sc in stepcontrollers), 0) self.assertEqual(sum(sc.running for sc in new_stepcontrollers), 0)
def test_startService_setSlaveInfo_UpdatesDb(self): self.master.db.insertTestData([ fakedb.Buildslave(name='bot', info={ 'admin': 'TheAdmin', 'host': 'TheHost', 'access_uri': 'TheURI', 'version': 'TheVersion', 'key': 'value', }) ]) slave = self.createBuildslave() yield slave.startService() # change a value slave.slave_status.updateInfo(key='new-value') self.clock.pump([0]) # we overrode the reactor, so gotta force the calls yield eventual.flushEventualQueue() # and the db is updated too: slave_db = yield self.master.db.buildslaves.getBuildslaveByName("bot") self.assertEqual(slave_db['slaveinfo']['admin'], 'TheAdmin') self.assertEqual(slave_db['slaveinfo']['host'], 'TheHost') self.assertEqual(slave_db['slaveinfo']['access_uri'], 'TheURI') self.assertEqual(slave_db['slaveinfo']['version'], 'TheVersion') self.assertEqual(slave_db['slaveinfo']['key'], 'new-value')
def test_stop_waiting_removes_non_called_waiter(self, mode): req = Requester() req_waiter1 = Requester() req_waiter2 = Requester() lock = BaseLock('test', maxCount=1) access = mock.Mock(spec=LockAccess) access.mode = mode lock.claim(req, access) d1 = lock.waitUntilMaybeAvailable(req_waiter1, access) d2 = lock.waitUntilMaybeAvailable(req_waiter2, access) lock.release(req, access) yield flushEventualQueue() self.assertFalse(lock.isAvailable(req, access)) self.assertTrue(lock.isAvailable(req_waiter1, access)) self.assertFalse(lock.isAvailable(req_waiter2, access)) self.assertTrue(d1.called) lock.stopWaitingUntilAvailable(req_waiter2, access, d2) self.assertFalse(lock.isAvailable(req, access)) self.assertTrue(lock.isAvailable(req_waiter1, access)) self.assertFalse(lock.isAvailable(req_waiter2, access)) lock.claim(req_waiter1, access) lock.release(req_waiter1, access) self.assertTrue(lock.isAvailable(req, access)) self.assertTrue(lock.isAvailable(req_waiter1, access)) self.assertTrue(lock.isAvailable(req_waiter2, access))
def _check2(ign): self.failUnlessEqual(len(success_events), 1) self.failUnlessEqual(len(finished_events), 0) self.failUnlessEqual(success_events[0].isFinished(), False) self.failUnlessEqual(success_events[0].getResults(), None) db.retire_buildrequests([brids["bn2"]], SUCCESS) return flushEventualQueue()
def assert_two_builds_created_one_after_another(self, stepcontrollers, builder_ids): # start two builds and verify that a second build starts after the # first is finished yield self.create_build_request([builder_ids[0]]) yield self.create_build_request([builder_ids[1]]) builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 1) self.assertEqual(builds[0]['results'], None) self.assertEqual(builds[0]['builderid'], builder_ids[0]) stepcontrollers[0].finish_step(SUCCESS) # execute Build.releaseLocks which is called eventually yield flushEventualQueue() builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], None) self.assertEqual(builds[1]['builderid'], builder_ids[1]) stepcontrollers[1].finish_step(SUCCESS) builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], SUCCESS)
def test_startService_setSlaveInfo_UpdatesDb(self): self.master.db.insertTestData([ fakedb.Buildslave(name='bot', info={ 'admin': 'TheAdmin', 'host': 'TheHost', 'access_uri': 'TheURI', 'version': 'TheVersion', 'key': 'value', }) ]) slave = self.createBuildslave() yield slave.startService() # change a value slave.slave_status.updateInfo(key='new-value') self.clock.pump( [0]) # we overrode the reactor, so gotta force the calls yield eventual.flushEventualQueue() # and the db is updated too: slave_db = yield self.master.db.buildslaves.getBuildslaveByName("bot") self.assertEqual(slave_db['slaveinfo']['admin'], 'TheAdmin') self.assertEqual(slave_db['slaveinfo']['host'], 'TheHost') self.assertEqual(slave_db['slaveinfo']['access_uri'], 'TheURI') self.assertEqual(slave_db['slaveinfo']['version'], 'TheVersion') self.assertEqual(slave_db['slaveinfo']['key'], 'new-value')
def assertResults(self, exp): d = eventual.flushEventualQueue() def cb(_): self.assertEqual(self.results, exp) d.addCallback(cb) return d
def _check3(ign): self.failUnlessEqual(len(success_events), 1) self.failUnlessEqual(len(finished_events), 1) self.failUnlessIdentical(bss.__class__, success_events[0].__class__) self.failUnlessEqual(success_events[0].isFinished(), True) self.failUnlessEqual(success_events[0].getResults(), FAILURE) self.failUnlessEqual(finished_events[0].getResults(), FAILURE) return flushEventualQueue()
def test_release_calls_waiters_in_fifo_order(self, mode1, mode2, count1, count2, maxCount): req = Requester() req_waiters = [Requester() for _ in range(5)] lock = BaseLock('test', maxCount=maxCount) access1 = mock.Mock(spec=LockAccess) access1.mode = mode1 access1.count = count1 access2 = mock.Mock(spec=LockAccess) access2.mode = mode2 access2.count = count2 accesses = [access1, access2, access1, access2, access1] expected_called = [False] * 5 lock.claim(req, access1) deferreds = [ lock.waitUntilMaybeAvailable(req_waiter, access) for req_waiter, access in zip(req_waiters, accesses) ] self.assertEqual([d.called for d in deferreds], expected_called) lock.release(req, access1) yield flushEventualQueue() expected_called[0] = True self.assertEqual([d.called for d in deferreds], expected_called) for i in range(4): self.assertTrue(lock.isAvailable(req_waiters[i], accesses[i])) lock.claim(req_waiters[i], accesses[i]) self.assertEqual([d.called for d in deferreds], expected_called) lock.release(req_waiters[i], accesses[i]) yield flushEventualQueue() expected_called[i + 1] = True self.assertEqual([d.called for d in deferreds], expected_called) lock.claim(req_waiters[4], accesses[4]) lock.release(req_waiters[4], accesses[4])
def test_release_calls_waiters_in_fifo_order(self, mode1, mode2): req = Requester() req_waiters = [Requester() for _ in range(5)] lock = BaseLock('test', maxCount=1) access1 = mock.Mock(spec=LockAccess) access1.mode = mode1 access2 = mock.Mock(spec=LockAccess) access2.mode = mode2 accesses = [access1, access2, access1, access2, access1] expected_called = [False] * 5 lock.claim(req, access1) deferreds = [lock.waitUntilMaybeAvailable(req_waiter, access) for req_waiter, access in zip(req_waiters, accesses)] self.assertEqual([d.called for d in deferreds], expected_called) lock.release(req, access1) yield flushEventualQueue() expected_called[0] = True self.assertEqual([d.called for d in deferreds], expected_called) for i in range(4): self.assertTrue(lock.isAvailable(req_waiters[i], accesses[i])) lock.claim(req_waiters[i], accesses[i]) self.assertEqual([d.called for d in deferreds], expected_called) lock.release(req_waiters[i], accesses[i]) yield flushEventualQueue() expected_called[i + 1] = True self.assertEqual([d.called for d in deferreds], expected_called) lock.claim(req_waiters[4], accesses[4]) lock.release(req_waiters[4], accesses[4])
def test_changing_max_lock_count_does_not_break_builder_locks( self, builder_count, lock_cls, mode, max_count_before, max_count_after, allowed_builds_before, allowed_builds_after): ''' Check that Buildbot does not allow extra claims on a claimed lock after a reconfig that changed the maxCount of that lock. Some Buildbot versions created a completely separate real lock after each maxCount change, which allowed to e.g. take an exclusive lock twice. ''' stepcontrollers, config_dict, lock, builder_ids = \ yield self.create_single_worker_n_builder_lock_config( builder_count, lock_cls, max_count_before, mode) # create a number of builds and check that the expected number of them # start for i in range(builder_count): yield self.create_build_request([builder_ids[i]]) builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), allowed_builds_before) # update the config and reconfig the master lock = lock_cls(lock.name, maxCount=max_count_after) self.update_builder_config(config_dict, stepcontrollers, lock, mode) yield self.master.reconfig() yield flushEventualQueue() # check that the number of running builds matches expectation builds = yield self.master.data.get(("builds", )) self.assertEqual(len(builds), allowed_builds_after) # finish the steps and check that builds finished as expected for stepcontroller in stepcontrollers: stepcontroller.finish_step(SUCCESS) yield flushEventualQueue() builds = yield self.master.data.get(("builds", )) for b in builds[allowed_builds_after:]: self.assertEqual(b['results'], SUCCESS)
def test_stop_waiting_wakes_up_next_deferred_if_already_woken(self, mode): req = Requester() req_waiter1 = Requester() req_waiter2 = Requester() lock = BaseLock('test', maxCount=1) access = mock.Mock(spec=LockAccess) access.mode = mode lock.claim(req, access) d1 = lock.waitUntilMaybeAvailable(req_waiter1, access) d2 = lock.waitUntilMaybeAvailable(req_waiter2, access) lock.release(req, access) yield flushEventualQueue() self.assertTrue(d1.called) self.assertFalse(d2.called) lock.stopWaitingUntilAvailable(req_waiter1, access, d1) yield flushEventualQueue() self.assertTrue(d2.called)
def test_release_calls_multiple_waiters_on_setMaxCount(self): req = Requester() req_waiters = [Requester() for _ in range(5)] lock = BaseLock('test', maxCount=1) access_counting = mock.Mock(spec=LockAccess) access_counting.mode = 'counting' lock.claim(req, access_counting) deferreds = [lock.waitUntilMaybeAvailable(req_waiter, access_counting) for req_waiter in req_waiters] self.assertEqual([d.called for d in deferreds], [False] * 5) lock.release(req, access_counting) yield flushEventualQueue() self.assertEqual([d.called for d in deferreds], [True] + [False] * 4) lock.setMaxCount(5) yield flushEventualQueue() self.assertEqual([d.called for d in deferreds], [True] * 5)
def test_can_release_non_waited_lock(self, mode): req = Requester() req_not_waited = Requester() lock = BaseLock('test', maxCount=1) access = mock.Mock(spec=LockAccess) access.mode = mode lock.release(req_not_waited, access) lock.claim(req, access) lock.release(req, access) yield flushEventualQueue() lock.release(req_not_waited, access)
def wait_until_idle(self, ign=None): done_d = defer.Deferred() d = flushEventualQueue() def _check(ign): if (not self.master.db.has_pending_operations() and self.master.botmaster.loop.is_quiet() and self.master.scheduler_manager.is_quiet() ): done_d.callback(None) return d2 = defer.Deferred() d2.addCallback(flushEventualQueue) d2.addCallback(_check) reactor.callLater(0.01, d2.callback, None) d.addCallback(_check) return done_d
def test_addGracefulWatcher_noCallsWhenNotChanged(self): s = self.makeStatus() callbacks = [] def callback(graceful): callbacks.append(graceful) s.addGracefulWatcher(callback) d = eventual.flushEventualQueue() @d.addCallback def check(_): self.assertEqual(callbacks, []) return d
def test_stop_waiting_does_not_fire_deferred_if_already_woken(self, mode): req = Requester() req_waiter = Requester() lock = BaseLock('test', maxCount=1) access = mock.Mock(spec=LockAccess) access.mode = mode lock.claim(req, access) d = lock.waitUntilMaybeAvailable(req_waiter, access) lock.release(req, access) yield flushEventualQueue() self.assertTrue(d.called) # note that if the function calls the deferred again, an exception would be thrown from # inside Twisted. lock.stopWaitingUntilAvailable(req_waiter, access, d)
def test_sleep(self): reactor = self.loop._reactor = task.Clock() eventual._setReactor(reactor) state = State(count=5) def proc(): self.results.append(reactor.seconds()) state.count -= 1 if state.count: return defer.succeed(reactor.seconds() + 10.0) self.loop.add(proc) self.loop.trigger() def check(ign): reactor.pump((0,) + (1,)*50) # run for 50 fake seconds self.assertEqual(self.results, [ 0.0, 10.0, 20.0, 30.0, 40.0 ]) d = eventual.flushEventualQueue() d.addCallback(check) return d
def wait_until_idle(self, ign=None): done_d = defer.Deferred() d = flushEventualQueue() def _check(ign): if (not self.master.db.has_pending_operations() and self.master.botmaster.loop.is_quiet() and self.master.scheduler_manager.is_quiet()): done_d.callback(None) return d2 = defer.Deferred() d2.addCallback(flushEventualQueue) d2.addCallback(_check) reactor.callLater(0.01, d2.callback, None) d.addCallback(_check) return done_d
def test_addInfoWatcher_calledOnceForTwoKeys(self): s = self.makeStatus() callbacks = [] def callback(info): callbacks.append(info) s.addInfoWatcher(callback) s.updateInfo(key='value', key2='value2') d = eventual.flushEventualQueue() @d.addCallback def check(_): self.assertEqual(callbacks, [{'key': 'value', 'key2': 'value2'}]) return d
def test_addGracefulWatcher_called(self): s = self.makeStatus() callbacks = [] def callback(graceful): callbacks.append(graceful) s.addGracefulWatcher(callback) s.setGraceful(True) d = eventual.flushEventualQueue() @d.addCallback def check(_): self.assertEqual(callbacks, [True]) return d
def test_attached_slaveInfoUpdates(self): # put in stale info: self.master.db.insertTestData([ fakedb.Buildslave(name='bot', info={ 'admin': 'WrongAdmin', 'host': 'WrongHost', 'access_uri': 'WrongURI', 'version': 'WrongVersion', 'key': 'value', }) ]) slave = self.createBuildslave() yield slave.startService() bot = createRemoteBot() bot.response['getVersion'] = mock.Mock( return_value=defer.succeed("TheVersion")) bot.response['getSlaveInfo'] = mock.Mock( return_value=defer.succeed({ 'admin': 'TheAdmin', 'host': 'TheHost', 'access_uri': 'TheURI', })) yield slave.attached(bot) self.assertEqual(slave.slave_status.getAdmin(), 'TheAdmin') self.assertEqual(slave.slave_status.getHost(), 'TheHost') self.assertEqual(slave.slave_status.getAccessURI(), 'TheURI') self.assertEqual(slave.slave_status.getVersion(), 'TheVersion') self.assertEqual(slave.slave_status.getInfo('key'), 'value') self.clock.pump( [0]) # we overrode the reactor, so gotta force the calls yield eventual.flushEventualQueue() # and the db is updated too: buildslave = yield self.master.db.buildslaves.getBuildslaveByName( "bot") self.assertEqual(buildslave['slaveinfo']['admin'], 'TheAdmin') self.assertEqual(buildslave['slaveinfo']['host'], 'TheHost') self.assertEqual(buildslave['slaveinfo']['access_uri'], 'TheURI') self.assertEqual(buildslave['slaveinfo']['version'], 'TheVersion')
def test_removeInfoWatcher(self): s = self.makeStatus() callbacks = [] def callback(info): callbacks.append(info) s.addInfoWatcher(callback) s.removeInfoWatcher(callback) s.updateInfo(key='value') d = eventual.flushEventualQueue() @d.addCallback def check(_): # never called: self.assertEqual(callbacks, []) return d
def test_sleep(self): reactor = self.loop._reactor = task.Clock() eventual._setReactor(reactor) state = State(count=5) def proc(): self.results.append(reactor.seconds()) state.count -= 1 if state.count: return defer.succeed(reactor.seconds() + 10.0) self.loop.add(proc) self.loop.trigger() def check(ign): reactor.pump((0, ) + (1, ) * 50) # run for 50 fake seconds self.assertEqual(self.results, [0.0, 10.0, 20.0, 30.0, 40.0]) d = eventual.flushEventualQueue() d.addCallback(check) return d
def test_addInfoWatcher_noCallsWhenNotChanged(self): s = self.makeStatus() FIRST_VALUE = 123 s.updateInfo(key=FIRST_VALUE) callbacks = [] def callback(info): callbacks.append(info) s.addInfoWatcher(callback) # set the same value again s.updateInfo(key=FIRST_VALUE) d = eventual.flushEventualQueue() @d.addCallback def check(_): self.assertEqual(callbacks, []) return d
def test_attached_slaveInfoUpdates(self): # put in stale info: self.master.db.insertTestData([ fakedb.Buildslave(name='bot', info={ 'admin': 'WrongAdmin', 'host': 'WrongHost', 'access_uri': 'WrongURI', 'version': 'WrongVersion', 'key': 'value', }) ]) slave = self.createBuildslave() yield slave.startService() bot = createRemoteBot() bot.response['getVersion'] = mock.Mock( return_value=defer.succeed("TheVersion")) bot.response['getSlaveInfo'] = mock.Mock(return_value=defer.succeed({ 'admin': 'TheAdmin', 'host': 'TheHost', 'access_uri': 'TheURI', })) yield slave.attached(bot) self.assertEqual(slave.slave_status.getAdmin(), 'TheAdmin') self.assertEqual(slave.slave_status.getHost(), 'TheHost') self.assertEqual(slave.slave_status.getAccessURI(), 'TheURI') self.assertEqual(slave.slave_status.getVersion(), 'TheVersion') self.assertEqual(slave.slave_status.getInfo('key'), 'value') self.clock.pump([0]) # we overrode the reactor, so gotta force the calls yield eventual.flushEventualQueue() # and the db is updated too: buildslave = yield self.master.db.buildslaves.getBuildslaveByName("bot") self.assertEqual(buildslave['slaveinfo']['admin'], 'TheAdmin') self.assertEqual(buildslave['slaveinfo']['host'], 'TheHost') self.assertEqual(buildslave['slaveinfo']['access_uri'], 'TheURI') self.assertEqual(buildslave['slaveinfo']['version'], 'TheVersion')
def _check1(ign): self.failUnlessEqual(len(success_events), 0) self.failUnlessEqual(len(finished_events), 0) db.retire_buildrequests([brids["bn1"]], FAILURE) return flushEventualQueue()
def tearDown(self): log.err = self.old_log_err return eventual.flushEventualQueue()
def cb(): d = eventual.flushEventualQueue() d.addCallback(testd.callback)
def assertResults(self, exp): yield eventual.flushEventualQueue() self.assertEqual(self.results, exp)
def _then(ign): cm = m.change_svc c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") cm.addChange(c) return flushEventualQueue()
def tearDown(self): return eventual.flushEventualQueue()
def test_builder_lock_release_wakes_builds_for_another_builder(self): """ If a builder locks a master lock then the build request distributor must retry running any buildrequests that might have been not scheduled due to unavailability of that lock when the lock becomes available. """ stepcontroller1 = BuildStepController() stepcontroller2 = BuildStepController() master_lock = util.MasterLock("lock1", maxCount=1) config_dict = { 'builders': [ BuilderConfig(name='builder1', workernames=['worker1'], factory=BuildFactory([stepcontroller1.step]), locks=[master_lock.access('counting')]), BuilderConfig(name='builder2', workernames=['worker2'], factory=BuildFactory([stepcontroller2.step]), locks=[master_lock.access('counting')]), ], 'workers': [ self.createLocalWorker('worker1'), self.createLocalWorker('worker2'), ], 'protocols': { 'null': {} }, 'multiMaster': True, } master = yield self.getMaster(config_dict) builder1_id = yield master.data.updates.findBuilderId('builder1') builder2_id = yield master.data.updates.findBuilderId('builder2') # start two builds and verify that a second build starts after the # first is finished yield self.createBuildrequest(master, [builder1_id]) yield self.createBuildrequest(master, [builder2_id]) builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), 1) self.assertEqual(builds[0]['results'], None) self.assertEqual(builds[0]['builderid'], builder1_id) stepcontroller1.finish_step(SUCCESS) # execute Build.releaseLocks which is called eventually yield flushEventualQueue() builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], None) self.assertEqual(builds[1]['builderid'], builder2_id) stepcontroller2.finish_step(SUCCESS) builds = yield master.data.get(("builds", )) self.assertEqual(len(builds), 2) self.assertEqual(builds[0]['results'], SUCCESS) self.assertEqual(builds[1]['results'], SUCCESS)