Index: third_party/buildbot_7_12/buildbot/test/test_locks.py |
diff --git a/third_party/buildbot_7_12/buildbot/test/test_locks.py b/third_party/buildbot_7_12/buildbot/test/test_locks.py |
deleted file mode 100644 |
index 93e4b1dfb737cab888b4c0b97990d91e29853855..0000000000000000000000000000000000000000 |
--- a/third_party/buildbot_7_12/buildbot/test/test_locks.py |
+++ /dev/null |
@@ -1,568 +0,0 @@ |
-# -*- test-case-name: buildbot.test.test_locks -*- |
- |
-import random |
- |
-from twisted.trial import unittest |
-from twisted.internet import defer, reactor |
- |
-from buildbot import master |
-from buildbot.steps import dummy |
-from buildbot.sourcestamp import SourceStamp |
-from buildbot.process.base import BuildRequest |
-from buildbot.test.runutils import RunMixin |
-from buildbot import locks |
- |
-def claimHarder(lock, owner, la): |
- """Return a Deferred that will fire when the lock is claimed. Keep trying |
- until we succeed.""" |
- if lock.isAvailable(la): |
- #print "claimHarder(%s): claiming" % owner |
- lock.claim(owner, la) |
- return defer.succeed(lock) |
- #print "claimHarder(%s): waiting" % owner |
- d = lock.waitUntilMaybeAvailable(owner, la) |
- d.addCallback(claimHarder, owner, la) |
- return d |
- |
-def hold(lock, owner, la, mode="now"): |
- if mode == "now": |
- lock.release(owner, la) |
- elif mode == "very soon": |
- reactor.callLater(0, lock.release, owner, la) |
- elif mode == "soon": |
- reactor.callLater(0.1, lock.release, owner, la) |
- |
-class Unit(unittest.TestCase): |
- def testNowCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- return self._testNow(la) |
- |
- def testNowExclusive(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'exclusive') |
- return self._testNow(la) |
- |
- def _testNow(self, la): |
- l = locks.BaseLock("name") |
- self.failUnless(l.isAvailable(la)) |
- l.claim("owner1", la) |
- self.failIf(l.isAvailable(la)) |
- l.release("owner1", la) |
- self.failUnless(l.isAvailable(la)) |
- |
- def testNowMixed1(self): |
- """ Test exclusive is not possible when a counting has the lock """ |
- lid = locks.MasterLock('dummy') |
- lac = locks.LockAccess(lid, 'counting') |
- lae = locks.LockAccess(lid, 'exclusive') |
- l = locks.BaseLock("name", maxCount=2) |
- self.failUnless(l.isAvailable(lac)) |
- l.claim("count-owner", lac) |
- self.failIf(l.isAvailable(lae)) |
- l.release("count-owner", lac) |
- self.failUnless(l.isAvailable(lac)) |
- |
- def testNowMixed2(self): |
- """ Test counting is not possible when an exclsuive has the lock """ |
- lid = locks.MasterLock('dummy') |
- lac = locks.LockAccess(lid, 'counting') |
- lae = locks.LockAccess(lid, 'exclusive') |
- l = locks.BaseLock("name", maxCount=2) |
- self.failUnless(l.isAvailable(lae)) |
- l.claim("count-owner", lae) |
- self.failIf(l.isAvailable(lac)) |
- l.release("count-owner", lae) |
- self.failUnless(l.isAvailable(lae)) |
- |
- def testLaterCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- return self._testLater(la) |
- |
- def testLaterExclusive(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'exclusive') |
- return self._testLater(la) |
- |
- def _testLater(self, la): |
- lock = locks.BaseLock("name") |
- d = claimHarder(lock, "owner1", la) |
- d.addCallback(lambda lock: lock.release("owner1", la)) |
- return d |
- |
- def testCompetitionCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- return self._testCompetition(la) |
- |
- def testCompetitionExclusive(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'exclusive') |
- return self._testCompetition(la) |
- |
- def _testCompetition(self, la): |
- lock = locks.BaseLock("name") |
- d = claimHarder(lock, "owner1", la) |
- d.addCallback(self._claim1, la) |
- return d |
- def _claim1(self, lock, la): |
- # we should have claimed it by now |
- self.failIf(lock.isAvailable(la)) |
- # now set up two competing owners. We don't know which will get the |
- # lock first. |
- d2 = claimHarder(lock, "owner2", la) |
- d2.addCallback(hold, "owner2", la, "now") |
- d3 = claimHarder(lock, "owner3", la) |
- d3.addCallback(hold, "owner3", la, "soon") |
- dl = defer.DeferredList([d2,d3]) |
- dl.addCallback(self._cleanup, lock, la) |
- # and release the lock in a moment |
- reactor.callLater(0.1, lock.release, "owner1", la) |
- return dl |
- |
- def _cleanup(self, res, lock, la): |
- d = claimHarder(lock, "cleanup", la) |
- d.addCallback(lambda lock: lock.release("cleanup", la)) |
- return d |
- |
- def testRandomCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- return self._testRandom(la) |
- |
- def testRandomExclusive(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'exclusive') |
- return self._testRandom(la) |
- |
- def _testRandom(self, la): |
- lock = locks.BaseLock("name") |
- dl = [] |
- for i in range(100): |
- owner = "owner%d" % i |
- mode = random.choice(["now", "very soon", "soon"]) |
- d = claimHarder(lock, owner, la) |
- d.addCallback(hold, owner, la, mode) |
- dl.append(d) |
- d = defer.DeferredList(dl) |
- d.addCallback(self._cleanup, lock, la) |
- return d |
- |
-class Multi(unittest.TestCase): |
- def testNowCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- lock = locks.BaseLock("name", 2) |
- self.failUnless(lock.isAvailable(la)) |
- lock.claim("owner1", la) |
- self.failUnless(lock.isAvailable(la)) |
- lock.claim("owner2", la) |
- self.failIf(lock.isAvailable(la)) |
- lock.release("owner1", la) |
- self.failUnless(lock.isAvailable(la)) |
- lock.release("owner2", la) |
- self.failUnless(lock.isAvailable(la)) |
- |
- def testLaterCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- lock = locks.BaseLock("name", 2) |
- lock.claim("owner1", la) |
- lock.claim("owner2", la) |
- d = claimHarder(lock, "owner3", la) |
- d.addCallback(lambda lock: lock.release("owner3", la)) |
- lock.release("owner2", la) |
- lock.release("owner1", la) |
- return d |
- |
- def _cleanup(self, res, lock, count, la): |
- dl = [] |
- for i in range(count): |
- d = claimHarder(lock, "cleanup%d" % i, la) |
- dl.append(d) |
- d2 = defer.DeferredList(dl) |
- # once all locks are claimed, we know that any previous owners have |
- # been flushed out |
- def _release(res): |
- for i in range(count): |
- lock.release("cleanup%d" % i, la) |
- d2.addCallback(_release) |
- return d2 |
- |
- def testRandomCounting(self): |
- lid = locks.MasterLock('dummy') |
- la = locks.LockAccess(lid, 'counting') |
- COUNT = 5 |
- lock = locks.BaseLock("name", COUNT) |
- dl = [] |
- for i in range(100): |
- owner = "owner%d" % i |
- mode = random.choice(["now", "very soon", "soon"]) |
- d = claimHarder(lock, owner, la) |
- def _check(lock): |
- self.failIf(len(lock.owners) > COUNT) |
- return lock |
- d.addCallback(_check) |
- d.addCallback(hold, owner, la, mode) |
- dl.append(d) |
- d = defer.DeferredList(dl) |
- d.addCallback(self._cleanup, lock, COUNT, la) |
- return d |
- |
-class Dummy: |
- pass |
- |
-def slave(slavename): |
- slavebuilder = Dummy() |
- slavebuilder.slave = Dummy() |
- slavebuilder.slave.slavename = slavename |
- return slavebuilder |
- |
-class MakeRealLock(unittest.TestCase): |
- |
- def make(self, lockid): |
- return lockid.lockClass(lockid) |
- |
- def testMaster(self): |
- mid1 = locks.MasterLock("name1") |
- mid2 = locks.MasterLock("name1") |
- mid3 = locks.MasterLock("name3") |
- mid4 = locks.MasterLock("name1", 3) |
- self.failUnlessEqual(mid1, mid2) |
- self.failIfEqual(mid1, mid3) |
- # they should all be hashable |
- d = {mid1: 1, mid2: 2, mid3: 3, mid4: 4} |
- |
- l1 = self.make(mid1) |
- self.failUnlessEqual(l1.name, "name1") |
- self.failUnlessEqual(l1.maxCount, 1) |
- self.failUnlessIdentical(l1.getLock(slave("slave1")), l1) |
- l4 = self.make(mid4) |
- self.failUnlessEqual(l4.name, "name1") |
- self.failUnlessEqual(l4.maxCount, 3) |
- self.failUnlessIdentical(l4.getLock(slave("slave1")), l4) |
- |
- def testSlave(self): |
- sid1 = locks.SlaveLock("name1") |
- sid2 = locks.SlaveLock("name1") |
- sid3 = locks.SlaveLock("name3") |
- sid4 = locks.SlaveLock("name1", maxCount=3) |
- mcfs = {"bigslave": 4, "smallslave": 1} |
- sid5 = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs) |
- mcfs2 = {"bigslave": 4, "smallslave": 1} |
- sid5a = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs2) |
- mcfs3 = {"bigslave": 1, "smallslave": 99} |
- sid5b = locks.SlaveLock("name1", maxCount=3, maxCountForSlave=mcfs3) |
- self.failUnlessEqual(sid1, sid2) |
- self.failIfEqual(sid1, sid3) |
- self.failIfEqual(sid1, sid4) |
- self.failIfEqual(sid1, sid5) |
- self.failUnlessEqual(sid5, sid5a) |
- self.failIfEqual(sid5a, sid5b) |
- # they should all be hashable |
- d = {sid1: 1, sid2: 2, sid3: 3, sid4: 4, sid5: 5, sid5a: 6, sid5b: 7} |
- |
- l1 = self.make(sid1) |
- self.failUnlessEqual(l1.name, "name1") |
- self.failUnlessEqual(l1.maxCount, 1) |
- l1s1 = l1.getLock(slave("slave1")) |
- self.failIfIdentical(l1s1, l1) |
- |
- l4 = self.make(sid4) |
- self.failUnlessEqual(l4.maxCount, 3) |
- l4s1 = l4.getLock(slave("slave1")) |
- self.failUnlessEqual(l4s1.maxCount, 3) |
- |
- l5 = self.make(sid5) |
- l5s1 = l5.getLock(slave("bigslave")) |
- l5s2 = l5.getLock(slave("smallslave")) |
- l5s3 = l5.getLock(slave("unnamedslave")) |
- self.failUnlessEqual(l5s1.maxCount, 4) |
- self.failUnlessEqual(l5s2.maxCount, 1) |
- self.failUnlessEqual(l5s3.maxCount, 3) |
- |
-class GetLock(unittest.TestCase): |
- def testGet(self): |
- # the master.cfg file contains "lock ids", which are instances of |
- # MasterLock and SlaveLock but which are not actually Locks per se. |
- # When the build starts, these markers are turned into RealMasterLock |
- # and RealSlaveLock instances. This insures that any builds running |
- # on slaves that were unaffected by the config change are still |
- # referring to the same Lock instance as new builds by builders that |
- # *were* affected by the change. There have been bugs in the past in |
- # which this didn't happen, and the Locks were bypassed because half |
- # the builders were using one incarnation of the lock while the other |
- # half were using a separate (but equal) incarnation. |
- # |
- # Changing the lock id in any way should cause it to be replaced in |
- # the BotMaster. This will result in a couple of funky artifacts: |
- # builds in progress might pay attention to a different lock, so we |
- # might bypass the locking for the duration of a couple builds. |
- # There's also the problem of old Locks lingering around in |
- # BotMaster.locks, but they're small and shouldn't really cause a |
- # problem. |
- |
- b = master.BotMaster() |
- l1 = locks.MasterLock("one") |
- l1a = locks.MasterLock("one") |
- l2 = locks.MasterLock("one", maxCount=4) |
- |
- rl1 = b.getLockByID(l1) |
- rl2 = b.getLockByID(l1a) |
- self.failUnlessIdentical(rl1, rl2) |
- rl3 = b.getLockByID(l2) |
- self.failIfIdentical(rl1, rl3) |
- |
- s1 = locks.SlaveLock("one") |
- s1a = locks.SlaveLock("one") |
- s2 = locks.SlaveLock("one", maxCount=4) |
- s3 = locks.SlaveLock("one", maxCount=4, |
- maxCountForSlave={"a":1, "b":2}) |
- s3a = locks.SlaveLock("one", maxCount=4, |
- maxCountForSlave={"a":1, "b":2}) |
- s4 = locks.SlaveLock("one", maxCount=4, |
- maxCountForSlave={"a":4, "b":4}) |
- |
- rl1 = b.getLockByID(s1) |
- rl2 = b.getLockByID(s1a) |
- self.failUnlessIdentical(rl1, rl2) |
- rl3 = b.getLockByID(s2) |
- self.failIfIdentical(rl1, rl3) |
- rl4 = b.getLockByID(s3) |
- self.failIfIdentical(rl1, rl4) |
- self.failIfIdentical(rl3, rl4) |
- rl5 = b.getLockByID(s3a) |
- self.failUnlessIdentical(rl4, rl5) |
- rl6 = b.getLockByID(s4) |
- self.failIfIdentical(rl5, rl6) |
- |
- |
- |
-class LockStep(dummy.Dummy): |
- def start(self): |
- number = self.build.requests[0].number |
- self.build.requests[0].events.append(("start", number)) |
- dummy.Dummy.start(self) |
- def done(self): |
- number = self.build.requests[0].number |
- self.build.requests[0].events.append(("done", number)) |
- dummy.Dummy.done(self) |
- |
-config_1 = """ |
-from buildbot import locks |
-from buildbot.process import factory |
-from buildbot.buildslave import BuildSlave |
-from buildbot.config import BuilderConfig |
-s = factory.s |
-from buildbot.test.test_locks import LockStep |
- |
-BuildmasterConfig = c = {} |
-c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit')] |
-c['schedulers'] = [] |
-c['slavePortnum'] = 0 |
- |
-first_lock = locks.SlaveLock('first') |
-second_lock = locks.MasterLock('second') |
-f1 = factory.BuildFactory([s(LockStep, timeout=2, locks=[first_lock])]) |
-f2 = factory.BuildFactory([s(LockStep, timeout=3, locks=[second_lock])]) |
-f3 = factory.BuildFactory([s(LockStep, timeout=2, locks=[])]) |
- |
-b1a = BuilderConfig(name='full1a', slavename='bot1', factory=f1) |
-b1b = BuilderConfig(name='full1b', slavename='bot1', factory=f1) |
-b1c = BuilderConfig(name='full1c', slavename='bot1', factory=f3, |
- locks=[first_lock, second_lock]) |
-b1d = BuilderConfig(name='full1d', slavename='bot1', factory=f2) |
- |
-b2a = BuilderConfig(name='full2a', slavename='bot2', factory=f1) |
-b2b = BuilderConfig(name='full2b', slavename='bot2', factory=f3, |
- locks=[second_lock]) |
-c['builders'] = [b1a, b1b, b1c, b1d, b2a, b2b] |
-""" |
- |
-config_1a = config_1 + \ |
-""" |
-b1b = BuilderConfig(name='full1b', builddir='1B', slavename='bot1', factory=f1) |
-c['builders'] = [b1a, b1b, b1c, b1d, b2a, b2b] |
-""" |
- |
- |
-class Locks(RunMixin, unittest.TestCase): |
- def setUp(self): |
- N = 'test_builder' |
- RunMixin.setUp(self) |
- self.req1 = req1 = BuildRequest("forced build", SourceStamp(), N) |
- req1.number = 1 |
- self.req2 = req2 = BuildRequest("forced build", SourceStamp(), N) |
- req2.number = 2 |
- self.req3 = req3 = BuildRequest("forced build", SourceStamp(), N) |
- req3.number = 3 |
- req1.events = req2.events = req3.events = self.events = [] |
- d = self.master.loadConfig(config_1) |
- d.addCallback(lambda res: self.master.startService()) |
- d.addCallback(lambda res: self.connectSlave( |
- ["full1a", "full1b", "full1c", "full1d"], |
- "bot1")) |
- d.addCallback(lambda res: self.connectSlave(["full2a", "full2b"], "bot2")) |
- return d |
- |
- def testLock1(self): |
- self.control.getBuilder("full1a").requestBuild(self.req1) |
- self.control.getBuilder("full1b").requestBuild(self.req2) |
- d = defer.DeferredList([self.req1.waitUntilFinished(), |
- self.req2.waitUntilFinished()]) |
- d.addCallback(self._testLock1_1) |
- return d |
- |
- def _testLock1_1(self, res): |
- # full1a should complete its step before full1b starts it |
- self.failUnlessEqual(self.events, |
- [("start", 1), ("done", 1), |
- ("start", 2), ("done", 2)]) |
- |
- def dont_testLock1a(self): ## disabled -- test itself is buggy |
- # just like testLock1, but we reload the config file first, with a |
- # change that causes full1b to be changed. This tickles a design bug |
- # in which full1a and full1b wind up with distinct Lock instances. |
- d = self.master.loadConfig(config_1a) |
- d.addCallback(self._testLock1a_1) |
- return d |
- def _testLock1a_1(self, res): |
- self.control.getBuilder("full1a").requestBuild(self.req1) |
- self.control.getBuilder("full1b").requestBuild(self.req2) |
- d = defer.DeferredList([self.req1.waitUntilFinished(), |
- self.req2.waitUntilFinished()]) |
- d.addCallback(self._testLock1a_2) |
- return d |
- |
- def _testLock1a_2(self, res): |
- # full1a should complete its step before full1b starts it |
- self.failUnlessEqual(self.events, |
- [("start", 1), ("done", 1), |
- ("start", 2), ("done", 2)]) |
- |
- def testLock2(self): |
- # two builds run on separate slaves with slave-scoped locks should |
- # not interfere |
- self.control.getBuilder("full1a").requestBuild(self.req1) |
- self.control.getBuilder("full2a").requestBuild(self.req2) |
- d = defer.DeferredList([self.req1.waitUntilFinished(), |
- self.req2.waitUntilFinished()]) |
- d.addCallback(self._testLock2_1) |
- return d |
- |
- def _testLock2_1(self, res): |
- # full2a should start its step before full1a finishes it. They run on |
- # different slaves, however, so they might start in either order. |
- self.failUnless(self.events[:2] == [("start", 1), ("start", 2)] or |
- self.events[:2] == [("start", 2), ("start", 1)]) |
- |
- def dont_testLock3(self): ## disabled -- test fails sporadically |
- # two builds run on separate slaves with master-scoped locks should |
- # not overlap |
- self.control.getBuilder("full1c").requestBuild(self.req1) |
- self.control.getBuilder("full2b").requestBuild(self.req2) |
- d = defer.DeferredList([self.req1.waitUntilFinished(), |
- self.req2.waitUntilFinished()]) |
- d.addCallback(self._testLock3_1) |
- return d |
- |
- def _testLock3_1(self, res): |
- # full2b should not start until after full1c finishes. The builds run |
- # on different slaves, so we can't really predict which will start |
- # first. The important thing is that they don't overlap. |
- self.failUnless(self.events == [("start", 1), ("done", 1), |
- ("start", 2), ("done", 2)] |
- or self.events == [("start", 2), ("done", 2), |
- ("start", 1), ("done", 1)] |
- ) |
- |
- # This test has been disabled due to flakeyness/intermittentness |
-# def testLock4(self): |
-# self.control.getBuilder("full1a").requestBuild(self.req1) |
-# self.control.getBuilder("full1c").requestBuild(self.req2) |
-# self.control.getBuilder("full1d").requestBuild(self.req3) |
-# d = defer.DeferredList([self.req1.waitUntilFinished(), |
-# self.req2.waitUntilFinished(), |
-# self.req3.waitUntilFinished()]) |
-# d.addCallback(self._testLock4_1) |
-# return d |
-# |
-# def _testLock4_1(self, res): |
-# # full1a starts, then full1d starts (because they do not interfere). |
-# # Once both are done, full1c can run. |
-# self.failUnlessEqual(self.events, |
-# [("start", 1), ("start", 3), |
-# ("done", 1), ("done", 3), |
-# ("start", 2), ("done", 2)]) |
- |
-class BuilderLocks(RunMixin, unittest.TestCase): |
- config = """\ |
-from buildbot import locks |
-from buildbot.process import factory |
-from buildbot.buildslave import BuildSlave |
-from buildbot.config import BuilderConfig |
-s = factory.s |
-from buildbot.test.test_locks import LockStep |
- |
-BuildmasterConfig = c = {} |
-c['slaves'] = [BuildSlave('bot1', 'sekrit'), BuildSlave('bot2', 'sekrit')] |
-c['schedulers'] = [] |
-c['slavePortnum'] = 0 |
- |
-master_lock = locks.MasterLock('master', maxCount=2) |
-f_excl = factory.BuildFactory([s(LockStep, timeout=0, |
- locks=[master_lock.access("exclusive")])]) |
-f_count = factory.BuildFactory([s(LockStep, timeout=0, |
- locks=[master_lock])]) |
- |
-slaves = ['bot1', 'bot2'] |
-c['builders'] = [ |
- BuilderConfig(name='excl_A', slavenames=slaves, factory=f_excl), |
- BuilderConfig(name='excl_B', slavenames=slaves, factory=f_excl), |
- BuilderConfig(name='count_A', slavenames=slaves, factory=f_count), |
- BuilderConfig(name='count_B', slavenames=slaves, factory=f_count), |
-] |
-""" |
- |
- def setUp(self): |
- N = 'test_builder' |
- RunMixin.setUp(self) |
- self.reqs = [BuildRequest("forced build", SourceStamp(), N) |
- for i in range(4)] |
- self.events = [] |
- for i in range(4): |
- self.reqs[i].number = i |
- self.reqs[i].events = self.events |
- d = self.master.loadConfig(self.config) |
- d.addCallback(lambda res: self.master.startService()) |
- d.addCallback(lambda res: self.connectSlave( |
- ["excl_A", "excl_B", "count_A", "count_B"], "bot1")) |
- d.addCallback(lambda res: self.connectSlave( |
- ["excl_A", "excl_B", "count_A", "count_B"], "bot2")) |
- return d |
- |
- def testOrder(self): |
- self.control.getBuilder("excl_A").requestBuild(self.reqs[0]) |
- self.control.getBuilder("excl_B").requestBuild(self.reqs[1]) |
- self.control.getBuilder("count_A").requestBuild(self.reqs[2]) |
- self.control.getBuilder("count_B").requestBuild(self.reqs[3]) |
- d = defer.DeferredList([r.waitUntilFinished() |
- for r in self.reqs]) |
- d.addCallback(self._testOrder) |
- return d |
- |
- def _testOrder(self, res): |
- # excl_A and excl_B cannot overlap with any other steps. |
- self.assert_(("start", 0) in self.events) |
- self.assert_(("done", 0) in self.events) |
- self.assert_(self.events.index(("start", 0)) + 1 == |
- self.events.index(("done", 0))) |
- |
- self.assert_(("start", 1) in self.events) |
- self.assert_(("done", 1) in self.events) |
- self.assert_(self.events.index(("start", 1)) + 1 == |
- self.events.index(("done", 1))) |
- |
- # FIXME: We really want to test that count_A and count_B were |
- # overlapped, but don't have a reliable way to do this. |