def test_canBeMergedWith_where_sourcestamp_do_not_both_have_changes(self): c1 = mock.Mock() c1.codebase = 'cb' ss1 = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', codebase='cb', changes=[c1]) ss2 = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', codebase='cb', changes=[]) self.assertFalse(ss1.canBeMergedWith(ss2))
def test_canBeMergedWith_where_sourcestamp_have_different_codebases(self): ss1 = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', codebase='cbA', changes=[]) ss2 = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', codebase='cbB', changes=[]) self.assertFalse(ss1.canBeMergedWith(ss2))
def testSuccess(self): S = buildset.BuildSet a,b = FakeBuilder(), FakeBuilder() # this time, both builds succeed source = sourcestamp.SourceStamp() s = S(["a","b"], source, "forced build") s.start([a,b]) st = s.status self.failUnlessEqual(st.getSourceStamp(), source) self.failUnlessEqual(st.getReason(), "forced build") self.failUnlessEqual(st.getBuilderNames(), ["a","b"]) self.failIf(st.isFinished()) builderstatus_a = builder.BuilderStatus("a") bsa = builder.BuildStatus(builderstatus_a, 1) bsa.setResults(builder.SUCCESS) a.requests[0].finished(bsa) builderstatus_b = builder.BuilderStatus("b") bsb = builder.BuildStatus(builderstatus_b, 1) bsb.setResults(builder.SUCCESS) b.requests[0].finished(bsb) self.failUnless(st.isFinished()) self.failUnlessEqual(st.getResults(), builder.SUCCESS)
def test_getAbsoluteSourceStamp_from_relative(self): ss = sourcestamp.SourceStamp(branch='dev', revision=None, project='p', repository='r') abs_ss = ss.getAbsoluteSourceStamp('abcdef') self.assertEqual(abs_ss.branch, 'dev') self.assertEqual(abs_ss.revision, 'abcdef') self.assertEqual(abs_ss.project, 'p') self.assertEqual(abs_ss.repository, 'r')
def test_canBeMergedWith_with_self_patched_sourcestamps(self): ss = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', codebase='cbA', changes=[], patch=(1, '')) self.assertTrue(ss.canBeMergedWith(ss))
def test_getAbsoluteSourceStamp_from_absolute(self): ss = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r') abs_ss = ss.getAbsoluteSourceStamp('abcdef') self.assertEqual(abs_ss.branch, 'dev') # revision gets overridden self.assertEqual(abs_ss.revision, 'abcdef') self.assertEqual(abs_ss.project, 'p') self.assertEqual(abs_ss.repository, 'r')
def setUp(self): config = """ from buildbot.status import html from buildbot.process.factory import BasicBuildFactory from buildbot.buildslave import BuildSlave f1 = BasicBuildFactory('cvsroot', 'cvsmodule') BuildmasterConfig = { 'slaves': [BuildSlave('bot1', 'passwd1')], 'schedulers': [], 'builders': [{'name': 'builder1', 'slavename': 'bot1', 'builddir':'workdir', 'factory':f1}], 'slavePortnum': 0, 'status': [html.WebStatus(http_port=0)], } """ if os.path.exists("test_logfile"): shutil.rmtree("test_logfile") os.mkdir("test_logfile") self.master = m = ConfiguredMaster("test_logfile", config) m.startService() # hack to find out what randomly-assigned port it is listening on port = self.find_webstatus(m).getPortnum() self.port = port # insert an event req = base.BuildRequest("reason", sourcestamp.SourceStamp()) build1 = base.Build([req]) bs = m.status.getBuilder("builder1").newBuild() bs.setReason("reason") bs.buildStarted(build1) step1 = BuildStep(name="setup") step1.setBuild(build1) bss = bs.addStepWithName("setup") step1.setStepStatus(bss) bss.stepStarted() log1 = step1.addLog("output") log1.addStdout("some stdout\n") log1.finish() log2 = step1.addHTMLLog("error", "<html>ouch</html>") log3 = step1.addLog("big") log3.addStdout("big log\n") for i in range(1000): log3.addStdout("a" * 500) log3.addStderr("b" * 500) log3.finish() log4 = step1.addCompleteLog("bigcomplete", "big2 log\n" + "a" * 1 * 1000 * 1000) step1.step_status.stepFinished(builder.SUCCESS) bs.buildFinished()
def testGetBuildSets(self): # validate IStatus.getBuildSets s = status.builder.Status(None, ".") bs1 = buildset.BuildSet(["a", "b"], sourcestamp.SourceStamp(), reason="one", bsid="1") s.buildsetSubmitted(bs1.status) self.failUnlessEqual(s.getBuildSets(), [bs1.status]) bs1.status.notifyFinishedWatchers() self.failUnlessEqual(s.getBuildSets(), [])
def test_constructor_most_recent_change(self): chgs = [ changes.Change('author', [], 'comments', branch='branch', revision='2'), changes.Change('author', [], 'comments', branch='branch', revision='3'), changes.Change('author', [], 'comments', branch='branch', revision='1'), ] for ch in chgs: # mock the DB changeid (aka build number) to match rev ch.number = int(ch.revision) ss = sourcestamp.SourceStamp(changes=chgs) self.assertEquals(ss.revision, '3')
def _then(ign): port = s.getPort() config = { 'connect': 'pb', 'username': '******', 'passwd': 'pw1', 'master': "localhost:%d" % port, 'builders': ["a", "b"], } self.tryclient = t = tryclient.Try(config) ss = sourcestamp.SourceStamp("branch1", "123", (1, "diff")) t.sourcestamp = ss return t.deliverJob()
def upgradeToVersion1(self): if hasattr(self, "sourceStamp"): # the old .sourceStamp attribute wasn't actually very useful maxChangeNumber, patch = self.sourceStamp changes = getattr(self, 'changes', []) source = sourcestamp.SourceStamp(branch=None, revision=None, patch=patch, changes=changes) self.source = source self.changes = source.changes del self.sourceStamp self.wasUpgraded = True
def test_getAbsoluteSourceStamp_from_absolute_with_changes(self): c1 = mock.Mock() c1.branch = 'dev' c1.revision = 'xyz' c1.project = 'p' c1.repository = 'r' ss = sourcestamp.SourceStamp(branch='dev', revision='xyz', project='p', repository='r', changes=[c1]) abs_ss = ss.getAbsoluteSourceStamp('abcdef') self.assertEqual(abs_ss.branch, 'dev') # revision changes, even though changes say different - this is # useful for CVS, for example self.assertEqual(abs_ss.revision, 'abcdef') self.assertEqual(abs_ss.project, 'p') self.assertEqual(abs_ss.repository, 'r')
def _started(ign): # hack to find out what randomly-assigned port it is listening on port = self.find_webstatus(m).getPortnum() self.port = port # insert an event req = BuildRequest("reason", sourcestamp.SourceStamp(), 'test_builder') build1 = base.Build([req]) bs = m.status.getBuilder("builder1").newBuild() bs.setReason("reason") bs.buildStarted(build1) step1 = BuildStep(name="setup") step1.setBuild(build1) bss = bs.addStepWithName("setup") step1.setStepStatus(bss) bss.stepStarted() log1 = step1.addLog("output") log1.addStdout(u"s\N{LATIN CAPITAL LETTER O WITH GRAVE}me stdout\n".encode("utf-8")) log1.finish() log2 = step1.addHTMLLog("error", "<html>ouch</html>") del log2 log3 = step1.addLog("big") log3.addStdout("big log\n") for i in range(1000): log3.addStdout("a" * 500) log3.addStderr("b" * 500) log3.finish() log4 = step1.addCompleteLog("bigcomplete", "big2 log\n" + "a" * 1*1000*1000) del log4 log5 = step1.addLog("mixed") log5.addHeader("header content") log5.addStdout("this is stdout content") log5.addStderr("errors go here") log5.addEntry(5, "non-standard content on channel 5") log5.addStderr(" and some trailing stderr") d1 = defer.maybeDeferred(step1.step_status.stepFinished, builder.SUCCESS) bs.buildFinished() return d1
def test_subscribe(self): self.basedir = "buildset/BuildSet/subscribe" self.create_master() db = self.master.db run = db.runInteractionNow ss = sourcestamp.SourceStamp(branch="branchy") ssid = run(lambda t: db.get_sourcestampid(ss, t)) d = defer.succeed(None) d.addCallback(self._setup_subscribe, ssid) d.addCallback(self._subscribe_test1) d.addCallback(self._setup_subscribe, ssid) d.addCallback(self._subscribe_test2) d.addCallback(self._setup_subscribe, ssid) d.addCallback(self._subscribe_test3) return d
def testTryUserpass(self): up = [("alice", "pw1"), ("bob", "pw2")] s = scheduler.Try_Userpass("try2", ["a", "b"], 0, userpass=up) self.addScheduler(s) port = s.getPort() config = { 'connect': 'pb', 'username': '******', 'passwd': 'pw1', 'master': "localhost:%d" % port, 'builders': ["a", "b"], } t = tryclient.Try(config) ss = sourcestamp.SourceStamp("branch1", "123", (1, "diff")) t.sourcestamp = ss d2 = self.master.d = defer.Deferred() d = t.deliverJob() d.addCallback(self._testTryUserpass_1, t, d2) return d
def testBuildSet(self): S = buildset.BuildSet a,b = FakeBuilder(), FakeBuilder() # two builds, the first one fails, the second one succeeds. The # waitUntilSuccess watcher fires as soon as the first one fails, # while the waitUntilFinished watcher doesn't fire until all builds # are complete. source = sourcestamp.SourceStamp() s = S(["a","b"], source, "forced build") s.start([a,b]) self.failUnlessEqual(len(a.requests), 1) self.failUnlessEqual(len(b.requests), 1) r1 = a.requests[0] self.failUnlessEqual(r1.reason, s.reason) self.failUnlessEqual(r1.source, s.source) st = s.status self.failUnlessEqual(st.getSourceStamp(), source) self.failUnlessEqual(st.getReason(), "forced build") self.failUnlessEqual(st.getBuilderNames(), ["a","b"]) self.failIf(st.isFinished()) brs = st.getBuildRequests() self.failUnlessEqual(len(brs), 2) res = [] d1 = s.waitUntilSuccess() d1.addCallback(lambda r: res.append(("success", r))) d2 = s.waitUntilFinished() d2.addCallback(lambda r: res.append(("finished", r))) self.failUnlessEqual(res, []) # the first build finishes here, with FAILURE builderstatus_a = builder.BuilderStatus("a") bsa = builder.BuildStatus(builderstatus_a, 1) bsa.setResults(builder.FAILURE) a.requests[0].finished(bsa) # any FAILURE flunks the BuildSet immediately, so the # waitUntilSuccess deferred fires right away. However, the # waitUntilFinished deferred must wait until all builds have # completed. self.failUnlessEqual(len(res), 1) self.failUnlessEqual(res[0][0], "success") bss = res[0][1] self.failUnless(interfaces.IBuildSetStatus(bss, None)) self.failUnlessEqual(bss.getResults(), builder.FAILURE) # here we finish the second build builderstatus_b = builder.BuilderStatus("b") bsb = builder.BuildStatus(builderstatus_b, 1) bsb.setResults(builder.SUCCESS) b.requests[0].finished(bsb) # .. which ought to fire the waitUntilFinished deferred self.failUnlessEqual(len(res), 2) self.failUnlessEqual(res[1][0], "finished") self.failUnlessEqual(res[1][1], bss) # and finish the BuildSet overall self.failUnless(st.isFinished()) self.failUnlessEqual(st.getResults(), builder.FAILURE)
def doBuild(self, buildername): brs = self.control.submitBuildSet([buildername], sourcestamp.SourceStamp(), "forced") return brs.waitUntilFinished()
def test_basic(self): self.basedir = "buildset/BuildSet/basic" self.create_master() db = self.master.db run = db.runInteractionNow # we must create all the things that go into a buildset #c1 = Change(who="brian", files=["foo.c", "subdir/bar.c"], # comments="first change", # revision="1234") #db.addChangeToDatabase(c1) ss = sourcestamp.SourceStamp(branch="branchy") ssid = run(lambda t: db.get_sourcestampid(ss, t)) props = Properties() props.setProperty("pname", "pvalue", "psource") bsid = run(lambda t: db.create_buildset(ssid, "reason", props, ["bn1", "bn2"], t)) mn, mi = "mastername", "incarnation" reqs = run( lambda t: db.get_unclaimed_buildrequests("bn1", 1, mn, mi, t)) self.failUnlessEqual(len(reqs), 1) self.failUnlessEqual(reqs[0].reason, "reason") self.failUnlessEqual(reqs[0].builderName, "bn1") #print reqs[0].properties #self.failUnlessEqual(reqs[0].properties["pname"], "pvalue") #BROKEN brids = db.get_buildrequestids_for_buildset(bsid) bn1_brid = brids["bn1"] bn2_brid = brids["bn2"] self.failUnlessEqual(bn1_brid, reqs[0].id) reqs2 = run( lambda t: db.get_unclaimed_buildrequests("bn2", 1, mn, mi, t)) self.failUnlessEqual(bn2_brid, reqs2[0].id) (successful, finished) = db.examine_buildset(bsid) self.failUnlessEqual(successful, None) self.failUnlessEqual(finished, False) bs = self.master.status.getBuildSets() self.failUnlessEqual(len(bs), 1) brs = bs[0].getBuilderNamesAndBuildRequests() self.failUnlessEqual(sorted(brs.keys()), ["bn1", "bn2"]) self.failUnlessEqual(sorted(bs[0].getBuilderNames()), ["bn1", "bn2"]) self.failUnlessEqual(len(bs[0].getBuildRequests()), 2) ss2 = bs[0].getSourceStamp() self.failUnlessEqual(ss2.branch, "branchy") self.failUnlessEqual(bs[0].getReason(), "reason") self.failUnlessEqual(bs[0].isFinished(), False) self.failUnlessEqual(bs[0].getResults(), None) db.retire_buildrequests([bn1_brid], SUCCESS) self.failUnlessEqual(db.examine_buildset(bsid), (None, False)) db.retire_buildrequests([bn2_brid], SUCCESS) self.failUnlessEqual(db.examine_buildset(bsid), (True, True)) bsid2 = run(lambda t: db.create_buildset(ssid, "reason", props, ["bn1", "bn2"], t)) brids2 = db.get_buildrequestids_for_buildset(bsid2) self.failUnlessEqual(db.examine_buildset(bsid2), (None, False)) db.retire_buildrequests([brids2["bn1"]], SUCCESS) self.failUnlessEqual(db.examine_buildset(bsid2), (None, False)) db.retire_buildrequests([brids2["bn2"]], FAILURE) self.failUnlessEqual(db.examine_buildset(bsid2), (False, True)) bsid3 = run(lambda t: db.create_buildset(ssid, "reason", props, ["bn1", "bn2"], t)) brids3 = db.get_buildrequestids_for_buildset(bsid3) self.failUnlessEqual(db.examine_buildset(bsid3), (None, False)) db.retire_buildrequests([brids3["bn1"]], FAILURE) self.failUnlessEqual(db.examine_buildset(bsid3), (False, False)) db.retire_buildrequests([brids3["bn2"]], SUCCESS) self.failUnlessEqual(db.examine_buildset(bsid3), (False, True))
def force(self, req): """ Overriden method from builders.StatusResourceBuilder. The only change to original behavior is that it sets 'clobber' value on the BuildRequest.properties.""" name = req.args.get("username", ["<unknown>"])[0] reason = req.args.get("comments", ["<no reason specified>"])[0] branch = req.args.get("branch", [""])[0] revision = req.args.get("revision", [""])[0] clobber = req.args.get("clobber", [False])[0] slavename = req.args.get("slavename", [False])[0] if clobber: clobber_str = ' (clobbered)' else: clobber_str = '' r = ("The web-page 'force build' button%s was pressed by %s: %s" % (clobber_str, name, reason)) message = ("web forcebuild of builder '%s', branch='%s', revision='%s'" ", clobber='%s'") log.msg( message % (self.builder_status.getName(), branch, revision, str(clobber))) if not self.builder_control: # TODO: tell the web user that their request was denied log.msg("but builder control is disabled") return Redirect("..") # keep weird stuff out of the branch and revision strings. TODO: # centralize this somewhere. if not re.match(r'^[\w\.\-\/]*$', branch): log.msg("bad branch '%s'" % branch) return Redirect("..") if not re.match(r'^[\w\.\-\/]*$', revision): log.msg("bad revision '%s'" % revision) return Redirect("..") if branch == "": branch = None if revision == "": revision = None # TODO: if we can authenticate that a particular User pushed the # button, use their name instead of None, so they'll be informed of # the results. s = sourcestamp.SourceStamp(branch=branch, revision=revision) props = process.properties.Properties() if clobber: props.setProperty("clobber", True, "Scheduler") if slavename: props.setProperty("slavename", slavename, "Scheduler") req = process.base.BuildRequest( r, s, builderName=self.builder_status.getName(), properties=props) try: self.builder_control.requestBuildSoon(req) except interfaces.NoSlaveError: # TODO: tell the web user that their request could not be # honored pass # Sends the user back to the waterfall page. return Redirect("../..")
def doBuild(self, buildername): br = base.BuildRequest("forced", sourcestamp.SourceStamp(), 'test_builder') d = br.waitUntilFinished() self.control.getBuilder(buildername).requestBuild(br) return d
def setUp(self): config = """ from buildbot.status import html from buildbot.process.factory import BasicBuildFactory from buildbot.buildslave import BuildSlave from buildbot.config import BuilderConfig f1 = BasicBuildFactory('cvsroot', 'cvsmodule') BuildmasterConfig = c = { 'slaves': [BuildSlave('bot1', 'passwd1')], 'schedulers': [], 'slavePortnum': 0, 'status': [html.WebStatus(http_port=0)], } c['builders'] = [ BuilderConfig(name='builder1', slavename='bot1', factory=f1), ] """ if os.path.exists("test_logfile"): shutil.rmtree("test_logfile") os.mkdir("test_logfile") self.master = m = ConfiguredMaster("test_logfile", config) m.startService() # hack to find out what randomly-assigned port it is listening on port = self.find_webstatus(m).getPortnum() self.port = port # insert an event req = base.BuildRequest("reason", sourcestamp.SourceStamp(), 'test_builder') build1 = base.Build([req]) bs = m.status.getBuilder("builder1").newBuild() bs.setReason("reason") bs.buildStarted(build1) step1 = BuildStep(name="setup") step1.setBuild(build1) bss = bs.addStepWithName("setup") step1.setStepStatus(bss) bss.stepStarted() log1 = step1.addLog("output") log1.addStdout(u"sÒme stdout\n") log1.finish() log2 = step1.addHTMLLog("error", "<html>ouch</html>") log3 = step1.addLog("big") log3.addStdout("big log\n") for i in range(1000): log3.addStdout("a" * 500) log3.addStderr("b" * 500) log3.finish() log4 = step1.addCompleteLog("bigcomplete", "big2 log\n" + "a" * 1 * 1000 * 1000) log5 = step1.addLog("mixed") log5.addHeader("header content") log5.addStdout("this is stdout content") log5.addStderr("errors go here") log5.addEntry(5, "non-standard content on channel 5") log5.addStderr(" and some trailing stderr") d = defer.maybeDeferred(step1.step_status.stepFinished, builder.SUCCESS) bs.buildFinished() return d
def create_status(self): for i in range(5): if i % 2 == 0: branch = "release" else: branch = None c = Change("user", ["foo.c"] * i, "see ticket #%i" % i, revision=str(42 + i), when=0.1 * i, branch=branch) self.master.change_svc.addChange(c) ss = sourcestamp.SourceStamp(revision=42) req = BuildRequest("reason", ss, 'test_builder') build1 = base.Build([req]) bs = self.master.status.getBuilder("builder1").newBuild() bs.setReason("reason") bs.buildStarted(build1) bs.setSourceStamp(ss) bs.setProperty("revision", "42", "testcase") bs.setProperty("got_revision", "47", "testcase") bs.setProperty("branch", "release", "testcase") step1 = BuildStep(name="setup") step1.setBuild(build1) bss = bs.addStepWithName("setup") step1.setStepStatus(bss) bss.stepStarted() step2 = BuildStep(name="build") step2.setBuild(build1) bss = bs.addStepWithName("build") step2.setStepStatus(bss) bss.stepStarted() step1.addURL("url1", "http://logurl.net/1") step1.addURL("url2", "http://logurl.net/2") step1.addURL("url3", "http://logurl.net/3") log1 = step1.addLog("output") log1.addStdout( u"some stdout\n") # FIXME: Unicode here fails validation log1.finish() # this has to validate too for the test to pass log2 = step1.addHTMLLog( "error", ''' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head><title>Teh Log</title></head> <body>Aaaiight</body> </html>''') del log2 log3 = step1.addLog("big") log3.addStdout("somewhat big log\n") for i in range(50): log3.addStdout("a" * 50 + "\n") log3.addStderr("b" * 50 + "\n") log3.finish() log5 = step1.addLog("mixed") log5.addHeader("header content") log5.addStdout("this is stdout content") log5.addStderr("errors go here") log5.addEntry(5, "non-standard content on channel 5") log5.addStderr(" and some trailing stderr") d = defer.succeed(None) for i in range(1, 3): ss = sourcestamp.SourceStamp(revision=42 + i, branch='release') req = BuildRequest("reason", ss, 'test_builder') build = base.Build([req] * i) bs = self.master.status.getBuilder("builder%i" % i).newBuild() bs.setReason("reason") bs.buildStarted(build) bs.setSourceStamp(ss) s = BuildStep(name="setup") s.setBuild(build1) bss = bs.addStepWithName("setup") s.setStepStatus(bss) bss.stepStarted() log = s.addLog("stdio") log.finish() d.chainDeferred( defer.maybeDeferred(step1.step_status.stepFinished, builder.SUCCESS)) bs.buildFinished() return d