class TestPropFuncs(unittest.TestCase): basedir = "test_misc_scheduler_propfuncs" def setUp(self): if os.path.exists(self.basedir): shutil.rmtree(self.basedir) os.makedirs(self.basedir) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir) manager = DBSchemaManager(spec, self.basedir) manager.upgrade() self.dbc = connector.DBConnector(spec) self.dbc.start() self.s = Scheduler(name="s", builderNames=["b1"]) self.s.parent = mock.Mock() self.s.parent.db = self.dbc return self.dbc.addSchedulers([self.s]) def tearDown(self): self.dbc.stop() shutil.rmtree(self.basedir) def test_buildIDSchedFunc(self): import time with mock.patch.object(time, 'time') as time_method: time_method.return_value = 10 self.dbc.runInteractionNow( lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals( state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(10))) # Running this again at the same time should increment our buildid by 1 self.dbc.runInteractionNow( lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals( state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(11))) # If time happens to go backwards, our buildid shouldn't time_method.return_value = 8 self.dbc.runInteractionNow( lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals( state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(12))) def test_buildUIDSchedFunc(self): import uuid with mock.patch.object(uuid, 'uuid4') as uuid4_method: uuid4_method.return_value.hex = '1234567890abcdef' props = self.dbc.runInteractionNow( lambda t: buildUIDSchedFunc(self.s, t, None)) self.assertEquals(props['builduid'], '1234567890abcdef')
def test_many_changes(self): m, cm, sm = self.build_harness("db/scheduler/many_changes") s = Scheduler("one", branch=None, treeStableTimer=0.01, builderNames=["builder-one"]) d = sm.updateSchedulers([s]) # add ten changes, then process them all at once. Sometimes the # database connector has problems with lots of queries happening # simultaneously. for i in range(10): c = Change(who="brian", files=["foo%d.txt" % i], comments="change %d" % i, revision="%d" % (i+10)) d.addCallback(lambda ign, c=c: cm.addChange(c)) d.addCallback(self.stall, 1.0) d.addCallback(lambda ign: s.run()) def _build_not_sleep(res): # a BuildRequest should be pushed, and the Scheduler should go # back to sleep self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failUnlessEqual(len(pending), 1) changes = pending[0][1].changes self.failUnlessEqual(len(changes), 10) d.addCallback(_build_not_sleep) return d
def test_stabletimer(self): m, cm, sm = self.build_harness("db/scheduler/stabletimer") s = Scheduler("one", branch=None, treeStableTimer=30, builderNames=["builder-one"]) d = sm.updateSchedulers([s]) # there are no changes in the database, so the scheduler should want # to keep sleeping. d.addCallback(lambda ign: s.run()) def _sleep_forever_not_build(res): self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failIf(pending) d.addCallback(_sleep_forever_not_build) # now add one change. The scheduler should want to wait for the # tree-stable timer to fire. c1 = Change(who="brian", files=["foo.c"], comments="first change", revision="1234") d.addCallback(lambda ign: cm.addChange(c1)) d.addCallback(lambda ign: s.run()) def _sleep_not_build(res): # the scheduler should tell us that they want to be woken up in # 30 seconds. This test would be much too fragile if we actually # asserted anything about its value, though. self.failUnlessEqual(type(res), float) pending = self.get_buildrequests(m, cm) self.failIf(pending) d.addCallback(_sleep_not_build) # running it again should tell us roughly the same thing d.addCallback(lambda ign: s.run()) d.addCallback(_sleep_not_build) def _reduce_timer(res): # artificially lower the tree-stable-timer value s.treeStableTimer = 0 d.addCallback(_reduce_timer) d.addCallback(lambda ign: s.run()) def _build_not_sleep(res): # a BuildRequest should be pushed, and the Scheduler should go # back to sleep self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failUnlessEqual(len(pending), 1) changes = pending[0][1].changes self.failUnlessEqual(len(changes), 1) self.failUnlessEqual(changes[0].revision, "1234") self.failUnlessEqual(changes[0].files, ["foo.c"]) d.addCallback(_build_not_sleep) return d
class TestPropFuncs(unittest.TestCase): basedir = "test_misc_scheduler_propfuncs" def setUp(self): if os.path.exists(self.basedir): shutil.rmtree(self.basedir) os.makedirs(self.basedir) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir) manager = DBSchemaManager(spec, self.basedir) manager.upgrade() self.dbc = connector.DBConnector(spec) self.dbc.start() self.s = Scheduler(name="s", builderNames=["b1"]) self.s.parent = mock.Mock() self.s.parent.db = self.dbc return self.dbc.addSchedulers([self.s]) def tearDown(self): self.dbc.stop() shutil.rmtree(self.basedir) def test_buildIDSchedFunc(self): import time with mock.patch.object(time, 'time') as time_method: time_method.return_value = 10 self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(10))) # Running this again at the same time should increment our buildid by 1 self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(11))) # If time happens to go backwards, our buildid shouldn't time_method.return_value = 8 self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None)) state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t)) self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(12))) def test_buildUIDSchedFunc(self): import uuid with mock.patch.object(uuid, 'uuid4') as uuid4_method: uuid4_method.return_value.hex = '1234567890abcdef' props = self.dbc.runInteractionNow(lambda t: buildUIDSchedFunc(self.s, t, None)) self.assertEquals(props['builduid'], '1234567890abcdef')
def setUp(self): if os.path.exists(self.basedir): shutil.rmtree(self.basedir) os.makedirs(self.basedir) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir) manager = DBSchemaManager(spec, self.basedir) manager.upgrade() self.dbc = connector.DBConnector(spec) self.dbc.start() self.s = Scheduler(name="s", builderNames=["b1"]) self.s.parent = mock.Mock() self.s.parent.db = self.dbc return self.dbc.addSchedulers([self.s])
def Update(_config, active_master, c): factory_obj = annotator_factory.AnnotatorFactory( active_master=active_master) builders = [ Builder(factory_obj, 'x86-generic'), Builder(factory_obj, 'amd64-generic'), ] c['schedulers'] += [ Scheduler(name='chromium_src_asan', branch='master', treeStableTimer=60, builderNames=[b['name'] for b in builders], ), ] c['builders'] += builders
def Update(self, c): global_schedulers = dict((s.name, s) for s in c['schedulers'] if s.name.startswith('global_')) assert not (set(global_schedulers) & set(self._schedulers)) for builder in self._builders: # Update the schedulers with the builder. schedulers = builder['schedulers'] if schedulers: for scheduler in schedulers: if scheduler in global_schedulers: global_schedulers[scheduler].builderNames.append(builder['name']) else: self._schedulers[scheduler]['builders'].append(builder['name']) # Construct the category. categories = [] if builder.get('category', None): categories.append(builder['category']) if builder.get('gatekeeper', None): categories.extend(builder['gatekeeper'].split('|')) category = '|'.join(categories) # Append the builder to the list. new_builder = {'name': builder['name'], 'factory': self._factories[builder['factory']], 'category': category, 'auto_reboot': builder['auto_reboot']} if builder['builddir']: new_builder['builddir'] = builder['builddir'] if builder['slavebuilddir']: new_builder['slavebuilddir'] = builder['slavebuilddir'] c['builders'].append(new_builder) # Process the main schedulers. for s_name in self._schedulers: scheduler = self._schedulers[s_name] if scheduler['type'] == 'Scheduler': instance = Scheduler(name=s_name, branch=scheduler['branch'], treeStableTimer=scheduler['treeStableTimer'], builderNames=scheduler['builders'], categories=scheduler['categories']) scheduler['instance'] = instance c['schedulers'].append(instance) elif scheduler['type'] == 'URLScheduler': ident = str(uuid.uuid4()) c['change_source'].append( URLPoller(changeurl=scheduler['url'], pollInterval=scheduler['pollInterval'], category=ident, include_revision=scheduler['include_revision'])) instance = Scheduler(name=s_name, change_filter=ChangeFilter(category=ident), builderNames=scheduler['builders']) scheduler['instance'] = instance c['schedulers'].append(instance) # Process the dependent schedulers. for s_name in self._schedulers: scheduler = self._schedulers[s_name] if scheduler['type'] == 'Dependent': c['schedulers'].append( Dependent(s_name, self._schedulers[scheduler['parent']]['instance'], scheduler['builders'])) # Process the triggerable schedulers. for s_name in self._schedulers: scheduler = self._schedulers[s_name] if scheduler['type'] == 'Triggerable': c['schedulers'].append(Triggerable(s_name, scheduler['builders'])) # Process the periodic schedulers. for s_name in self._schedulers: scheduler = self._schedulers[s_name] if scheduler['type'] == 'Periodic': c['schedulers'].append( Periodic(s_name, periodicBuildTimer=scheduler['periodicBuildTimer'], builderNames=scheduler['builders'])) # Process the nightly schedulers. for s_name in self._schedulers: scheduler = self._schedulers[s_name] if scheduler['type'] == 'Nightly': c['schedulers'].append(Nightly(s_name, branch=scheduler['branch'], hour=scheduler['hour'], builderNames=scheduler['builders']))
class TestTestOrder(unittest.TestCase): """Tests that tests are run according to their corresponding build's start time""" basedir = "test_test_order" def setUp(self): if os.path.exists(self.basedir): shutil.rmtree(self.basedir) os.makedirs(self.basedir) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir) manager = DBSchemaManager(spec, self.basedir) manager.upgrade() self.dbc = connector.DBConnector(spec) self.dbc.start() parent = mock.Mock() parent.db = self.dbc change_manager = ChangeManager() change_manager.parent = parent parent.change_svc = change_manager self.s = Scheduler(name="s", builderNames=["b1"]) self.s.parent = parent return self.dbc.addSchedulers([self.s]) 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 tearDown(self): self.dbc.stop() shutil.rmtree(self.basedir) def test_singleRequest(self): # Easy peasy c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}) self.dbc.addChangeToDatabase(c1) builder = self.makeBuilder(BuildFactory) # Run the scheduler d = self.s.run() # Check that we have a build request def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 1) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 1) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, '1') changes = build.source.changes self.assertEquals(changes[0].revision, '1') return d.addCallback(startBuild) return d def test_threeRequests(self): # Three changes, r1, r2, r3 # They start in order, and finish in reverse order # We want the to be testing r3 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r3') changes = build.source.changes # The last revision should be r3, since it started latest self.assertEquals(changes[0].revision, 'r1') self.assertEquals(changes[1].revision, 'r2') self.assertEquals(changes[2].revision, 'r3') return d.addCallback(startBuild) return d def test_threeRequestsUnsorted(self): # Three changes, r1, r2, r3 # They start in order, and finish in reverse order # We want the to be testing r3 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(BuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was submitted latest self.assertEquals(changes[0].revision, 'r3') self.assertEquals(changes[1].revision, 'r2') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_threeRequestsManual(self): # Three changes, r1, r2, r3 # r2, and r3 have buildids # r1 is manually triggered, and is submitted later # we want to be testing r1 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was manually triggered later self.assertEquals(changes[0].revision, 'r2') self.assertEquals(changes[1].revision, 'r3') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_Rebuilds(self): # Two changes, r2, r3 # They start in order, and finish in reverse order # We also have a pending request to re-build r1 that happens after r2, r3 have started # We want to end up re-building r1 c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) # Run the scheduler d = self.s.run() # Rebuild r1 def addRebuild(t): c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c3) ss = SourceStamp(branch='b1', changes=[c3], revision='r1') ss1 = ss.getAbsoluteSourceStamp('r1') ssid = self.dbc.get_sourcestampid(ss, t) bsid = self.dbc.create_buildset(ssid, "rebuild", Properties(), ["b1"], t) d.addCallback(lambda ign: self.dbc.runInteractionNow(addRebuild)) builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was manually triggered later self.assertEquals(changes[0].revision, 'r2') self.assertEquals(changes[1].revision, 'r3') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_brokenRequest(self): c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}) self.dbc.addChangeToDatabase(c1) builder = self.makeBuilder(RequestSortingBuildFactory) # Run the scheduler d = self.s.run() # Check that we have a build request def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 1) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] # Hack the request to break the sorting requests[0].submittedAt = "asdf" requests[0].reason = "rebuild" self.assertEquals(len(requests), 1) build = builder.buildFactory.newBuild(requests) # This should have generated an error self.failUnless(len(self.flushLoggedErrors()) == 1) self.assertEquals(build.source.revision, '1') changes = build.source.changes self.assertEquals(changes[0].revision, '1') return d.addCallback(startBuild) return d
def test_immediate(self): m, cm, sm = self.build_harness("db/scheduler/immediate") def fileIsImportant(c): for fn in c.files: if not fn.endswith(".txt"): return True return False # we set the treeStableTimer to something tiny, since "None" has a # special meaning ("do not merge Changes") s = Scheduler("one", branch=None, treeStableTimer=0.01, builderNames=["builder-one"], fileIsImportant=fileIsImportant) d = sm.updateSchedulers([s]) # there are no changes in the database, so the scheduler should want # to keep sleeping. d.addCallback(lambda ign: s.run()) def _sleep_forever_not_build(res): self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failIf(pending) d.addCallback(_sleep_forever_not_build) # now add one change. The change is "unimportant", so no build will # be run. c1 = Change(who="brian", files=["docs.txt"], comments="doc change", revision="1234") d.addCallback(lambda ign: cm.addChange(c1)) d.addCallback(lambda ign: s.run()) d.addCallback(_sleep_forever_not_build) # running it again should tell us the same thing d.addCallback(lambda ign: s.run()) d.addCallback(_sleep_forever_not_build) # now add a second change which evaluates as "important", which # should trigger a build with both changes after the treeStableTimer # has passed, which should be quickly c2 = Change(who="brian", files=["foo.c", "subdir/bar.c"], comments="second change", revision="1235") d.addCallback(lambda ign: cm.addChange(c2)) # stall here to let the treeStableTimer expire d.addCallback(self.stall, 1.0) d.addCallback(lambda ign: s.run()) def _build_not_sleep(res): # a BuildRequest should be pushed, and the Scheduler should go # back to sleep self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failUnlessEqual(len(pending), 1) changes = pending[0][1].changes self.failUnlessEqual(len(changes), 2) self.failUnlessEqual(changes[0].revision, "1234") self.failUnlessEqual(changes[0].files, ["docs.txt"]) self.failUnlessEqual(changes[1].revision, "1235") self.failUnlessIn("foo.c", changes[1].files) self.failUnlessIn("subdir/bar.c", changes[1].files) d.addCallback(_build_not_sleep) # running it again should not do anything d.addCallback(lambda ign: s.run()) def _build_and_sleep(res): self.failUnlessEqual(res, None) pending = self.get_buildrequests(m, cm) self.failUnlessEqual(len(pending), 1) d.addCallback(_build_and_sleep) return d
class TestTestOrder(unittest.TestCase): """Tests that tests are run according to their corresponding build's start time""" basedir = "test_test_order" def setUp(self): if os.path.exists(self.basedir): shutil.rmtree(self.basedir) os.makedirs(self.basedir) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir) manager = DBSchemaManager(spec, self.basedir) manager.upgrade() self.dbc = connector.DBConnector(spec) self.dbc.start() parent = mock.Mock() parent.db = self.dbc change_manager = ChangeManager() change_manager.parent = parent parent.change_svc = change_manager self.s = Scheduler(name="s", builderNames=["b1"]) self.s.parent = parent return self.dbc.addSchedulers([self.s]) 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 tearDown(self): self.dbc.stop() shutil.rmtree(self.basedir) def test_singleRequest(self): # Easy peasy c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}) self.dbc.addChangeToDatabase(c1) builder = self.makeBuilder(BuildFactory) # Run the scheduler d = self.s.run() # Check that we have a build request def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 1) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 1) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, '1') changes = build.source.changes self.assertEquals(changes[0].revision, '1') return d.addCallback(startBuild) return d def test_threeRequests(self): # Three changes, r1, r2, r3 # They start in order, and finish in reverse order # We want the to be testing r3 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r3') changes = build.source.changes # The last revision should be r3, since it started latest self.assertEquals(changes[0].revision, 'r1') self.assertEquals(changes[1].revision, 'r2') self.assertEquals(changes[2].revision, 'r3') return d.addCallback(startBuild) return d def test_threeRequestsUnsorted(self): # Three changes, r1, r2, r3 # They start in order, and finish in reverse order # We want the to be testing r3 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(BuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was submitted latest self.assertEquals(changes[0].revision, 'r3') self.assertEquals(changes[1].revision, 'r2') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_threeRequestsManual(self): # Three changes, r1, r2, r3 # r2, and r3 have buildids # r1 is manually triggered, and is submitted later # we want to be testing r1 in the end c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', when=6) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) self.dbc.addChangeToDatabase(c3) # Run the scheduler d = self.s.run() builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was manually triggered # later self.assertEquals(changes[0].revision, 'r2') self.assertEquals(changes[1].revision, 'r3') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_Rebuilds(self): # Two changes, r2, r3 # They start in order, and finish in reverse order # We also have a pending request to re-build r1 that happens after r2, r3 have started # We want to end up re-building r1 c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000003'}, when=4) c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000002'}, when=5) self.dbc.addChangeToDatabase(c1) self.dbc.addChangeToDatabase(c2) # Run the scheduler d = self.s.run() # Rebuild r1 def addRebuild(t): c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}, when=6) self.dbc.addChangeToDatabase(c3) ss = SourceStamp(branch='b1', changes=[c3], revision='r1') ssid = self.dbc.get_sourcestampid(ss, t) self.dbc.create_buildset(ssid, "rebuild", Properties(), ["b1"], t) d.addCallback(lambda ign: self.dbc.runInteractionNow(addRebuild)) builder = self.makeBuilder(RequestSortingBuildFactory) # Check that we have three build requests def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 3) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] self.assertEquals(len(requests), 3) build = builder.buildFactory.newBuild(requests) self.assertEquals(build.source.revision, 'r1') changes = build.source.changes # The last revision should be r1, since it was manually triggered # later self.assertEquals(changes[0].revision, 'r2') self.assertEquals(changes[1].revision, 'r3') self.assertEquals(changes[2].revision, 'r1') return d.addCallback(startBuild) return d def test_brokenRequest(self): c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'], comments='really important', properties={'buildid': '20110214000001'}) self.dbc.addChangeToDatabase(c1) builder = self.makeBuilder(RequestSortingBuildFactory) # Run the scheduler d = self.s.run() # Check that we have a build request def checkRequests(ign): req = self.dbc.runQueryNow("select count(*) from buildrequests") self.assertEquals(req[0][0], 1) d.addCallback(checkRequests) # Claim the request def claimRequest(ign): d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"]) return d d.addCallback(claimRequest) # Start the build! def startBuild(assignments): self.assertEquals(len(assignments.keys()), 1) requests = assignments.values()[0] # Hack the request to break the sorting requests[0].submittedAt = "asdf" requests[0].reason = "rebuild" self.assertEquals(len(requests), 1) build = builder.buildFactory.newBuild(requests) # This should have generated an error self.failUnless(len(self.flushLoggedErrors()) == 1) self.assertEquals(build.source.revision, '1') changes = build.source.changes self.assertEquals(changes[0].revision, '1') return d.addCallback(startBuild) return d