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

Reply via email to