def reconfigServiceBuilders(self, new_config): timer = metrics.Timer("BotMaster.reconfigServiceBuilders") timer.start() # arrange builders by name old_by_name = dict([(b.name, b) for b in list(self) if isinstance(b, Builder)]) old_set = set(old_by_name) new_by_name = dict([(bc.name, bc) for bc in new_config.builders]) new_set = set(new_by_name) # calculate new builders, by name, and removed builders removed_names, added_names = util.diffSets(old_set, new_set) if removed_names or added_names: log.msg("adding %d new builders, removing %d" % (len(added_names), len(removed_names))) for n in removed_names: builder = old_by_name[n] del self.builders[n] builder.master = None builder.botmaster = None # pylint: disable=cell-var-from-loop yield defer.maybeDeferred(lambda: builder.disownServiceParent()) for n in added_names: builder = Builder(n) self.builders[n] = builder builder.botmaster = self builder.master = self.master yield builder.setServiceParent(self) self.builderNames = list(self.builders) yield self.master.data.updates.updateBuilderList( self.master.masterid, [util.ascii2unicode(n) for n in self.builderNames]) metrics.MetricCountEvent.log("num_builders", len(self.builders), absolute=True) timer.stop()
def reconfigServiceBuilders(self, new_config): timer = metrics.Timer("BotMaster.reconfigServiceBuilders") timer.start() # arrange builders by name old_by_name = {b.name: b for b in list(self) if isinstance(b, Builder)} old_set = set(old_by_name) new_by_name = {bc.name: bc for bc in new_config.builders} new_set = set(new_by_name) # calculate new builders, by name, and removed builders removed_names, added_names = util.diffSets(old_set, new_set) if removed_names or added_names: log.msg("adding %d new builders, removing %d" % (len(added_names), len(removed_names))) for n in removed_names: builder = old_by_name[n] del self.builders[n] builder.master = None builder.botmaster = None # pylint: disable=cell-var-from-loop yield defer.maybeDeferred(lambda: builder.disownServiceParent()) for n in added_names: builder = Builder(n) self.builders[n] = builder builder.botmaster = self builder.master = self.master yield builder.setServiceParent(self) self.builderNames = list(self.builders) yield self.master.data.updates.updateBuilderList( self.master.masterid, [util.bytes2unicode(n) for n in self.builderNames]) metrics.MetricCountEvent.log("num_builders", len(self.builders), absolute=True) timer.stop()
def reconfigServiceBuilders(self, new_config): timer = metrics.Timer("BotMaster.reconfigServiceBuilders") timer.start() # arrange builders by name old_by_name = dict([ (b.name, b) for b in list(self) if isinstance(b, Builder) ]) old_set = set(old_by_name.iterkeys()) new_by_name = dict([ (bc.name, bc) for bc in new_config.builders ]) new_set = set(new_by_name.iterkeys()) # calculate new builders, by name, and removed builders removed_names, added_names = util.diffSets(old_set, new_set) if removed_names or added_names: log.msg("adding %d new builders, removing %d" % (len(added_names), len(removed_names))) for n in removed_names: builder = old_by_name[n] del self.builders[n] builder.master = None builder.botmaster = None wfd = defer.waitForDeferred( defer.maybeDeferred(lambda : builder.disownServiceParent())) yield wfd wfd.getResult() for n in added_names: builder = Builder(n) self.builders[n] = builder builder.botmaster = self builder.master = self.master builder.setServiceParent(self) self.builderNames = self.builders.keys() metrics.MetricCountEvent.log("num_builders", len(self.builders), absolute=True) timer.stop()
def collapse_fn(master, builder, brdict1, brdict2): if not claimed: yield self.master.data.updates.claimBuildRequests([20]) claimed.append(20) res = yield Builder._defaultCollapseRequestFn( master, builder, brdict1, brdict2) return res
def makeBuildStep(basedir, step_class=BuildStep, **kwargs): bss = setupBuildStepStatus(basedir) ss = SourceStamp() setup = {"name": "builder1", "slavename": "bot1", "builddir": "builddir", "factory": None} b0 = Builder(setup, bss.getBuild().getBuilder()) b0.botmaster = FakeBotMaster() br = BuildRequest("reason", ss, "test_builder") b = Build([br]) b.setBuilder(b0) s = step_class(**kwargs) s.setBuild(b) s.setStepStatus(bss) b.build_status = bss.getBuild() b.setupProperties() s.slaveVersion = fake_slaveVersion return s
def makeBuildStep(basedir, step_class=BuildStep, **kwargs): bss = setupBuildStepStatus(basedir) ss = SourceStamp() setup = {'name': "builder1", "slavename": "bot1", 'builddir': "builddir", 'slavebuilddir': "slavebuilddir", 'factory': None} b0 = Builder(setup, bss.getBuild().getBuilder()) b0.botmaster = FakeBotMaster() br = BuildRequest("reason", ss, 'test_builder') b = Build([br]) b.setBuilder(b0) s = step_class(**kwargs) s.setBuild(b) s.setStepStatus(bss) b.build_status = bss.getBuild() b.setupProperties() s.slaveVersion = fake_slaveVersion s.step_status.setText(s.describe(False)) return s
def makeBuildStep(basedir, step_class=BuildStep, **kwargs): bss = setupBuildStepStatus(basedir) ss = SourceStamp() setup = { 'name': "builder1", "slavename": "bot1", 'builddir': "builddir", 'factory': None } b0 = Builder(setup, bss.getBuild().getBuilder()) b0.botmaster = FakeBotMaster() br = BuildRequest("reason", ss) b = Build([br]) b.setBuilder(b0) s = step_class(**kwargs) s.setBuild(b) s.setStepStatus(bss) b.build_status = bss.getBuild() b.setupProperties() s.slaveVersion = fake_slaveVersion return s
def reconfigServiceBuilders(self, new_config): timer = metrics.Timer("BotMaster.reconfigServiceBuilders") timer.start() # arrange builders by name old_by_name = dict([(b.name, b) for b in list(self) if isinstance(b, Builder)]) old_set = set(old_by_name.iterkeys()) new_by_name = dict([(bc.name, bc) for bc in new_config.builders]) new_set = set(new_by_name.iterkeys()) # calculate new builders, by name, and removed builders removed_names, added_names = util.diffSets(old_set, new_set) if removed_names or added_names: log.msg("adding %d new builders, removing %d" % (len(added_names), len(removed_names))) for n in removed_names: builder = old_by_name[n] del self.builders[n] builder.master = None builder.botmaster = None yield defer.maybeDeferred( lambda: builder.disownServiceParent()) for n in added_names: builder = Builder(n) self.builders[n] = builder builder.botmaster = self builder.master = self.master builder.setServiceParent(self) self.builderNames = self.builders.keys() metrics.MetricCountEvent.log("num_builders", len(self.builders), absolute=True) # remove unclaimed builds if the builder has been removed from configuration if len(self.master.config.projects) > 1: queued_builds = yield self.master.db.buildrequests.getBuildRequestInQueue( sorted=True) # TODO: if we are running in multimaster mode with multiple instance of katana we need # to check for the project key as well removed_builders = [ b for b in queued_builds if b["buildername"] not in new_set ] self.removeQueuedBuilds(removed_builders) timer.stop()
def makeBuilder(self, klass): dummy_factory = klass([Dummy()]) builder = { 'name': 'b1', 'slavenames': ['s1'], 'builddir': 'b1', 'slavebuilddir': 'b1', 'factory': dummy_factory, } builder_status = mock.Mock() builder = Builder(builder, builder_status) builder.running = True builder.db = self.dbc builder.master_name = 'test_master' builder.master_incarnation = '12345' builder.botmaster = mock.Mock() builder.botmaster.shouldMergeRequests.return_value = True return builder
def reconfigServiceBuilders(self, new_config): timer = metrics.Timer("BotMaster.reconfigServiceBuilders") timer.start() # arrange builders by name old_by_name = dict([(b.name, b) for b in list(self) if isinstance(b, Builder)]) old_set = set(old_by_name.iterkeys()) new_by_name = dict([(bc.name, bc) for bc in new_config.builders]) new_set = set(new_by_name.iterkeys()) # calculate new builders, by name, and removed builders removed_names, added_names = util.diffSets(old_set, new_set) if removed_names or added_names: log.msg("adding %d new builders, removing %d" % (len(added_names), len(removed_names))) for n in removed_names: builder = old_by_name[n] del self.builders[n] builder.master = None builder.botmaster = None wfd = defer.waitForDeferred( defer.maybeDeferred(lambda: builder.disownServiceParent())) yield wfd wfd.getResult() for n in added_names: builder = Builder(n) self.builders[n] = builder builder.botmaster = self builder.master = self.master builder.setServiceParent(self) self.builderNames = self.builders.keys() metrics.MetricCountEvent.log("num_builders", len(self.builders), absolute=True) timer.stop()
def makeBuilder(self, klass): dummy_factory = klass([Dummy()]) builder = { "name": "b1", "slavenames": ["s1"], "builddir": "b1", "slavebuilddir": "b1", "factory": dummy_factory, } builder_status = mock.Mock() builder = Builder(builder, builder_status) builder.running = True builder.db = self.dbc builder.master_name = "test_master" builder.master_incarnation = "12345" builder.botmaster = mock.Mock() builder.botmaster.shouldMergeRequests.return_value = True return builder
def loadConfig_Builders(self, newBuilderData): somethingChanged = False newList = {} newBuilderNames = [] allBuilders = self.botmaster.builders.copy() for data in newBuilderData: name = data['name'] newList[name] = data newBuilderNames.append(name) # identify all that were removed for oldname in self.botmaster.getBuildernames(): if oldname not in newList: log.msg("removing old builder %s" % oldname) del allBuilders[oldname] somethingChanged = True # announce the change self.status.builderRemoved(oldname) # everything in newList is either unchanged, changed, or new for name, data in newList.items(): old = self.botmaster.builders.get(name) basedir = data['builddir'] # used on both master and slave #name, slave, builddir, factory = data if not old: # new # category added after 0.6.2 category = data.get('category', None) log.msg("adding new builder %s for category %s" % (name, category)) statusbag = self.status.builderAdded(name, basedir, category) builder = Builder(data, statusbag) allBuilders[name] = builder somethingChanged = True elif old.compareToSetup(data): # changed: try to minimize the disruption and only modify the # pieces that really changed diffs = old.compareToSetup(data) log.msg("updating builder %s: %s" % (name, "\n".join(diffs))) statusbag = old.builder_status statusbag.saveYourself() # seems like a good idea # TODO: if the basedir was changed, we probably need to make # a new statusbag new_builder = Builder(data, statusbag) new_builder.consumeTheSoulOfYourPredecessor(old) # that migrates any retained slavebuilders too # point out that the builder was updated. On the Waterfall, # this will appear just after any currently-running builds. statusbag.addPointEvent(["config", "updated"]) allBuilders[name] = new_builder somethingChanged = True else: # unchanged: leave it alone log.msg("builder %s is unchanged" % name) pass if somethingChanged: sortedAllBuilders = [allBuilders[name] for name in newBuilderNames] d = self.botmaster.setBuilders(sortedAllBuilders) return d return None
class TestTrigger(steps.BuildStepMixin, unittest.TestCase): def setUp(self): return self.setUpBuildStep() def tearDown(self): return self.tearDownBuildStep() def setupStep(self, step, sourcestampsInBuild=None, gotRevisionsInBuild=None, *args, **kwargs): sourcestamps = sourcestampsInBuild or [] got_revisions = gotRevisionsInBuild or {} steps.BuildStepMixin.setupStep(self, step, *args, **kwargs) # This step reaches deeply into a number of parts of Buildbot. That # should be fixed! # set up a buildmaster that knows about two fake schedulers, a and b m = fakemaster.make_master() self.build.builder.botmaster = m.botmaster m.db = fakedb.FakeDBConnector(self) m.status = master.Status(m) m.config.buildbotURL = "baseurl/" self.scheduler_a = a = FakeTriggerable(name='a') self.scheduler_b = b = FakeTriggerable(name='b') def allSchedulers(): return [ a, b ] m.allSchedulers = allSchedulers a.brids = {'A': 11} b.brids = {'B': 22} make_fake_br = lambda brid, name: fakedb.BuildRequest(id=brid, buildsetid=BRID_TO_BSID(brid), buildername=name) make_fake_build = lambda brid: fakedb.Build(brid=brid, id=BRID_TO_BID(brid), number=BRID_TO_BUILD_NUMBER(brid)) m.db.insertTestData([ make_fake_br(11, "A"), make_fake_br(22, "B"), make_fake_build(11), make_fake_build(22), ]) def getAllSourceStamps(): return sourcestamps self.build.getAllSourceStamps = getAllSourceStamps def getAllGotRevisions(): return got_revisions self.build.build_status.getAllGotRevisions = getAllGotRevisions request = Mock() request.id = 1 self.build.requests = [request] self.exp_add_sourcestamp = None self.exp_a_trigger = None self.exp_b_trigger = None self.exp_added_urls = [] def runStep(self, expect_waitForFinish=False): d = steps.BuildStepMixin.runStep(self) if expect_waitForFinish: # the build doesn't finish until after a callLater, so this has the # effect of checking whether the deferred has been fired already; # it should not have been! early = [] d.addCallback(early.append) self.assertEqual(early, []) def check(_): self.assertEqual(self.scheduler_a.triggered_with, self.exp_a_trigger) self.assertEqual(self.scheduler_b.triggered_with, self.exp_b_trigger) self.assertEqual(self.step_status.addURL.call_args_list, self.exp_added_urls) if self.exp_add_sourcestamp: self.assertEqual(self.addSourceStamp_kwargs, self.exp_add_sourcestamp) d.addCallback(check) # pause runStep's completion until after any other callLater's are done def wait(_): d = defer.Deferred() reactor.callLater(0, d.callback, None) return d d.addCallback(wait) return d def expectTriggeredWith(self, a=None, b=None): self.exp_a_trigger = a self.exp_b_trigger = b def expectAddedSourceStamp(self, **kwargs): self.exp_add_sourcestamp = kwargs def expectTriggeredLinks(self, *args): def get_args(sch, name): label = lambda name, num: "%s #%d" % (name, num) url = lambda name, num: "baseurl/builders/%s/builds/%d" % (name, num ) num = BRID_TO_BUILD_NUMBER(sch.brids[name]) #returns the *args and **kwargs that will be called on addURL... # which is just addURL('label', 'url') return ( (label(name,num), url(name,num)) , {} ) if 'a' in args: self.exp_added_urls.append(get_args(self.scheduler_a, 'A')) if 'b' in args: self.exp_added_urls.append(get_args(self.scheduler_b, 'B')) # tests def test_no_schedulerNames(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger()) def test_sourceStamp_and_updateSourceStamp(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger(schedulerNames=['c'], sourceStamp=dict(x=1), updateSourceStamp=True)) def test_sourceStamps_and_updateSourceStamp(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger(schedulerNames=['c'], sourceStamps=[dict(x=1), dict(x=2)], updateSourceStamp=True)) def test_updateSourceStamp_and_alwaysUseLatest(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger(schedulerNames=['c'], updateSourceStamp=True, alwaysUseLatest=True)) def test_sourceStamp_and_alwaysUseLatest(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger(schedulerNames=['c'], sourceStamp=dict(x=1), alwaysUseLatest=True)) def test_sourceStamps_and_alwaysUseLatest(self): self.assertRaises(config.ConfigErrors, lambda : trigger.Trigger(schedulerNames=['c'], sourceStamps=[dict(x=1), dict(x=2)], alwaysUseLatest=True)) def test_simple(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], sourceStamps = {})) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_simple_failure(self): self.setupStep(trigger.Trigger(schedulerNames=['a'])) self.scheduler_a.result = FAILURE # not waitForFinish, so trigger step succeeds even though the build # didn't fail self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() @compat.usesFlushLoggedErrors def test_simple_exception(self): self.setupStep(trigger.Trigger(schedulerNames=['a'])) self.scheduler_a.exception = True self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) d = self.runStep() def flush(_): self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) d.addCallback(flush) return d def test_bogus_scheduler(self): self.setupStep(trigger.Trigger(schedulerNames=['a', 'x'])) self.expectOutcome(result=FAILURE, status_text=['not valid scheduler:', 'x']) self.expectTriggeredWith(a=None) # a is not triggered! return self.runStep() def test_updateSourceStamp(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=True), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ], gotRevisionsInBuild = {'': 23456}, ) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({'':{'codebase':'', 'repository': 'x', 'revision': 23456} }, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_updateSourceStamp_no_got_revision(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=True), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ]) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({'':{'codebase':'', 'repository': 'x', 'revision': 11111} # uses old revision }, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_not_updateSourceStamp(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=False), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ], gotRevisionsInBuild = {'': 23456}, ) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({'':{'codebase':'', 'repository': 'x', 'revision': 11111} }, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_updateSourceStamp_multiple_repositories(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=True), sourcestampsInBuild = [ FakeSourceStamp(codebase='cb1', revision='12345'), FakeSourceStamp(codebase='cb2', revision='12345') ], gotRevisionsInBuild = {'cb1': 23456, 'cb2': 34567}, ) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({'cb1': {'codebase':'cb1', 'revision':23456}, 'cb2': {'codebase':'cb2', 'revision':34567} }, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_updateSourceStamp_prop_false(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=properties.Property('usess')), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ], gotRevisionsInBuild = {'': 23456}, ) self.properties.setProperty('usess', False, 'me') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) # didn't use got_revision self.expectTriggeredWith(a=({'': { 'codebase':'', 'repository': 'x', 'revision': 11111 }}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_updateSourceStamp_prop_true(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], updateSourceStamp=properties.Property('usess')), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ], gotRevisionsInBuild = {'': 23456}, ) self.properties.setProperty('usess', True, 'me') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) # didn't use got_revision self.expectTriggeredWith(a=({'': { 'codebase':'', 'repository': 'x', 'revision': 23456 }}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_alwaysUseLatest(self): self.setupStep(trigger.Trigger(schedulerNames=['b'], alwaysUseLatest=True), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ]) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) # Do not pass setid self.expectTriggeredWith(b=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_alwaysUseLatest_prop_false(self): self.setupStep(trigger.Trigger(schedulerNames=['b'], alwaysUseLatest=properties.Property('aul')), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ]) self.properties.setProperty('aul', False, 'me') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) # didn't use latest self.expectTriggeredWith(b=({'': { 'codebase':'', 'repository': 'x', 'revision': 11111} }, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_alwaysUseLatest_prop_true(self): self.setupStep(trigger.Trigger(schedulerNames=['b'], alwaysUseLatest=properties.Property('aul')), sourcestampsInBuild = [FakeSourceStamp(codebase='', repository='x', revision=11111) ]) self.properties.setProperty('aul', True, 'me') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) # didn't use latest self.expectTriggeredWith(b=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_sourceStamp(self): ss = dict(revision=9876, branch='dev') self.setupStep(trigger.Trigger(schedulerNames=['b'], sourceStamp=ss)) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) self.expectTriggeredWith(b=({'': ss}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_set_of_sourceStamps(self): ss1 = dict(codebase='cb1', repository='r1', revision=9876, branch='dev') ss2 = dict(codebase='cb2',repository='r2', revision=5432, branch='dev') self.setupStep(trigger.Trigger(schedulerNames=['b'], sourceStamps=[ss1,ss2])) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) self.expectTriggeredWith(b=({'cb1':ss1, 'cb2':ss2}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_set_of_sourceStamps_override_build(self): ss1 = dict(codebase='cb1', repository='r1', revision=9876, branch='dev') ss2 = dict(codebase='cb2',repository='r2', revision=5432, branch='dev') ss3 = FakeSourceStamp(codebase='cb3', repository='r3', revision=1234, branch='dev') ss4 = FakeSourceStamp(codebase='cb4',repository='r4', revision=2345, branch='dev') self.setupStep(trigger.Trigger(schedulerNames=['b'], sourceStamps=[ss1,ss2]), sourcestampsInBuild=[ss3, ss4]) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) self.expectTriggeredWith(b=({'cb1':ss1, 'cb2':ss2}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_sourceStamp_prop(self): self.setupStep(trigger.Trigger(schedulerNames=['b'], sourceStamp=dict(revision=properties.Property('rev'), branch='dev'))) self.properties.setProperty('rev', 602, 'me') expected_ss = dict(revision=602, branch='dev') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'b'"]) self.expectTriggeredWith(b=({'': expected_ss}, {'stepname': ('Trigger', 'Trigger')}, 1)) return self.runStep() def test_waitForFinish(self): self.setupStep(trigger.Trigger(schedulerNames=['a', 'b'], waitForFinish=True)) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'", "'b'"]) self.expectTriggeredWith( a=({}, {'stepname': ('Trigger', 'Trigger')}, 1), b=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) self.expectTriggeredLinks('a','b') return self.runStep(expect_waitForFinish=True) def test_waitForFinish_failure(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], waitForFinish=True)) self.scheduler_a.result = FAILURE self.expectOutcome(result=DEPENDENCY_FAILURE, status_text=['Dependency failed to build.']) self.expectTriggeredWith(a=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) self.expectTriggeredLinks('a') return self.runStep(expect_waitForFinish=True) @compat.usesFlushLoggedErrors def test_waitForFinish_exception(self): self.setupStep(trigger.Trigger(schedulerNames=['a', 'b'], waitForFinish=True)) self.scheduler_b.exception = True self.expectOutcome(result=DEPENDENCY_FAILURE, status_text=['Dependency failed to build.']) self.expectTriggeredWith( a=({}, {'stepname': ('Trigger', 'Trigger')}, 1), b=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) self.expectTriggeredLinks('a') # b doesn't return a brid d = self.runStep(expect_waitForFinish=True) def flush(_): self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1) d.addCallback(flush) return d def test_set_properties(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], set_properties=dict(x=1, y=2))) self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, dict(stepname=('Trigger', 'Trigger'), x=(1, 'Trigger'), y=(2, 'Trigger')), 1)) return self.runStep() def test_set_properties_prop(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], set_properties=dict(x=properties.Property('X'), y=2))) self.properties.setProperty('X', 'xxx', 'here') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, dict(stepname=('Trigger', 'Trigger'), x=('xxx', 'Trigger'), y=(2, 'Trigger')), 1)) return self.runStep() def test_copy_properties(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], copy_properties=['a', 'b'])) self.properties.setProperty('a', 'A', 'AA') self.properties.setProperty('b', 'B', 'BB') self.properties.setProperty('c', 'C', 'CC') self.expectOutcome(result=SUCCESS, status_text=['Triggered:', "'a'"]) self.expectTriggeredWith(a=({}, dict(a=('A', 'Trigger'), b=('B', 'Trigger'), stepname=('Trigger', 'Trigger')), 1)) return self.runStep() def test_interrupt(self): self.setupStep(trigger.Trigger(schedulerNames=['a'], waitForFinish=True)) self.expectOutcome(result=INTERRUPTED, status_text=['Trigger', '(build was interrupted)']) self.expectTriggeredWith(a=({}, {'stepname': ('Trigger', 'Trigger')}, 1)) d = self.runStep(expect_waitForFinish=True) # interrupt before the callLater representing the Triggerable # schedulers completes self.step.interrupt(failure.Failure(RuntimeError('oh noes'))) return d @defer.inlineCallbacks def test_interruptConnectionLostShouldRetry(self): self.master = fakemaster.FakeMaster() self.master.maybeStartBuildsForSlave = lambda slave: True self.master.db = fakedb.FakeDBConnector(self) rows = [fakedb.SourceStampSet(id=1), fakedb.SourceStamp(id=1, sourcestampsetid=1, codebase='c', branch="az", repository="xz", revision="ww"), fakedb.Buildset(id=1, reason='because', sourcestampsetid=1), fakedb.BuildRequest(id=1, buildsetid=1, buildername="bldr", submitted_at=130000)] yield self.master.db.insertTestData(rows) self.master.status = master.Status(self.master) self.master.config.buildbotURL = "baseurl/" self.scheduler_a = a = FakeTriggerable(name='a') self.scheduler_b = b = FakeTriggerable(name='b') def allSchedulers(): return [a, b] self.master.allSchedulers = allSchedulers self.factory = factory.BuildFactory() self.step = trigger.Trigger(schedulerNames=['a'], waitForFinish=True) self.step.addCompleteLog = lambda x,y: True self.factory.addStep(self.step) config_args = dict(name="bldr", slavename="slv", builddir="bdir", slavebuilddir="sbdir", project='default', factory=self.factory) builder_config = config.BuilderConfig(**config_args) self.bldr = Builder(builder_config.name, _addServices=False) self.bldr.master = self.master self.bldr.botmaster = self.master.botmaster mastercfg = config.MasterConfig() mastercfg.builders = [ builder_config ] self.bldr.startService() yield self.bldr.reconfigService(mastercfg) def newBuild(buildrequests): self.build = Build(buildrequests) self.build.setStepFactories([fakebuild.FakeStepFactory(self.step)]) return self.build self.bldr.config.factory.newBuild = newBuild self.bldr.notifyRequestsRemoved = lambda x: True sb = Mock(spec=['isAvailable'], name='test-slave-1') sb.name = 'test-slave-1' sb.isAvailable.return_value = 1 sb.slave = Mock() sb.slave.updateStatusBuildFinished = lambda result, build: result sb.slave.properties = properties.Properties() sb.prepare = lambda x, y: True sb.ping = lambda timeout: True sb.buildStarted = lambda: True sb.buildFinished = lambda _: False sb.setSlaveIdle = lambda: False sb.remote = Mock() self.bldr.slaves.append(sb) self.assertEqual(self.master.db.buildrequests.claims, {}) from buildbot.process import buildrequestdistributor self.brd = buildrequestdistributor.BuildRequestDistributor(self.master.botmaster) self.brd.startService() yield self.brd._maybeStartBuildsOnBuilder(self.bldr) self.assertEqual(self.master.db.buildrequests.claims[1].brid, 1) self.build.build_status.saveYourself = lambda: True self.build.currentStep.start() self.build.lostRemote() self.assertEqual(self.master.db.buildrequests.claims, {}) if self.brd.running: self.brd.stopService() @defer.inlineCallbacks def test_TriggerStepMultiMasterMode(self): m = fakemaster.FakeMaster() m.maybeStartBuildsForSlave = lambda slave: True m.status = master.Status(m) m.config.buildbotURL = "baseurl/" m.config.multiMaster = True m.db = fakedb.FakeDBConnector(self) scheduler_a = FakeTriggerable(name='a') m.allSchedulers = lambda: [scheduler_a] def trigger_sch(sourcestamps = None, set_props=None, triggeredbybrid=None, reason=None): rows = [ fakedb.MasterConfig(id=1, buildbotURL="build-master-01/", objectid=1), fakedb.MasterConfig(id=2, buildbotURL="build-master-02/", objectid=2), fakedb.SourceStampSet(id=1), fakedb.SourceStamp(id=1, sourcestampsetid=1, codebase='c', branch="az", repository="xz", revision="ww"), fakedb.Buildset(id=1, reason='because', sourcestampsetid=1), fakedb.BuildRequest(id=1, buildsetid=1, buildername="builder1", submitted_at=130000), fakedb.BuildRequest(id=2, buildsetid=1, buildername="builder2", submitted_at=130000), fakedb.BuildRequestClaim(brid=1, objectid=2, claimed_at=130000), fakedb.BuildRequestClaim(brid=2, objectid=1, claimed_at=130000), fakedb.Build(id=1, number=1, brid=1), fakedb.Build(id=2, number=1, brid=2)] d = m.db.insertTestData(rows) d.addCallback(lambda _: (SUCCESS, {'builder1': 1L, 'builder2': 2L})) return d scheduler_a.trigger = trigger_sch self.step = trigger.Trigger(schedulerNames=['a'], waitForFinish=True) self.step.addCompleteLog = lambda x,y: True self.step.step_status = Mock() self.step.step_status.getLogs = lambda: [] self.expected_urls = [] self.step.step_status.addURL = lambda text, path, results=None: \ self.expected_urls.append({'text': text, 'path': path}) self.step.build = fakebuild.FakeBuild() self.step.build.builder.botmaster = m.botmaster self.step.build.getAllSourceStamps = lambda: [] self.step.build.build_status.getAllGotRevisions = lambda: {} request = Mock() request.id = 1 self.step.build.requests = [request] self.remote = Mock(name="SlaveBuilder(remote)") yield self.step.startStep(self.remote) self.assertEquals(len(self.expected_urls), 2) self.assertTrue({'text': 'builder1 #1', 'path': 'build-master-02/builders/builder1/builds/1'} in self.expected_urls) self.assertTrue({'text': 'builder1 #1', 'path': 'build-master-02/builders/builder1/builds/1'} in self.expected_urls)
def test_interruptConnectionLostShouldRetry(self): self.master = fakemaster.FakeMaster() self.master.maybeStartBuildsForSlave = lambda slave: True self.master.db = fakedb.FakeDBConnector(self) rows = [fakedb.SourceStampSet(id=1), fakedb.SourceStamp(id=1, sourcestampsetid=1, codebase='c', branch="az", repository="xz", revision="ww"), fakedb.Buildset(id=1, reason='because', sourcestampsetid=1), fakedb.BuildRequest(id=1, buildsetid=1, buildername="bldr", submitted_at=130000)] yield self.master.db.insertTestData(rows) self.master.status = master.Status(self.master) self.master.config.buildbotURL = "baseurl/" self.scheduler_a = a = FakeTriggerable(name='a') self.scheduler_b = b = FakeTriggerable(name='b') def allSchedulers(): return [a, b] self.master.allSchedulers = allSchedulers self.factory = factory.BuildFactory() self.step = trigger.Trigger(schedulerNames=['a'], waitForFinish=True) self.step.addCompleteLog = lambda x,y: True self.factory.addStep(self.step) config_args = dict(name="bldr", slavename="slv", builddir="bdir", slavebuilddir="sbdir", project='default', factory=self.factory) builder_config = config.BuilderConfig(**config_args) self.bldr = Builder(builder_config.name, _addServices=False) self.bldr.master = self.master self.bldr.botmaster = self.master.botmaster mastercfg = config.MasterConfig() mastercfg.builders = [ builder_config ] self.bldr.startService() yield self.bldr.reconfigService(mastercfg) def newBuild(buildrequests): self.build = Build(buildrequests) self.build.setStepFactories([fakebuild.FakeStepFactory(self.step)]) return self.build self.bldr.config.factory.newBuild = newBuild self.bldr.notifyRequestsRemoved = lambda x: True sb = Mock(spec=['isAvailable'], name='test-slave-1') sb.name = 'test-slave-1' sb.isAvailable.return_value = 1 sb.slave = Mock() sb.slave.updateStatusBuildFinished = lambda result, build: result sb.slave.properties = properties.Properties() sb.prepare = lambda x, y: True sb.ping = lambda timeout: True sb.buildStarted = lambda: True sb.buildFinished = lambda _: False sb.setSlaveIdle = lambda: False sb.remote = Mock() self.bldr.slaves.append(sb) self.assertEqual(self.master.db.buildrequests.claims, {}) from buildbot.process import buildrequestdistributor self.brd = buildrequestdistributor.BuildRequestDistributor(self.master.botmaster) self.brd.startService() yield self.brd._maybeStartBuildsOnBuilder(self.bldr) self.assertEqual(self.master.db.buildrequests.claims[1].brid, 1) self.build.build_status.saveYourself = lambda: True self.build.currentStep.start() self.build.lostRemote() self.assertEqual(self.master.db.buildrequests.claims, {}) if self.brd.running: self.brd.stopService()