Improve mocks and add a unit test to test this case.
Signed-off-by: Brian Foley <[email protected]>
---
lib/mcpu.py | 4 +--
test/py/ganeti.mcpu_unittest.py | 35 +++++++++++++++++++++++
test/py/mocks.py | 61 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/lib/mcpu.py b/lib/mcpu.py
index 689b89c..2255cec 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -538,9 +538,9 @@ class Processor(object):
try:
result = self._ExecLU(lu)
except errors.OpPrereqError, err:
- (_, ecode) = err.args
- if ecode != errors.ECODE_TEMP_NORES:
+ if len(err.args) < 2 or err.args[1] != errors.ECODE_TEMP_NORES:
raise
+
logging.debug("Temporarily out of resources; will retry internally")
try:
lu.PrepareRetry(self.Log)
diff --git a/test/py/ganeti.mcpu_unittest.py b/test/py/ganeti.mcpu_unittest.py
index 18fabd8..796c2ba 100755
--- a/test/py/ganeti.mcpu_unittest.py
+++ b/test/py/ganeti.mcpu_unittest.py
@@ -33,12 +33,16 @@
import unittest
import itertools
+import mocks
+from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock
from ganeti import compat
from ganeti import mcpu
from ganeti import opcodes
from ganeti import cmdlib
from ganeti import locking
+from ganeti import ht
+from ganeti import errors
from ganeti import constants
from ganeti.constants import \
LOCK_ATTEMPTS_TIMEOUT, \
@@ -175,6 +179,37 @@ class TestProcessResult(unittest.TestCase):
self.assertEqual(op2.comment, "foobar")
self.assertEqual(op2.debug_level, 3)
+class TestExecLU(unittest.TestCase):
+ class OpTest(opcodes.OpCode):
+ OP_DSC_FIELD = "data"
+ OP_PARAMS = [
+ ("data", ht.NoDefault, ht.TString, None),
+ ]
+
+ def setUp(self):
+ self.ctx = mocks.FakeContext()
+ self.cfg = self.ctx.GetConfig("ec_id")
+ self.rpc = CreateRpcRunnerMock()
+ self.proc = mcpu.Processor(self.ctx, "ec_id", enable_locks = False)
+ self.op = self.OpTest()
+ self.calc_timeout = lambda: 42
+
+ def testRunLU(self):
+ lu = mocks.FakeLU(self.proc, self.op, self.cfg, self.rpc, None)
+ self.proc._ExecLU(lu)
+
+ def testRunLUWithPrereqError(self):
+ prereq = errors.OpPrereqError(self.op, errors.ECODE_INVAL)
+ lu = mocks.FakeLU(self.proc, self.op, self.cfg, self.rpc, prereq)
+ self.assertRaises(errors.OpPrereqError, self.proc._LockAndExecLU,
+ lu, locking.LEVEL_CLUSTER, self.calc_timeout)
+
+ def testRunLUWithPrereqErrorMissingECode(self):
+ prereq = errors.OpPrereqError(self.op)
+ lu = mocks.FakeLU(self.proc, self.op, self.cfg, self.rpc, prereq)
+ self.assertRaises(errors.OpPrereqError, self.proc._LockAndExecLU,
+ lu, locking.LEVEL_CLUSTER, self.calc_timeout)
+
if __name__ == "__main__":
testutils.GanetiTestProgram()
diff --git a/test/py/mocks.py b/test/py/mocks.py
index 649b032..406caca 100644
--- a/test/py/mocks.py
+++ b/test/py/mocks.py
@@ -33,6 +33,7 @@
import os
+from ganeti import locking
from ganeti import netutils
@@ -47,6 +48,11 @@ FAKE_CLUSTER_KEY =
("AAAAB3NzaC1yc2EAAAABIwAAAQEAsuGLw70et3eApJ/ZEJkAVZogIrm"
class FakeConfig(object):
"""Fake configuration object"""
+ def __init__(self):
+ self.write_count = 0
+
+ def OutDate(self):
+ pass
def IsCluster(self):
return True
@@ -112,6 +118,14 @@ class FakeContext(object):
self.cfg = FakeConfig()
self.glm = FakeGLM()
+ def GetConfig(self, ec_id):
+ return self.cfg
+
+ def GetRpc(self, cfg):
+ return None
+
+ def GetWConfdContext(self, _ec_id):
+ return (None, None, None)
class FakeGetentResolver(object):
"""Fake runtime.GetentResolver"""
@@ -139,3 +153,50 @@ class FakeGetentResolver(object):
def LookupGid(self, gid):
return "group%s" % gid
+
+class FakeLU(object):
+ HPATH = "fake-lu"
+ HTYPE = None
+
+ def __init__(self, processor, op, cfg, rpc_runner, prereq_err):
+ self.proc = processor
+ self.cfg = cfg
+ self.op = op
+ self.rpc = rpc_runner
+ self.prereq_err = prereq_err
+
+ self.needed_locks = {}
+ self.opportunistic_locks = dict.fromkeys(locking.LEVELS, False)
+ self.dont_collate_locks = dict.fromkeys(locking.LEVELS, False)
+ self.add_locks = {}
+
+ self.LogWarning = processor.LogWarning
+
+ def CheckArguments(self):
+ pass
+
+ def ExpandNames(self):
+ pass
+
+ def DeclareLocks(self, level):
+ pass
+
+ def CheckPrereq(self):
+ if self.prereq_err:
+ raise self.prereq_err
+ pass
+
+ def Exec(self, feedback_fn):
+ pass
+
+ def BuildHooksNodes(self):
+ return ([], [])
+
+ def BuildHooksEnv(self):
+ return {}
+
+ def PreparePostHookNodes(self, post_hook_node_uuids):
+ return []
+
+ def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
+ return lu_result
--
2.8.0.rc3.226.g39d4020