def test_blamelist_for_patch(self): r = FakeRequest() r.sources.extend([self.patchSource]) build = Build([r]) blamelist = build.blamelist() # If no patch is set, author will not be est self.assertEqual(blamelist, [])
def setupPropsIfNeeded(props): if props is not None: return props = Properties() Build.setupPropertiesKnownBeforeBuildStarts(props, [buildrequest], self, workerforbuilder) return props
def testStopBuildWaitingForLocks(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) b.builder.botmaster = FakeMaster() slavebuilder = Mock() status = Mock() l = SlaveLock('lock') lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) b.setLocks([l]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS step.alwaysRun = False b.setStepFactories([(step, {})]) real_lock.claim(Mock(), l.access('counting')) def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.stopBuild('stop it') return retval b.acquireLocks = acquireLocks b.startBuild(status, None, slavebuilder) self.assert_( ('startStep', (b.remote,), {}) not in step.method_calls) self.assert_(b.currentStep is None) self.assertEqual(b.result, EXCEPTION) self.assert_( ('interrupt', ('stop it',), {}) not in step.method_calls)
def canStartBuild(self, workerforbuilder, buildrequest): can_start = True # check whether the locks that the build will acquire can actually be # acquired locks = self.config.locks if IRenderable.providedBy(locks): # collect properties that would be set for a build if we # started it now and render locks using it props = Properties() Build.setupPropertiesKnownBeforeBuildStarts(props, [buildrequest], self, workerforbuilder) locks = yield props.render(locks) locks = [(self.botmaster.getLockFromLockAccess(access), access) for access in locks] if locks: can_start = Build._canAcquireLocks(locks, workerforbuilder) if can_start is False: defer.returnValue(can_start) if callable(self.config.canStartBuild): can_start = yield self.config.canStartBuild(self, workerforbuilder, buildrequest) defer.returnValue(can_start)
def canStartWithWorkerForBuilder(self, workerforbuilder, buildrequests=None): locks = self.config.locks if IRenderable.providedBy(locks): if buildrequests is None: raise RuntimeError("buildrequests parameter must be specified " " when using renderable builder locks. Not " "specifying buildrequests is deprecated") # collect properties that would be set for a build if we # started it now and render locks using it props = Properties() Build.setupPropertiesKnownBeforeBuildStarts(props, buildrequests, self, workerforbuilder) locks = yield props.render(locks) # Make sure we don't warn and throw an exception at the same time if buildrequests is None: warnings.warn( "Not passing corresponding buildrequests to " "Builder.canStartWithWorkerForBuilder is deprecated") locks = [(self.botmaster.getLockFromLockAccess(access), access) for access in locks] can_start = Build.canStartWithWorkerForBuilder(locks, workerforbuilder) defer.returnValue(can_start)
def testBuildLocksAcquired(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) b.builder.botmaster = FakeMaster() slavebuilder = Mock() status = Mock() l = SlaveLock("lock") claimCount = [0] lock_access = l.access("counting") l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim b.setLocks([l]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([(step, {})]) b.startBuild(status, None, slavebuilder) self.assertEqual(b.result, SUCCESS) self.assert_(("startStep", (b.remote,), {}) in step.method_calls) self.assertEquals(claimCount[0], 1)
def testBuildWaitingForLocks(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) b.builder.botmaster = FakeMaster() slavebuilder = Mock() status = Mock() l = SlaveLock('lock') claimCount = [0] lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim b.setLocks([l]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([(step, {})]) real_lock.claim(Mock(), l.access('counting')) b.startBuild(status, None, slavebuilder) self.assert_( ('startStep', (b.remote,), {}) not in step.method_calls) self.assertEquals(claimCount[0], 1) self.assert_(b.currentStep is None) self.assert_(b._acquiringLock is not None)
def _startBuildFor(self, workerforbuilder, buildrequests): build = self.config.factory.newBuild(buildrequests) build.setBuilder(self) props = build.getProperties() # give the properties a reference back to this build props.build = build Build.setupPropertiesKnownBeforeBuildStarts( props, build.requests, build.builder, workerforbuilder) log.msg("starting build %s using worker %s" % (build, workerforbuilder)) # set up locks locks = yield build.render(self.config.locks) yield build.setLocks(locks) if self.config.env: build.setWorkerEnvironment(self.config.env) # append the build to self.building self.building.append(build) # The worker is ready to go. workerforbuilder.buildStarted() sets its # state to BUILDING (so we won't try to use it for any other builds). # This gets set back to IDLE by the Build itself when it finishes. # Note: This can't be done in `Build.startBuild`, since it needs to be done # synchronously, before the BuildRequestDistributor looks at # another build request. workerforbuilder.buildStarted() # create the BuildStatus object that goes with the Build bs = self.builder_status.newBuild() # let status know self.master.status.build_started(buildrequests[0].id, self.name, bs) # start the build. This will first set up the steps, then tell the # BuildStatus that it has started, which will announce it to the world # (through our BuilderStatus object, which is its parent). Finally it # will start the actual build process. This is done with a fresh # Deferred since _startBuildFor should not wait until the build is # finished. This uses `maybeDeferred` to ensure that any exceptions # raised by startBuild are treated as deferred errbacks (see # http://trac.buildbot.net/ticket/2428). d = defer.maybeDeferred(build.startBuild, bs, workerforbuilder) # this shouldn't happen. if it does, the worker will be wedged d.addErrback(log.err, 'from a running build; this is a ' 'serious error - please file a bug at http://buildbot.net') defer.returnValue(True)
def test_getWorkerName_old_api(self): class FakeProperties(Mock): implements(interfaces.IProperties) import posixpath r = FakeRequest() build = Build([r]) build.properties = FakeProperties() build.builder = FakeBuilder(self.master) build.build_status = FakeBuildStatus() w = worker.FakeWorker(self.master) w.path_module = posixpath w.properties = FakeProperties() w.workername = 'worker name' w.worker_basedir = None workerforbuilder = Mock(name='workerforbuilder') workerforbuilder.worker = w build.setupWorkerForBuilder(workerforbuilder) with assertNotProducesWarnings(DeprecatedWorkerAPIWarning): new = build.getWorkerName() with assertProducesWarning( DeprecatedWorkerNameWarning, message_pattern="'getSlaveName' method is deprecated"): old = build.getSlaveName() self.assertEqual(old, 'worker name') self.assertIdentical(new, old)
def setUp(self): @implementer(interfaces.IProperties) class FakeProperties(Mock): pass FakeProperties.render = Mock(side_effect=lambda x: x) class FakeBuildStatus(Mock): pass r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.master = fakemaster.make_master(wantData=True, testcase=self) self.worker = worker.FakeWorker(self.master) self.worker.attached(None) self.workerforbuilder = Mock(name='workerforbuilder') self.workerforbuilder.worker = self.worker self.build = Build([r]) self.build.setStepFactories([]) self.builder = FakeBuilder( fakemaster.make_master(wantData=True, testcase=self)) self.build.setBuilder(self.builder) self.properties = self.build.properties = FakeProperties() self.build_status = FakeBuildStatus() self.build._flushProperties = Mock() self.build.startBuild(self.build_status, self.workerforbuilder)
def setUp(self): r = FakeRequest() self.build = Build([r]) self.build.setStepFactories([]) self.builder = Mock() self.build.setBuilder(self.builder) self.build_status = FakeBuildStatus() self.build.startBuild(self.build_status, None, Mock())
def testStepDoneRetryOverridesAnythingElse(self): r = FakeRequest() b = Build([r]) b.results = [RETRY] b.result = RETRY b.remote = Mock() step = FakeBuildStep() step.alwaysRun = True b.stepDone(WARNINGS, step) b.stepDone(FAILURE, step) b.stepDone(SUCCESS, step) terminate = b.stepDone(EXCEPTION, step) self.assertEqual(terminate, True) self.assertEqual(b.result, RETRY)
def testStopBuild(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) step = Mock() step.return_value = step b.setStepFactories([(step, {})]) slavebuilder = Mock() status = Mock() def startStep(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.Deferred() step.startStep = startStep b.startBuild(status, None, slavebuilder) self.assertEqual(b.result, EXCEPTION) self.assert_(("interrupt", ("stop it",), {}) in step.method_calls)
class TestMultipleSourceStamps(unittest.TestCase): def setUp(self): r = FakeRequest() s1 = FakeSource() s1.repository = "repoA" s1.codebase = "A" s1.changes = [FakeChange(10), FakeChange(11)] s1.revision = "12345" s2 = FakeSource() s2.repository = "repoB" s2.codebase = "B" s2.changes = [FakeChange(12), FakeChange(13)] s2.revision = "67890" s3 = FakeSource() s3.repository = "repoC" # no codebase defined s3.changes = [FakeChange(14), FakeChange(15)] s3.revision = "111213" r.sources.extend([s1, s2, s3]) self.build = Build([r]) def test_buildReturnSourceStamp(self): """ Test that a build returns the correct sourcestamp """ source1 = self.build.getSourceStamp("A") source2 = self.build.getSourceStamp("B") self.assertEqual( [source1.repository, source1.revision], ["repoA", "12345"]) self.assertEqual( [source2.repository, source2.revision], ["repoB", "67890"]) def test_buildReturnSourceStamp_empty_codebase(self): """ Test that a build returns the correct sourcestamp if codebase is empty """ codebase = '' source3 = self.build.getSourceStamp(codebase) self.assertTrue(source3 is not None) self.assertEqual( [source3.repository, source3.revision], ["repoC", "111213"])
def testBuildLocksOrder(self): """Test that locks are acquired in FIFO order; specifically that counting locks cannot jump ahead of exclusive locks""" eBuild = self.build cBuilder = FakeBuilder(self.master) cBuild = Build([self.request]) cBuild.setBuilder(cBuilder) eWorker = Mock() cWorker = Mock() eWorker.worker = self.worker cWorker.worker = self.worker eWorker.prepare = cWorker.prepare = lambda _: True eWorker.ping = cWorker.ping = lambda: True l = WorkerLock("lock", 2) claimLog = [] realLock = self.master.botmaster.getLockByID(l).getLock(self.worker) def claim(owner, access): claimLog.append(owner) return realLock.oldClaim(owner, access) realLock.oldClaim = realLock.claim realLock.claim = claim eBuild.setLocks([l.access("exclusive")]) cBuild.setLocks([l.access("counting")]) fakeBuild = Mock() fakeBuildAccess = l.access("counting") realLock.claim(fakeBuild, fakeBuildAccess) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS eBuild.setStepFactories([FakeStepFactory(step)]) cBuild.setStepFactories([FakeStepFactory(step)]) e = eBuild.startBuild(FakeBuildStatus(), eWorker) c = cBuild.startBuild(FakeBuildStatus(), cWorker) d = defer.DeferredList([e, c]) realLock.release(fakeBuild, fakeBuildAccess) def check(ign): self.assertEqual(eBuild.results, SUCCESS) self.assertEqual(cBuild.results, SUCCESS) self.assertEqual(claimLog, [fakeBuild, eBuild, cBuild]) d.addCallback(check) return d
def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.build = Build([r]) self.builder = Mock() self.builder.botmaster = FakeMaster() self.build.setBuilder(self.builder)
def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.build = Build([r]) self.build.setStepFactories([]) self.builder = Mock() self.build.setBuilder(self.builder) self.build_status = FakeBuildStatus() self.build.startBuild(self.build_status, None, Mock())
def testBuildLocksOrder(self): """Test that locks are acquired in FIFO order; specifically that counting locks cannot jump ahead of exclusive locks""" eBuild = self.build cBuilder = self.createBuilder() cBuild = Build([self.request]) cBuild.setBuilder(cBuilder) eSlavebuilder = Mock() cSlavebuilder = Mock() slave = eSlavebuilder.slave cSlavebuilder.slave = slave l = SlaveLock('lock', 2) claimLog = [] realLock = self.master.botmaster.getLockByID(l).getLock(slave) def claim(owner, access): claimLog.append(owner) return realLock.oldClaim(owner, access) realLock.oldClaim = realLock.claim realLock.claim = claim eBuild.setLocks([l.access('exclusive')]) cBuild.setLocks([l.access('counting')]) fakeBuild = Mock() fakeBuildAccess = l.access('counting') realLock.claim(fakeBuild, fakeBuildAccess) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS eBuild.setStepFactories([FakeStepFactory(step)]) cBuild.setStepFactories([FakeStepFactory(step)]) e = eBuild.startBuild(FakeBuildStatus(), None, eSlavebuilder) c = cBuild.startBuild(FakeBuildStatus(), None, cSlavebuilder) d = defer.DeferredList([e, c]) realLock.release(fakeBuild, fakeBuildAccess) def check(ign): self.assertEqual(eBuild.result, SUCCESS) self.assertEqual(cBuild.result, SUCCESS) self.assertEquals(claimLog, [fakeBuild, eBuild, cBuild]) d.addCallback(check) return d
def test_workername_old_api(self): @implementer(interfaces.IProperties) class FakeProperties(Mock): pass import posixpath r = FakeRequest() build = Build([r]) build.properties = FakeProperties() build.builder = FakeBuilder(self.master) build.build_status = FakeBuildStatus() w = worker.FakeWorker(self.master) w.path_module = posixpath w.properties = FakeProperties() w.workername = "worker name" w.worker_basedir = None workerforbuilder = Mock(name="workerforbuilder") workerforbuilder.worker = w build.setupWorkerForBuilder(workerforbuilder) with assertNotProducesWarnings(DeprecatedWorkerAPIWarning): new = build.workername with assertProducesWarning(DeprecatedWorkerNameWarning, message_pattern="'slavename' attribute is deprecated"): old = build.slavename self.assertEqual(old, "worker name") self.assertIdentical(new, old)
def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.request = r self.master = FakeMaster() self.master.botmaster = FakeBotMaster(master=self.master) self.builder = self.createBuilder() self.build = Build([r]) self.build.setBuilder(self.builder)
def setUp(self): self.setUpTestReactor() self.props = {} r = FakeRequest() r.sources = [] r.sources.append(FakeSource()) r.sources[0].changes = [FakeChange()] r.sources[0].repository = "http://svn-repo-A" r.sources[0].codebase = "A" r.sources[0].branch = "develop" r.sources[0].revision = "12345" r.sources.append(FakeSource()) r.sources[1].changes = [FakeChange()] r.sources[1].repository = "http://svn-repo-B" r.sources[1].codebase = "B" r.sources[1].revision = "34567" self.build = Build([r]) self.build.setStepFactories([]) self.builder = FakeBuilder(fakemaster.make_master(self, wantData=True)) self.build.setBuilder(self.builder) self.build.build_status = FakeBuildStatus() # record properties that will be set self.build.properties.setProperty = self.setProperty
def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.request = r self.master = fakemaster.make_master(wantData=True, testcase=self) self.worker = worker.FakeWorker(self.master) self.worker.attached(None) self.builder = FakeBuilder(self.master) self.build = Build([r]) self.build.conn = fakeprotocol.FakeConnection(self.master, self.worker) self.workerforbuilder = Mock(name='workerforbuilder') self.workerforbuilder.worker = self.worker self.workerforbuilder.prepare = lambda _: True self.workerforbuilder.ping = lambda: True self.build.setBuilder(self.builder) self.build.text = [] self.build.buildid = 666
def setUp(self): self.setUpTestReactor() r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.request = r self.master = fakemaster.make_master(self, wantData=True) self.worker = worker.FakeWorker(self.master) self.worker.attached(None) self.builder = FakeBuilder(self.master) self.build = Build([r]) self.build.conn = fakeprotocol.FakeConnection(self.worker) self.workerforbuilder = Mock(name='workerforbuilder') self.workerforbuilder.worker = self.worker self.workerforbuilder.substantiate_if_needed = lambda _: True self.workerforbuilder.ping = lambda: True self.build.setBuilder(self.builder) self.build.text = [] self.build.buildid = 666
def setUp(self): class FakeProperties(Mock): implements(interfaces.IProperties) class FakeBuildStatus(Mock): pass r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.master = fakemaster.make_master(wantData=True, testcase=self) self.slave = slave.FakeSlave(self.master) self.slave.attached(None) self.slavebuilder = Mock(name='slavebuilder') self.slavebuilder.slave = self.slave self.build = Build([r]) self.build.setStepFactories([]) self.builder = FakeBuilder( fakemaster.make_master(wantData=True, testcase=self)) self.build.setBuilder(self.builder) self.properties = self.build.properties = FakeProperties() self.build_status = FakeBuildStatus() self.build._flushProperties = Mock() self.build.startBuild(self.build_status, None, self.slavebuilder)
def testStepDoneFailOverridesWarnings(self): r = FakeRequest() b = Build([r]) b.results = [SUCCESS, WARNINGS] b.result = WARNINGS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE)
def testStepDoneWarnings(self): r = FakeRequest() b = Build([r]) b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, WARNINGS)
def testStepDoneFail(self): r = FakeRequest() b = Build([r]) b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE)
def testStepDoneWarningsDontOverrideFailure(self): r = FakeRequest() b = Build([r]) b.results = [FAILURE] b.result = FAILURE b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE)
def testRunSuccessfulBuild(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([(step, {})]) slavebuilder = Mock() status = Mock() b.startBuild(status, None, slavebuilder) self.assertEqual(b.result, SUCCESS) self.assert_( ('startStep', (b.remote,), {}) in step.method_calls)
def testStepDoneHaltOnFailure(self): r = FakeRequest() b = Build([r]) b.results = [] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.haltOnFailure = True terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, True) self.assertEqual(b.result, FAILURE)
def setUp(self): self.props = {} r = FakeRequest() r.sources = [] r.sources.append(FakeSource()) r.sources[0].changes = [FakeChange()] r.sources[0].repository = "http://svn-repo-A" r.sources[0].codebase = "A" r.sources[0].branch = "develop" r.sources[0].revision = "12345" self.build = Build([r]) self.build.setStepFactories([]) self.builder = Mock() self.build.setBuilder(self.builder) self.build.build_status = FakeBuildStatus() # record properties that will be set self.build.build_status.setProperty = self.setProperty
def testStepDoneHaltOnFailureFlunkOnWarnings(self): r = FakeRequest() b = Build([r]) b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.flunkOnWarnings = True self.haltOnFailure = True terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE)
def testStepDoneWarnOnFailure(self): r = FakeRequest() b = Build([r]) b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.warnOnFailure = True step.flunkOnFailure = False terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, WARNINGS)
def canStartBuild(self, workerforbuilder, buildrequest): can_start = True # check whether the locks that the build will acquire can actually be # acquired locks = self.config.locks worker = workerforbuilder.worker props = None # don't unnecessarily setup properties for build def setupPropsIfNeeded(props): if props is not None: return props props = Properties() Build.setupPropertiesKnownBeforeBuildStarts( props, [buildrequest], self, workerforbuilder) return props if worker.builds_may_be_incompatible: # Check if the latent worker is actually compatible with the build. # The instance type of the worker may depend on the properties of # the build that substantiated it. props = setupPropsIfNeeded(props) can_start = yield worker.isCompatibleWithBuild(props) if not can_start: return False if IRenderable.providedBy(locks): # collect properties that would be set for a build if we # started it now and render locks using it props = setupPropsIfNeeded(props) locks = yield props.render(locks) locks = yield self.botmaster.getLockFromLockAccesses( locks, self.config_version) if locks: can_start = Build._canAcquireLocks(locks, workerforbuilder) if can_start is False: return can_start if callable(self.config.canStartBuild): can_start = yield self.config.canStartBuild( self, workerforbuilder, buildrequest) return can_start
def canStartBuild(self, workerforbuilder, buildrequest): can_start = True # check whether the locks that the build will acquire can actually be # acquired locks = self.config.locks worker = workerforbuilder.worker props = None # don't unnecessarily setup properties for build def setupPropsIfNeeded(props): if props is not None: return props = Properties() Build.setupPropertiesKnownBeforeBuildStarts(props, [buildrequest], self, workerforbuilder) return props if worker.builds_may_be_incompatible: # Check if the latent worker is actually compatible with the build. # The instance type of the worker may depend on the properties of # the build that substantiated it. props = setupPropsIfNeeded(props) can_start = yield worker.isCompatibleWithBuild(props) if not can_start: return False if IRenderable.providedBy(locks): # collect properties that would be set for a build if we # started it now and render locks using it props = setupPropsIfNeeded(props) locks = yield props.render(locks) locks = [(self.botmaster.getLockFromLockAccess(access), access) for access in locks] if locks: can_start = Build._canAcquireLocks(locks, workerforbuilder) if can_start is False: return can_start if callable(self.config.canStartBuild): can_start = yield self.config.canStartBuild(self, workerforbuilder, buildrequest) return can_start
def testAlwaysRunStepStopBuild(self): """Test that steps marked with alwaysRun=True still get run even if the build is stopped.""" # Create a build with 2 steps, the first one will get interrupted, and # the second one is marked with alwaysRun=True r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) step1 = Mock() step1.return_value = step1 step1.alwaysRun = False step2 = Mock() step2.return_value = step2 step2.alwaysRun = True b.setStepFactories([ (step1, {}), (step2, {}), ]) slavebuilder = Mock() status = Mock() def startStep1(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.succeed( SUCCESS ) step1.startStep = startStep1 step1.stepDone.return_value = False step2Started = [False] def startStep2(*args, **kw): step2Started[0] = True return defer.succeed( SUCCESS ) step2.startStep = startStep2 step1.stepDone.return_value = False d = b.startBuild(status, None, slavebuilder) def check(ign): self.assertEqual(b.result, EXCEPTION) self.assert_( ('interrupt', ('stop it',), {}) in step1.method_calls) self.assert_(step2Started[0]) d.addCallback(check) return d
def setUp(self): class FakeBuildStatus(Mock): implements(interfaces.IProperties) r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.master = fakemaster.make_master(wantData=True, testcase=self) self.slave = slave.FakeSlave(self.master) self.slave.attached(None) self.slavebuilder = Mock(name="slavebuilder") self.slavebuilder.slave = self.slave self.build = Build([r]) self.build.setStepFactories([]) self.builder = FakeBuilder(fakemaster.make_master(wantData=True, testcase=self)) self.build.setBuilder(self.builder) self.build_status = FakeBuildStatus() self.build.startBuild(self.build_status, None, self.slavebuilder)
def testStopBuildWaitingForStepLocks(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) b.builder.botmaster = FakeMaster() slavebuilder = Mock() status = Mock() l = SlaveLock('lock') lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) step = LoggingBuildStep(locks=[lock_access]) def factory(*args): return step b.setStepFactories([(factory, {})]) real_lock.claim(Mock(), l.access('counting')) gotLocks = [False] def acquireLocks(res=None): gotLocks[0] = True retval = LoggingBuildStep.acquireLocks(step, res) self.assert_(b.currentStep is step) b.stopBuild('stop it') return retval step.acquireLocks = acquireLocks step.setStepStatus = Mock() step.step_status = Mock() step.step_status.addLog().chunkSize = 10 step.step_status.getLogs.return_value = [] b.startBuild(status, None, slavebuilder) self.assertEqual(gotLocks, [True]) self.assert_(('stepStarted', (), {}) in step.step_status.method_calls) self.assertEqual(b.result, EXCEPTION)
def testStopBuild(self): r = FakeRequest() b = Build([r]) b.setBuilder(Mock()) step = Mock() step.return_value = step b.setStepFactories([(step, {})]) slavebuilder = Mock() status = Mock() def startStep(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.Deferred() step.startStep = startStep b.startBuild(status, None, slavebuilder) self.assertEqual(b.result, EXCEPTION) self.assert_( ('interrupt', ('stop it',), {}) in step.method_calls)
class TestSetupProperties_MultipleSources(unittest.TestCase): """ Test that the property values, based on the available requests, are initialized properly """ def setUp(self): self.props = {} r = FakeRequest() r.sources = [] r.sources.append(FakeSource()) r.sources[0].changes = [FakeChange()] r.sources[0].repository = "http://svn-repo-A" r.sources[0].codebase = "A" r.sources[0].branch = "develop" r.sources[0].revision = "12345" r.sources.append(FakeSource()) r.sources[1].changes = [FakeChange()] r.sources[1].repository = "http://svn-repo-B" r.sources[1].codebase = "B" r.sources[1].revision = "34567" self.build = Build([r]) self.build.setStepFactories([]) self.builder = FakeBuilder( fakemaster.make_master(wantData=True, testcase=self)) self.build.setBuilder(self.builder) self.build.build_status = FakeBuildStatus() # record properties that will be set self.build.properties.setProperty = self.setProperty def setProperty(self, n, v, s, runtime=False): if s not in self.props: self.props[s] = {} if not self.props[s]: self.props[s] = {} self.props[s][n] = v def test_sourcestamp_properties_not_set(self): self.build.setupProperties() self.assertTrue("codebase" not in self.props["Build"]) self.assertTrue("revision" not in self.props["Build"]) self.assertTrue("branch" not in self.props["Build"]) self.assertTrue("project" not in self.props["Build"]) self.assertTrue("repository" not in self.props["Build"])
def test_properties_revision(self): Build.setupBuildProperties(self.build.getProperties(), [self.r], self.r.sources) revision = self.props["Build"]["revision"] self.assertEqual(revision, "12345")
def test_properties_branch(self): Build.setupBuildProperties(self.build.getProperties(), [self.r], self.r.sources) branch = self.props["Build"]["branch"] self.assertEqual(branch, "develop")
def test_property_project(self): Build.setupBuildProperties(self.build.getProperties(), [self.r], self.r.sources) project = self.props["Build"]["project"] self.assertEqual(project, '')
def testBuildcanStartWithSlavebuilder(self): b = self.build slavebuilder1 = Mock() slavebuilder2 = Mock() l = SlaveLock('lock') counting_access = l.access('counting') real_lock = b.builder.botmaster.getLockByID(l) # no locks, so both these pass (call twice to verify there's no state/memory) lock_list = [(real_lock, counting_access)] self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_1 = real_lock.getLock(slavebuilder1.slave) slave_lock_2 = real_lock.getLock(slavebuilder2.slave) # then have slavebuilder2 claim its lock: slave_lock_2.claim(slavebuilder2, counting_access) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_2.release(slavebuilder2, counting_access) # then have slavebuilder1 claim its lock: slave_lock_1.claim(slavebuilder1, counting_access) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_1.release(slavebuilder1, counting_access)
def testBuild_canAcquireLocks(self): b = self.build workerforbuilder1 = Mock() workerforbuilder2 = Mock() lock = WorkerLock('lock') counting_access = lock.access('counting') real_lock = yield b.builder.botmaster.getLockByID(lock, 0) # no locks, so both these pass (call twice to verify there's no # state/memory) lock_list = [(real_lock, counting_access)] self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_1 = real_lock.getLockForWorker( workerforbuilder1.worker.workername) worker_lock_2 = real_lock.getLockForWorker( workerforbuilder2.worker.workername) # then have workerforbuilder2 claim its lock: worker_lock_2.claim(workerforbuilder2, counting_access) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_2.release(workerforbuilder2, counting_access) # then have workerforbuilder1 claim its lock: worker_lock_1.claim(workerforbuilder1, counting_access) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_1.release(workerforbuilder1, counting_access)
class TestBuildProperties(unittest.TestCase): """ Test that a Build has the necessary L{IProperties} methods, and that they properly delegate to the C{build_status} attribute - so really just a test of the L{IProperties} adapter. """ def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.build = Build([r]) self.build.setStepFactories([]) self.builder = Mock() self.build.setBuilder(self.builder) self.build_status = FakeBuildStatus() self.build.startBuild(self.build_status, None, Mock()) def test_getProperty(self): self.build.getProperty('x') self.build_status.getProperty.assert_called_with('x', None) def test_getProperty_default(self): self.build.getProperty('x', 'nox') self.build_status.getProperty.assert_called_with('x', 'nox') def test_setProperty(self): self.build.setProperty('n', 'v', 's') self.build_status.setProperty.assert_called_with('n', 'v', 's', runtime=True) def test_hasProperty(self): self.build_status.hasProperty.return_value = True self.assertTrue(self.build.hasProperty('p')) self.build_status.hasProperty.assert_called_with('p') def test_has_key(self): self.build_status.has_key.return_value = True # getattr because pep8 doesn't like calls to has_key self.assertTrue(getattr(self.build, 'has_key')('p')) # has_key calls through to hasProperty self.build_status.hasProperty.assert_called_with('p') def test_render(self): self.build.render("xyz") self.build_status.render.assert_called_with("xyz")
class TestSetupProperties_SingleSource(unittest.TestCase): """ Test that the property values, based on the available requests, are initialized properly """ def setUp(self): self.props = {} r = FakeRequest() r.sources = [] r.sources.append(FakeSource()) r.sources[0].changes = [FakeChange()] r.sources[0].repository = "http://svn-repo-A" r.sources[0].codebase = "A" r.sources[0].branch = "develop" r.sources[0].revision = "12345" self.build = Build([r]) self.build.setStepFactories([]) self.builder = Mock() self.build.setBuilder(self.builder) self.build.build_status = FakeBuildStatus() # record properties that will be set self.build.build_status.setProperty = self.setProperty def setProperty(self, n, v, s, runtime=False): if s not in self.props: self.props[s] = {} if not self.props[s]: self.props[s] = {} self.props[s][n] = v def test_properties_codebase(self): self.build.setupProperties() codebase = self.props["Build"]["codebase"] self.assertEqual(codebase, "A") def test_properties_repository(self): self.build.setupProperties() repository = self.props["Build"]["repository"] self.assertEqual(repository, "http://svn-repo-A") def test_properties_revision(self): self.build.setupProperties() revision = self.props["Build"]["revision"] self.assertEqual(revision, "12345") def test_properties_branch(self): self.build.setupProperties() branch = self.props["Build"]["branch"] self.assertEqual(branch, "develop") def test_property_project(self): self.build.setupProperties() project = self.props["Build"]["project"] self.assertEqual(project, '')
def test_blamelist_for_patch(self): r = FakeRequest() r.sources.extend([self.patchSource]) build = Build([r]) blamelist = build.blamelist() self.assertEqual(blamelist, ['jeff'])
def test_blamelist_for_changes(self): r = FakeRequest() r.sources.extend([self.sourceByMe, self.sourceByHim]) build = Build([r]) blamelist = build.blamelist() self.assertEqual(blamelist, ['him', 'me'])
def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.stopBuild('stop it') return retval
class TestBuild(TestReactorMixin, unittest.TestCase): def setUp(self): self.setUpTestReactor() r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.request = r self.master = fakemaster.make_master(self, wantData=True) self.worker = worker.FakeWorker(self.master) self.worker.attached(None) self.builder = FakeBuilder(self.master) self.build = Build([r]) self.build.conn = fakeprotocol.FakeConnection(self.master, self.worker) self.workerforbuilder = Mock(name='workerforbuilder') self.workerforbuilder.worker = self.worker self.workerforbuilder.substantiate_if_needed = lambda _: True self.workerforbuilder.ping = lambda: True self.build.setBuilder(self.builder) self.build.text = [] self.build.buildid = 666 def assertWorkerPreparationFailure(self, reason): states = "".join(self.master.data.updates.stepStateString.values()) self.assertIn(states, reason) def testRunSuccessfulBuild(self): b = self.build step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) def testStopBuild(self): b = self.build step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) def startStep(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.Deferred() step.startStep = startStep b.startBuild(self.workerforbuilder) self.assertEqual(b.results, CANCELLED) self.assertIn('stop it', step.interrupted) def test_build_retry_when_worker_substantiate_returns_false(self): b = self.build step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) self.workerforbuilder.substantiate_if_needed = lambda _: False b.startBuild(self.workerforbuilder) self.assertEqual(b.results, RETRY) self.assertWorkerPreparationFailure('error while worker_prepare') def test_build_cancelled_when_worker_substantiate_returns_false_due_to_cancel(self): b = self.build step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) d = defer.Deferred() self.workerforbuilder.substantiate_if_needed = lambda _: d b.startBuild(self.workerforbuilder) b.stopBuild('Cancel Build', CANCELLED) d.callback(False) self.assertEqual(b.results, CANCELLED) self.assertWorkerPreparationFailure('error while worker_prepare') def test_build_retry_when_worker_substantiate_returns_false_due_to_cancel(self): b = self.build step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) d = defer.Deferred() self.workerforbuilder.substantiate_if_needed = lambda _: d b.startBuild(self.workerforbuilder) b.stopBuild('Cancel Build', RETRY) d.callback(False) self.assertEqual(b.results, RETRY) self.assertWorkerPreparationFailure('error while worker_prepare') @defer.inlineCallbacks def testAlwaysRunStepStopBuild(self): """Test that steps marked with alwaysRun=True still get run even if the build is stopped.""" # Create a build with 2 steps, the first one will get interrupted, and # the second one is marked with alwaysRun=True b = self.build step1 = FakeBuildStep() step1.alwaysRun = False step1.results = None step2 = FakeBuildStep() step2.alwaysRun = True step2.results = None b.setStepFactories([ FakeStepFactory(step1), FakeStepFactory(step2), ]) def startStep1(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.succeed(SUCCESS) step1.startStep = startStep1 step1.stepDone = lambda: False step2Started = [False] def startStep2(*args, **kw): step2Started[0] = True return defer.succeed(SUCCESS) step2.startStep = startStep2 step1.stepDone = lambda: False yield b.startBuild(self.workerforbuilder) self.assertEqual(b.results, CANCELLED) self.assertIn('stop it', step1.interrupted) self.assertTrue(step2Started[0]) @defer.inlineCallbacks def test_start_step_throws_exception(self): b = self.build step1 = FakeBuildStep() b.setStepFactories([ FakeStepFactory(step1), ]) def startStep(*args, **kw): raise TestException() step1.startStep = startStep yield b.startBuild(self.workerforbuilder) self.assertEqual(b.results, EXCEPTION) self.flushLoggedErrors(TestException) @defer.inlineCallbacks def testBuild_canAcquireLocks(self): b = self.build workerforbuilder1 = Mock() workerforbuilder2 = Mock() lock = WorkerLock('lock') counting_access = lock.access('counting') real_lock = yield b.builder.botmaster.getLockByID(lock, 0) # no locks, so both these pass (call twice to verify there's no # state/memory) lock_list = [(real_lock, counting_access)] self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_1 = real_lock.getLockForWorker( workerforbuilder1.worker.workername) worker_lock_2 = real_lock.getLockForWorker( workerforbuilder2.worker.workername) # then have workerforbuilder2 claim its lock: worker_lock_2.claim(workerforbuilder2, counting_access) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_2.release(workerforbuilder2, counting_access) # then have workerforbuilder1 claim its lock: worker_lock_1.claim(workerforbuilder1, counting_access) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertFalse( Build._canAcquireLocks(lock_list, workerforbuilder1)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) self.assertTrue( Build._canAcquireLocks(lock_list, workerforbuilder2)) worker_lock_1.release(workerforbuilder1, counting_access) def testBuilddirPropType(self): b = self.build b.builder.config.workerbuilddir = 'test' self.workerforbuilder.worker.worker_basedir = "/srv/buildbot/worker" self.workerforbuilder.worker.path_module = posixpath b.getProperties = Mock() b.setProperty = Mock() b.setupWorkerBuildirProperty(self.workerforbuilder) expected_path = '/srv/buildbot/worker/test' b.setProperty.assert_has_calls( [call('builddir', expected_path, 'Worker')], any_order=True) @defer.inlineCallbacks def testBuildLocksAcquired(self): b = self.build lock = WorkerLock('lock') claimCount = [0] lock_access = lock.access('counting') lock.access = lambda mode: lock_access real_workerlock = yield b.builder.botmaster.getLockByID(lock, 0) real_lock = real_workerlock.getLockForWorker(self.workerforbuilder.worker.workername) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim yield b.setLocks([lock_access]) step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) self.assertEqual(claimCount[0], 1) @defer.inlineCallbacks def testBuildLocksOrder(self): """Test that locks are acquired in FIFO order; specifically that counting locks cannot jump ahead of exclusive locks""" eBuild = self.build cBuilder = FakeBuilder(self.master) cBuild = Build([self.request]) cBuild.setBuilder(cBuilder) eWorker = Mock() cWorker = Mock() eWorker.worker = self.worker cWorker.worker = self.worker eWorker.substantiate_if_needed = cWorker.substantiate_if_needed = lambda _: True eWorker.ping = cWorker.ping = lambda: True lock = WorkerLock('lock', 2) claimLog = [] real_workerlock = yield self.master.botmaster.getLockByID(lock, 0) realLock = real_workerlock.getLockForWorker(self.worker.workername) def claim(owner, access): claimLog.append(owner) return realLock.oldClaim(owner, access) realLock.oldClaim = realLock.claim realLock.claim = claim yield eBuild.setLocks([lock.access('exclusive')]) yield cBuild.setLocks([lock.access('counting')]) fakeBuild = Mock() fakeBuildAccess = lock.access('counting') realLock.claim(fakeBuild, fakeBuildAccess) step = FakeBuildStep() eBuild.setStepFactories([FakeStepFactory(step)]) cBuild.setStepFactories([FakeStepFactory(step)]) e = eBuild.startBuild(eWorker) c = cBuild.startBuild(cWorker) d = defer.DeferredList([e, c]) realLock.release(fakeBuild, fakeBuildAccess) yield d self.assertEqual(eBuild.results, SUCCESS) self.assertEqual(cBuild.results, SUCCESS) self.assertEqual(claimLog, [fakeBuild, eBuild, cBuild]) @defer.inlineCallbacks def testBuildWaitingForLocks(self): b = self.build lock = WorkerLock('lock') claimCount = [0] lock_access = lock.access('counting') lock.access = lambda mode: lock_access real_workerlock = yield b.builder.botmaster.getLockByID(lock, 0) real_lock = real_workerlock.getLockForWorker(self.workerforbuilder.worker.workername) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim yield b.setLocks([lock_access]) step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), lock.access('counting')) b.startBuild(self.workerforbuilder) self.assertEqual(claimCount[0], 1) self.assertTrue(b.currentStep is None) self.assertTrue(b._acquiringLock is not None) @defer.inlineCallbacks def testStopBuildWaitingForLocks(self): b = self.build lock = WorkerLock('lock') lock_access = lock.access('counting') lock.access = lambda mode: lock_access real_workerlock = yield b.builder.botmaster.getLockByID(lock, 0) real_lock = real_workerlock.getLockForWorker(self.workerforbuilder.worker.workername) yield b.setLocks([lock_access]) step = FakeBuildStep() step.alwaysRun = False b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), lock.access('counting')) def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.stopBuild('stop it') return retval b.acquireLocks = acquireLocks b.startBuild(self.workerforbuilder) self.assertTrue(b.currentStep is None) self.assertEqual(b.results, CANCELLED) @defer.inlineCallbacks def testStopBuildWaitingForLocks_lostRemote(self): b = self.build lock = WorkerLock('lock') lock_access = lock.access('counting') lock.access = lambda mode: lock_access real_workerlock = yield b.builder.botmaster.getLockByID(lock, 0) real_lock = real_workerlock.getLockForWorker(self.workerforbuilder.worker.workername) yield b.setLocks([lock_access]) step = FakeBuildStep() step.alwaysRun = False b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), lock.access('counting')) def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.lostRemote() return retval b.acquireLocks = acquireLocks b.startBuild(self.workerforbuilder) self.assertTrue(b.currentStep is None) self.assertEqual(b.results, RETRY) @defer.inlineCallbacks def testStopBuildWaitingForStepLocks(self): b = self.build lock = WorkerLock('lock') lock_access = lock.access('counting') lock.access = lambda mode: lock_access real_workerlock = yield b.builder.botmaster.getLockByID(lock, 0) real_lock = real_workerlock.getLockForWorker(self.workerforbuilder.worker.workername) step = BuildStep(locks=[lock_access]) b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), lock.access('counting')) gotLocks = [False] def acquireLocks(res=None): gotLocks[0] = True retval = BuildStep.acquireLocks(step, res) self.assertTrue(b.currentStep is step) b.stopBuild('stop it') return retval step.acquireLocks = acquireLocks b.startBuild(self.workerforbuilder) self.assertEqual(gotLocks, [True]) self.assertEqual(b.results, CANCELLED) def testStepDone(self): b = self.build b.results = SUCCESS step = FakeBuildStep() terminate = b.stepDone(SUCCESS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, SUCCESS) def testStepDoneHaltOnFailure(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.haltOnFailure = True terminate = b.stepDone(FAILURE, step) self.assertTrue(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneHaltOnFailureNoFlunkOnFailure(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.flunkOnFailure = False step.haltOnFailure = True terminate = b.stepDone(FAILURE, step) self.assertTrue(terminate.result) self.assertEqual(b.results, SUCCESS) def testStepDoneFlunkOnWarningsFlunkOnFailure(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.flunkOnFailure = True step.flunkOnWarnings = True b.stepDone(WARNINGS, step) terminate = b.stepDone(FAILURE, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneNoWarnOnWarnings(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.warnOnWarnings = False terminate = b.stepDone(WARNINGS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, SUCCESS) def testStepDoneWarnings(self): b = self.build b.results = SUCCESS step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, WARNINGS) def testStepDoneFail(self): b = self.build b.results = SUCCESS step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneFailOverridesWarnings(self): b = self.build b.results = WARNINGS step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneWarnOnFailure(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.warnOnFailure = True step.flunkOnFailure = False terminate = b.stepDone(FAILURE, step) self.assertFalse(terminate.result) self.assertEqual(b.results, WARNINGS) def testStepDoneFlunkOnWarnings(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.flunkOnWarnings = True terminate = b.stepDone(WARNINGS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneHaltOnFailureFlunkOnWarnings(self): b = self.build b.results = SUCCESS step = FakeBuildStep() step.flunkOnWarnings = True self.haltOnFailure = True terminate = b.stepDone(WARNINGS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneWarningsDontOverrideFailure(self): b = self.build b.results = FAILURE step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertFalse(terminate.result) self.assertEqual(b.results, FAILURE) def testStepDoneRetryOverridesAnythingElse(self): b = self.build b.results = RETRY step = FakeBuildStep() step.alwaysRun = True b.stepDone(WARNINGS, step) b.stepDone(FAILURE, step) b.stepDone(SUCCESS, step) terminate = b.stepDone(EXCEPTION, step) self.assertTrue(terminate.result) self.assertEqual(b.results, RETRY) def test_getSummaryStatistic(self): b = self.build b.executedSteps = [ BuildStep(), BuildStep(), BuildStep() ] b.executedSteps[0].setStatistic('casualties', 7) b.executedSteps[2].setStatistic('casualties', 4) add = operator.add self.assertEqual(b.getSummaryStatistic('casualties', add), 11) self.assertEqual(b.getSummaryStatistic('casualties', add, 10), 21) def create_fake_steps(self, names): steps = [] def create_fake_step(name): step = FakeBuildStep() step.name = name return step for name in names: step = create_fake_step(name) steps.append(step) return steps @defer.inlineCallbacks def test_start_build_sets_properties(self): b = self.build b.setProperty("foo", "bar", "test") step = FakeBuildStep() b.setStepFactories([FakeStepFactory(step)]) yield b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) # remove duplicates, note that set() can't be used as properties contain complex # data structures. Also, remove builddir which depends on the platform got_properties = [] for prop in sorted(self.master.data.updates.properties): if prop not in got_properties and prop[1] != 'builddir': got_properties.append(prop) self.assertEqual(got_properties, [ (10, 'branch', None, 'Build'), (10, 'buildnumber', 1, 'Build'), (10, 'codebase', '', 'Build'), (10, 'foo', 'bar', 'test'), # custom property (10, 'owners', ['me'], 'Build'), (10, 'project', '', 'Build'), (10, 'repository', '', 'Build'), (10, 'revision', '12345', 'Build') ]) @defer.inlineCallbacks def testAddStepsAfterCurrentStep(self): b = self.build steps = self.create_fake_steps(["a", "b", "c"]) def startStepB(*args, **kw): new_steps = self.create_fake_steps(["d", "e"]) b.addStepsAfterCurrentStep([FakeStepFactory(s) for s in new_steps]) return SUCCESS steps[1].startStep = startStepB b.setStepFactories([FakeStepFactory(s) for s in steps]) yield b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) expected_names = ["a", "b", "d", "e", "c"] executed_names = [s.name for s in b.executedSteps] self.assertEqual(executed_names, expected_names) @defer.inlineCallbacks def testAddStepsAfterLastStep(self): b = self.build steps = self.create_fake_steps(["a", "b", "c"]) def startStepB(*args, **kw): new_steps = self.create_fake_steps(["d", "e"]) b.addStepsAfterLastStep([FakeStepFactory(s) for s in new_steps]) return SUCCESS steps[1].startStep = startStepB b.setStepFactories([FakeStepFactory(s) for s in steps]) yield b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) expected_names = ["a", "b", "c", "d", "e"] executed_names = [s.name for s in b.executedSteps] self.assertEqual(executed_names, expected_names) def testStepNamesUnique(self): # if the step names are unique they should remain unchanged b = self.build steps = self.create_fake_steps(["clone", "command", "clean"]) b.setStepFactories([FakeStepFactory(s) for s in steps]) b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) expected_names = ["clone", "command", "clean"] executed_names = [s.name for s in b.executedSteps] self.assertEqual(executed_names, expected_names) def testStepNamesDuplicate(self): b = self.build steps = self.create_fake_steps(["stage", "stage", "stage"]) b.setStepFactories([FakeStepFactory(s) for s in steps]) b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) expected_names = ["stage", "stage_1", "stage_2"] executed_names = [s.name for s in b.executedSteps] self.assertEqual(executed_names, expected_names) def testStepNamesDuplicateAfterAdd(self): b = self.build steps = self.create_fake_steps(["a", "b", "c"]) def startStepB(*args, **kw): new_steps = self.create_fake_steps(["c", "c"]) b.addStepsAfterCurrentStep([FakeStepFactory(s) for s in new_steps]) return SUCCESS steps[1].startStep = startStepB b.setStepFactories([FakeStepFactory(s) for s in steps]) b.startBuild(self.workerforbuilder) self.assertEqual(b.results, SUCCESS) expected_names = ["a", "b", "c", "c_1", "c_2"] executed_names = [s.name for s in b.executedSteps] self.assertEqual(executed_names, expected_names) @defer.inlineCallbacks def testGetUrl(self): self.build.number = 3 url = yield self.build.getUrl() self.assertEqual(url, 'http://localhost:8080/#builders/83/builds/3') @defer.inlineCallbacks def testGetUrlForVirtualBuilder(self): # Let's fake a virtual builder self.builder._builders['wilma'] = 108 self.build.setProperty('virtual_builder_name', 'wilma', 'Build') self.build.setProperty('virtual_builder_tags', ['_virtual_']) self.build.number = 33 url = yield self.build.getUrl() self.assertEqual(url, 'http://localhost:8080/#builders/108/builds/33') def test_active_builds_metric(self): """ The number of active builds is increased when a build starts and decreased when it finishes. """ b = self.build controller, step_factory = makeControllableStepFactory() b.setStepFactories([step_factory]) observer = MetricLogObserver() observer.enable() self.addCleanup(observer.disable) def get_active_builds(): return observer.asDict()['counters'].get('active_builds', 0) self.assertEqual(get_active_builds(), 0) b.startBuild(self.workerforbuilder) self.assertEqual(get_active_builds(), 1) controller.finishStep(SUCCESS) self.assertEqual(get_active_builds(), 0) def test_active_builds_metric_failure(self): """ The number of active builds is increased when a build starts and decreased when it finishes.. """ b = self.build b.setStepFactories([FailingStepFactory()]) observer = MetricLogObserver() observer.enable() self.addCleanup(observer.disable) def get_active_builds(): return observer.asDict()['counters'].get('active_builds', 0) self.assertEqual(get_active_builds(), 0) b.startBuild(self.workerforbuilder) self.flushLoggedErrors(TestException) self.assertEqual(get_active_builds(), 0)
def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.lostRemote() return retval
class TestBuild(unittest.TestCase): def setUp(self): r = FakeRequest() r.sources = [FakeSource()] r.sources[0].changes = [FakeChange()] r.sources[0].revision = "12345" self.request = r self.master = FakeMaster() self.master.botmaster = FakeBotMaster(master=self.master) self.slave = slave.FakeSlave(self.master) self.builder = self.createBuilder() self.build = Build([r]) self.build.master = self.master self.build.setBuilder(self.builder) def createBuilder(self): bldr = Mock() bldr.botmaster = self.master.botmaster return bldr def testRunSuccessfulBuild(self): b = self.build step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([FakeStepFactory(step)]) slavebuilder = Mock() b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assertEqual(b.result, SUCCESS) self.assert_(('startStep', (slavebuilder.remote, ), {}) in step.method_calls) def testStopBuild(self): b = self.build step = Mock() step.return_value = step b.setStepFactories([FakeStepFactory(step)]) slavebuilder = Mock() def startStep(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.Deferred() step.startStep = startStep b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assertEqual(b.result, EXCEPTION) self.assert_(('interrupt', ('stop it', ), {}) in step.method_calls) def testAlwaysRunStepStopBuild(self): """Test that steps marked with alwaysRun=True still get run even if the build is stopped.""" # Create a build with 2 steps, the first one will get interrupted, and # the second one is marked with alwaysRun=True b = self.build step1 = Mock() step1.return_value = step1 step1.alwaysRun = False step2 = Mock() step2.return_value = step2 step2.alwaysRun = True b.setStepFactories([ FakeStepFactory(step1), FakeStepFactory(step2), ]) slavebuilder = Mock() def startStep1(*args, **kw): # Now interrupt the build b.stopBuild("stop it") return defer.succeed(SUCCESS) step1.startStep = startStep1 step1.stepDone.return_value = False step2Started = [False] def startStep2(*args, **kw): step2Started[0] = True return defer.succeed(SUCCESS) step2.startStep = startStep2 step1.stepDone.return_value = False d = b.startBuild(FakeBuildStatus(), None, slavebuilder) def check(ign): self.assertEqual(b.result, EXCEPTION) self.assert_(('interrupt', ('stop it', ), {}) in step1.method_calls) self.assert_(step2Started[0]) d.addCallback(check) return d def testBuildcanStartWithSlavebuilder(self): b = self.build slavebuilder1 = Mock() slavebuilder2 = Mock() l = SlaveLock('lock') counting_access = l.access('counting') real_lock = b.builder.botmaster.getLockByID(l) # no locks, so both these pass (call twice to verify there's no state/memory) lock_list = [(real_lock, counting_access)] self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_1 = real_lock.getLock(slavebuilder1.slave) slave_lock_2 = real_lock.getLock(slavebuilder2.slave) # then have slavebuilder2 claim its lock: slave_lock_2.claim(slavebuilder2, counting_access) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_2.release(slavebuilder2, counting_access) # then have slavebuilder1 claim its lock: slave_lock_1.claim(slavebuilder1, counting_access) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertFalse( Build.canStartWithSlavebuilder(lock_list, slavebuilder1)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) self.assertTrue( Build.canStartWithSlavebuilder(lock_list, slavebuilder2)) slave_lock_1.release(slavebuilder1, counting_access) def testBuilddirPropType(self): import posixpath b = self.build slavebuilder = Mock() b.build_status = Mock() b.builder.config.slavebuilddir = 'test' slavebuilder.slave.slave_basedir = "/srv/buildbot/slave" slavebuilder.slave.path_module = posixpath b.getProperties = Mock() b.setProperty = Mock() b.setupSlaveBuilder(slavebuilder) expected_path = '/srv/buildbot/slave/test' b.setProperty.assert_has_calls([ call('workdir', expected_path, 'slave (deprecated)'), call('builddir', expected_path, 'slave') ], any_order=True) def testBuildLocksAcquired(self): b = self.build slavebuilder = Mock() l = SlaveLock('lock') claimCount = [0] lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock( slavebuilder.slave) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim b.setLocks([lock_access]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([FakeStepFactory(step)]) b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assertEqual(b.result, SUCCESS) self.assert_(('startStep', (slavebuilder.remote, ), {}) in step.method_calls) self.assertEquals(claimCount[0], 1) def testBuildLocksOrder(self): """Test that locks are acquired in FIFO order; specifically that counting locks cannot jump ahead of exclusive locks""" eBuild = self.build cBuilder = self.createBuilder() cBuild = Build([self.request]) cBuild.setBuilder(cBuilder) eSlavebuilder = Mock() cSlavebuilder = Mock() slave = eSlavebuilder.slave cSlavebuilder.slave = slave l = SlaveLock('lock', 2) claimLog = [] realLock = self.master.botmaster.getLockByID(l).getLock(slave) def claim(owner, access): claimLog.append(owner) return realLock.oldClaim(owner, access) realLock.oldClaim = realLock.claim realLock.claim = claim eBuild.setLocks([l.access('exclusive')]) cBuild.setLocks([l.access('counting')]) fakeBuild = Mock() fakeBuildAccess = l.access('counting') realLock.claim(fakeBuild, fakeBuildAccess) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS eBuild.setStepFactories([FakeStepFactory(step)]) cBuild.setStepFactories([FakeStepFactory(step)]) e = eBuild.startBuild(FakeBuildStatus(), None, eSlavebuilder) c = cBuild.startBuild(FakeBuildStatus(), None, cSlavebuilder) d = defer.DeferredList([e, c]) realLock.release(fakeBuild, fakeBuildAccess) def check(ign): self.assertEqual(eBuild.result, SUCCESS) self.assertEqual(cBuild.result, SUCCESS) self.assertEquals(claimLog, [fakeBuild, eBuild, cBuild]) d.addCallback(check) return d def testBuildWaitingForLocks(self): b = self.build slavebuilder = Mock() l = SlaveLock('lock') claimCount = [0] lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock( slavebuilder.slave) def claim(owner, access): claimCount[0] += 1 return real_lock.old_claim(owner, access) real_lock.old_claim = real_lock.claim real_lock.claim = claim b.setLocks([lock_access]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), l.access('counting')) b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assert_(('startStep', (slavebuilder.remote, ), {}) not in step.method_calls) self.assertEquals(claimCount[0], 1) self.assert_(b.currentStep is None) self.assert_(b._acquiringLock is not None) def testStopBuildWaitingForLocks(self): b = self.build slavebuilder = Mock() l = SlaveLock('lock') lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) b.setLocks([lock_access]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS step.alwaysRun = False b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), l.access('counting')) def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.stopBuild('stop it') return retval b.acquireLocks = acquireLocks b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assert_(('startStep', (slavebuilder.remote, ), {}) not in step.method_calls) self.assert_(b.currentStep is None) self.assertEqual(b.result, EXCEPTION) self.assert_(('interrupt', ('stop it', ), {}) not in step.method_calls) def testStopBuildWaitingForLocks_lostRemote(self): b = self.build slavebuilder = Mock() l = SlaveLock('lock') lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) b.setLocks([lock_access]) step = Mock() step.return_value = step step.startStep.return_value = SUCCESS step.alwaysRun = False b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), l.access('counting')) def acquireLocks(res=None): retval = Build.acquireLocks(b, res) b.lostRemote() return retval b.acquireLocks = acquireLocks b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assert_(('startStep', (slavebuilder.remote, ), {}) not in step.method_calls) self.assert_(b.currentStep is None) self.assertEqual(b.result, RETRY) self.assert_(('interrupt', ('stop it', ), {}) not in step.method_calls) self.build.build_status.setText.assert_called_with( ["retry", "lost", "remote"]) self.build.build_status.setResults.assert_called_with(RETRY) def testStopBuildWaitingForStepLocks(self): b = self.build slavebuilder = Mock() l = SlaveLock('lock') lock_access = l.access('counting') l.access = lambda mode: lock_access real_lock = b.builder.botmaster.getLockByID(l).getLock(slavebuilder) step = LoggingBuildStep(locks=[lock_access]) b.setStepFactories([FakeStepFactory(step)]) real_lock.claim(Mock(), l.access('counting')) gotLocks = [False] def acquireLocks(res=None): gotLocks[0] = True retval = LoggingBuildStep.acquireLocks(step, res) self.assert_(b.currentStep is step) b.stopBuild('stop it') return retval step.acquireLocks = acquireLocks step.setStepStatus = Mock() step._step_status = Mock() step.step_status.addLog().chunkSize = 10 step.step_status.getLogs.return_value = [] b.startBuild(FakeBuildStatus(), None, slavebuilder) self.assertEqual(gotLocks, [True]) self.assert_(('stepStarted', (), {}) in step.step_status.method_calls) self.assertEqual(b.result, EXCEPTION) def testStepDone(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(SUCCESS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, SUCCESS) def testStepDoneHaltOnFailure(self): b = self.build b.results = [] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.haltOnFailure = True terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, True) self.assertEqual(b.result, FAILURE) def testStepDoneHaltOnFailureNoFlunkOnFailure(self): b = self.build b.results = [] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.flunkOnFailure = False step.haltOnFailure = True terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, True) self.assertEqual(b.result, SUCCESS) def testStepDoneFlunkOnWarningsFlunkOnFailure(self): b = self.build b.results = [] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.flunkOnFailure = True step.flunkOnWarnings = True b.stepDone(WARNINGS, step) terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneNoWarnOnWarnings(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.warnOnWarnings = False terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, SUCCESS) def testStepDoneWarnings(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, WARNINGS) def testStepDoneFail(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneFailOverridesWarnings(self): b = self.build b.results = [SUCCESS, WARNINGS] b.result = WARNINGS b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneWarnOnFailure(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.warnOnFailure = True step.flunkOnFailure = False terminate = b.stepDone(FAILURE, step) self.assertEqual(terminate, False) self.assertEqual(b.result, WARNINGS) def testStepDoneFlunkOnWarnings(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.flunkOnWarnings = True terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneHaltOnFailureFlunkOnWarnings(self): b = self.build b.results = [SUCCESS] b.result = SUCCESS b.remote = Mock() step = FakeBuildStep() step.flunkOnWarnings = True self.haltOnFailure = True terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneWarningsDontOverrideFailure(self): b = self.build b.results = [FAILURE] b.result = FAILURE b.remote = Mock() step = FakeBuildStep() terminate = b.stepDone(WARNINGS, step) self.assertEqual(terminate, False) self.assertEqual(b.result, FAILURE) def testStepDoneRetryOverridesAnythingElse(self): b = self.build b.results = [RETRY] b.result = RETRY b.remote = Mock() step = FakeBuildStep() step.alwaysRun = True b.stepDone(WARNINGS, step) b.stepDone(FAILURE, step) b.stepDone(SUCCESS, step) terminate = b.stepDone(EXCEPTION, step) self.assertEqual(terminate, True) self.assertEqual(b.result, RETRY)