commit a5728081faa3068dcb797a7ccccd9ce47c0b23e0
Author: Guido Trotter <ultrotter@google.com>
Date:   Tue Feb 10 15:06:24 2009 +0000

    Instance parameters: force typing
    
    We want all the hv/be parameters to have a known type, rather than a
    random mix of empty string, boolean values, and None, so we declare the
    type of each variable and we enforce/convert it.
    
    - Add some new constants for enforceable value types
    - Add new constants dicts HVS_PARAMETER_TYPES and BES_PARAMETER_TYPES
      holding not only the valid parameters but also their types
    - Drop the old HVS_PARAMETERS and BES_PARAMETERS constants and calculate
      the values from the type dict
    - Convert all the default parameters to a valid type value
    - Create a new ForceDictType utils function, to check/enforce a dict's
      element value types, with relevant unit tests
    - Drop a few custom functions to check/convert the BE param types in
      utils and cli, in favor of ForceDictType
    - Double-check the parameter types using ForceDictType in both scripts
      and LogicalUnits, when possible.
    
    As a bonus:
    - Remove some old commented-out code in gnt-instance
    - Remove some already fixed FIXME
    - Fix a bug which prevented VALUE_DEFAULT to be applied to BE parameters
      in SetInstanceParams because the value was checked for validity before
      that transformation was made
    - Fix a bug which prevented initing a cluster and passing hvparams to
      work at all
    - ForceDictType allows an allowed_values for exceptions, which makes us
      able to do the checking even when some values must not be
      converted/typechecked (for example the 'default' string in
      SetInstanceParameters)
    
    Reviewed-by: iustinp

diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 423f5fa..1050002 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -38,12 +38,13 @@ import ganeti
 import testutils
 from ganeti import constants
 from ganeti import utils
+from ganeti import errors
 from ganeti.utils import IsProcessAlive, RunCmd, \
      RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \
      ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \
      ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \
      SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree, OwnIpAddress, \
-     TailFile
+     TailFile, ForceDictType
 
 from ganeti.errors import LockError, UnitParseError, GenericError, \
      ProgrammerError
@@ -921,6 +922,45 @@ class FieldSetTestCase(unittest.TestCase):
     self.failIf(f.NonMatching(["b12", "c"]))
     self.failUnless(f.NonMatching(["a", "1"]))
 
+class TestForceDictType(unittest.TestCase):
+  """Test case for ForceDictType"""
+
+  def setUp(self):
+    self.key_types = {
+      'a': constants.VTYPE_INT,
+      'b': constants.VTYPE_BOOL,
+      'c': constants.VTYPE_STRING,
+      'd': constants.VTYPE_SIZE,
+      }
+
+  def _fdt(self, dict, allowed_values=None):
+    if allowed_values is None:
+      ForceDictType(dict, self.key_types)
+    else:
+      ForceDictType(dict, self.key_types, allowed_values=allowed_values)
+
+    return dict
+
+  def testSimpleDict(self):
+    self.assertEqual(self._fdt({}), {})
+    self.assertEqual(self._fdt({'a': 1}), {'a': 1})
+    self.assertEqual(self._fdt({'a': '1'}), {'a': 1})
+    self.assertEqual(self._fdt({'a': 1, 'b': 1}), {'a':1, 'b': True})
+    self.assertEqual(self._fdt({'b': 1, 'c': 'foo'}), {'b': True, 'c': 'foo'})
+    self.assertEqual(self._fdt({'b': 1, 'c': False}), {'b': True, 'c': ''})
+    self.assertEqual(self._fdt({'b': 'false'}), {'b': False})
+    self.assertEqual(self._fdt({'b': 'False'}), {'b': False})
+    self.assertEqual(self._fdt({'b': 'true'}), {'b': True})
+    self.assertEqual(self._fdt({'b': 'True'}), {'b': True})
+    self.assertEqual(self._fdt({'d': '4'}), {'d': 4})
+    self.assertEqual(self._fdt({'d': '4M'}), {'d': 4})
+
+  def testErrors(self):
+    self.assertRaises(errors.TypeEnforcementError, self._fdt, {'a': 'astring'})
+    self.assertRaises(errors.TypeEnforcementError, self._fdt, {'c': True})
+    self.assertRaises(errors.TypeEnforcementError, self._fdt, {'d': 'astring'})
+    self.assertRaises(errors.TypeEnforcementError, self._fdt, {'d': '4 L'})
+
 
 if __name__ == '__main__':
   unittest.main()
