4 # Copyright (C) 2009, 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the mcpu module"""
28 from ganeti import mcpu
29 from ganeti import opcodes
30 from ganeti import cmdlib
31 from ganeti import locking
32 from ganeti import constants
33 from ganeti.constants import \
34 LOCK_ATTEMPTS_TIMEOUT, \
35 LOCK_ATTEMPTS_MAXWAIT, \
41 REQ_BGL_WHITELIST = frozenset([
42 opcodes.OpClusterActivateMasterIp,
43 opcodes.OpClusterDeactivateMasterIp,
44 opcodes.OpClusterDestroy,
45 opcodes.OpClusterPostInit,
46 opcodes.OpClusterRename,
47 opcodes.OpInstanceRename,
50 opcodes.OpTestAllocator,
54 class TestLockAttemptTimeoutStrategy(unittest.TestCase):
55 def testConstants(self):
56 tpa = mcpu.LockAttemptTimeoutStrategy._TIMEOUT_PER_ATTEMPT
57 self.assert_(len(tpa) > LOCK_ATTEMPTS_TIMEOUT / LOCK_ATTEMPTS_MAXWAIT)
58 self.assert_(sum(tpa) >= LOCK_ATTEMPTS_TIMEOUT)
60 self.assertTrue(LOCK_ATTEMPTS_TIMEOUT >= 1800,
61 msg="Waiting less than half an hour per priority")
62 self.assertTrue(LOCK_ATTEMPTS_TIMEOUT <= 3600,
63 msg="Waiting more than an hour per priority")
66 strat = mcpu.LockAttemptTimeoutStrategy(_random_fn=lambda: 0.5,
70 for i in range(len(strat._TIMEOUT_PER_ATTEMPT)):
71 timeout = strat.NextAttempt()
72 self.assert_(timeout is not None)
74 self.assert_(timeout <= LOCK_ATTEMPTS_MAXWAIT)
75 self.assert_(timeout >= LOCK_ATTEMPTS_MINWAIT)
76 self.assert_(prev is None or timeout >= prev)
81 self.assert_(strat.NextAttempt() is None)
84 class TestDispatchTable(unittest.TestCase):
86 for opcls in opcodes.OP_MAPPING.values():
89 self.assertTrue(opcls in mcpu.Processor.DISPATCH_TABLE,
90 msg="%s missing handler class" % opcls)
92 # Check against BGL whitelist
93 lucls = mcpu.Processor.DISPATCH_TABLE[opcls]
95 self.assertTrue(opcls in REQ_BGL_WHITELIST,
96 msg=("%s not whitelisted for BGL" % opcls.OP_ID))
98 self.assertFalse(opcls in REQ_BGL_WHITELIST,
99 msg=("%s whitelisted for BGL, but doesn't use it" %
103 class TestProcessResult(unittest.TestCase):
106 self._count = itertools.count(200)
108 def _Submit(self, jobs):
109 job_ids = [self._count.next() for _ in jobs]
110 self._submitted.extend(zip(job_ids, jobs))
113 def testNoJobs(self):
114 for i in [object(), [], False, True, None, 1, 929, {}]:
115 self.assertEqual(mcpu._ProcessResult(NotImplemented, NotImplemented, i),
118 def testDefaults(self):
119 src = opcodes.OpTestDummy()
121 res = mcpu._ProcessResult(self._Submit, src, cmdlib.ResultWithJobs([[
122 opcodes.OpTestDelay(),
123 opcodes.OpTestDelay(),
125 opcodes.OpTestDelay(),
128 self.assertEqual(res, {
129 constants.JOB_IDS_KEY: [200, 201],
132 (_, (op1, op2)) = self._submitted.pop(0)
133 (_, (op3, )) = self._submitted.pop(0)
134 self.assertRaises(IndexError, self._submitted.pop)
136 for op in [op1, op2, op3]:
137 self.assertTrue("OP_TEST_DUMMY" in op.comment)
138 self.assertFalse(hasattr(op, "priority"))
139 self.assertFalse(hasattr(op, "debug_level"))
141 def testParams(self):
142 src = opcodes.OpTestDummy(priority=constants.OP_PRIO_HIGH,
145 res = mcpu._ProcessResult(self._Submit, src, cmdlib.ResultWithJobs([[
146 opcodes.OpTestDelay(priority=constants.OP_PRIO_LOW),
148 opcodes.OpTestDelay(comment="foobar", debug_level=10),
149 ]], other=True, value=range(10)))
151 self.assertEqual(res, {
152 constants.JOB_IDS_KEY: [200, 201],
157 (_, (op1, )) = self._submitted.pop(0)
158 (_, (op2, )) = self._submitted.pop(0)
159 self.assertRaises(IndexError, self._submitted.pop)
161 self.assertEqual(op1.priority, constants.OP_PRIO_LOW)
162 self.assertTrue("OP_TEST_DUMMY" in op1.comment)
163 self.assertEqual(op1.debug_level, 3)
165 self.assertEqual(op2.priority, constants.OP_PRIO_HIGH)
166 self.assertEqual(op2.comment, "foobar")
167 self.assertEqual(op2.debug_level, 3)
170 class _FakeLuWithLocks:
171 def __init__(self, needed_locks, share_locks):
172 self.needed_locks = needed_locks
173 self.share_locks = share_locks
177 def __init__(self, owning_nal):
178 self._owning_nal = owning_nal
180 def check_owned(self, level, names):
181 assert level == locking.LEVEL_NODE_ALLOC
182 assert names == locking.NAL
183 return self._owning_nal
185 def owning_all(self, level):
189 class TestVerifyLocks(unittest.TestCase):
190 def testNoLocks(self):
191 lu = _FakeLuWithLocks({}, {})
192 glm = _FakeGlm(False)
193 mcpu._VerifyLocks(lu, glm,
194 _mode_whitelist=NotImplemented,
195 _nal_whitelist=NotImplemented)
197 def testNotAllSameMode(self):
198 for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
199 lu = _FakeLuWithLocks({
203 locking.LEVEL_NODE_ALLOC: 0,
205 glm = _FakeGlm(False)
206 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[], _nal_whitelist=[])
208 def testDifferentMode(self):
209 for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
210 lu = _FakeLuWithLocks({
214 locking.LEVEL_NODE_ALLOC: 1,
216 glm = _FakeGlm(False)
218 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[], _nal_whitelist=[])
219 except AssertionError, err:
220 self.assertTrue("using the same mode as nodes" in str(err))
222 self.fail("Exception not raised")
224 # Once more with the whitelist
225 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[_FakeLuWithLocks],
228 def testSameMode(self):
229 for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
230 lu = _FakeLuWithLocks({
232 locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
235 locking.LEVEL_NODE_ALLOC: 1,
240 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[_FakeLuWithLocks],
242 except AssertionError, err:
243 self.assertTrue("whitelisted to use different modes" in str(err))
245 self.fail("Exception not raised")
247 # Once more without the whitelist
248 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[], _nal_whitelist=[])
250 def testAllWithoutAllocLock(self):
251 for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
252 lu = _FakeLuWithLocks({
253 level: locking.ALL_SET,
256 locking.LEVEL_NODE_ALLOC: 0,
258 glm = _FakeGlm(False)
260 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[], _nal_whitelist=[])
261 except AssertionError, err:
262 self.assertTrue("allocation lock must be used if" in str(err))
264 self.fail("Exception not raised")
266 # Once more with the whitelist
267 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[],
268 _nal_whitelist=[_FakeLuWithLocks])
270 def testAllWithAllocLock(self):
271 for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
272 lu = _FakeLuWithLocks({
273 level: locking.ALL_SET,
274 locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
277 locking.LEVEL_NODE_ALLOC: 0,
282 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[],
283 _nal_whitelist=[_FakeLuWithLocks])
284 except AssertionError, err:
285 self.assertTrue("whitelisted for not acquiring" in str(err))
287 self.fail("Exception not raised")
289 # Once more without the whitelist
290 mcpu._VerifyLocks(lu, glm, _mode_whitelist=[], _nal_whitelist=[])
293 if __name__ == "__main__":
294 testutils.GanetiTestProgram()