Browse Source

[master] Merge branch 'trac2114'

Jelte Jansen 12 years ago
parent
commit
7126375135

+ 16 - 0
src/lib/config/tests/testdata/spec32.spec

@@ -33,6 +33,22 @@
           }
           ]
         }
+      },
+      { "item_name": "named_set_item3",
+        "item_type": "named_set",
+        "item_optional": true,
+        "item_default": { "values": [ 1, 2, 3 ] },
+        "named_set_item_spec": {
+          "item_name": "named_set_element",
+          "item_type": "list",
+          "item_optional": false,
+          "item_default": [],
+          "list_item_spec":
+          { "item_name": "list_value",
+            "item_type": "integer",
+            "item_optional": true
+          }
+        }
       }
     ]
   }

+ 26 - 16
src/lib/python/isc/config/config_data.py

@@ -74,15 +74,15 @@ def check_type(spec_part, value):
         raise isc.cc.data.DataTypeError(str(value) + " is not a map")
 
 def convert_type(spec_part, value):
-    """Convert the given value(type is string) according specification 
-    part relevant for the value. Raises an isc.cc.data.DataTypeError 
+    """Convert the given value(type is string) according specification
+    part relevant for the value. Raises an isc.cc.data.DataTypeError
     exception if conversion failed.
     """
     if type(spec_part) == dict and 'item_type' in spec_part:
         data_type = spec_part['item_type']
     else:
         raise isc.cc.data.DataTypeError(str("Incorrect specification part for type conversion"))
-   
+
     try:
         if data_type == "integer":
             return int(value)
@@ -95,9 +95,9 @@ def convert_type(spec_part, value):
         elif data_type == "list":
             ret = []
             if type(value) == list:
-                for item in value:    
+                for item in value:
                     ret.append(convert_type(spec_part['list_item_spec'], item))
-            elif type(value) == str:    
+            elif type(value) == str:
                 value = value.split(',')
                 for item in value:
                     sub_value = item.split()
@@ -257,7 +257,7 @@ class ConfigData:
     """This class stores the module specs and the current non-default
        config values. It provides functions to get the actual value or
        the default value if no non-default value has been set"""
-   
+
     def __init__(self, specification):
         """Initialize a ConfigData instance. If specification is not
            of type ModuleSpec, a ConfigDataError is raised."""
@@ -350,7 +350,7 @@ class MultiConfigData:
     CURRENT = 2
     DEFAULT = 3
     NONE    = 4
-    
+
     def __init__(self):
         self._specifications = {}
         self._current_config = {}
@@ -413,7 +413,7 @@ class MultiConfigData:
            the module name, and the value is the config values for
            that module"""
         return self._current_config
-        
+
     def get_local_changes(self):
         """Returns the local config changes, i.e. those that have not
            been committed yet and are not known by the configuration
@@ -440,7 +440,7 @@ class MultiConfigData:
            get_value() for a general way to find a configuration value
            """
         return isc.cc.data.find_no_exc(self._local_changes, identifier)
-        
+
     def get_current_value(self, identifier):
         """Returns the current non-default value as known by the
            configuration manager, or None if it is not set.
@@ -448,7 +448,7 @@ class MultiConfigData:
            value
         """
         return isc.cc.data.find_no_exc(self._current_config, identifier)
-        
+
     def get_default_value(self, identifier):
         """Returns the default value for the given identifier as
            specified by the module specification, or None if there is
@@ -486,22 +486,32 @@ class MultiConfigData:
                         else:
                             return None
                     id_part = id_parts.pop(0)
+                    item_id, list_indices =\
+                        isc.cc.data.split_identifier_list_indices(id_part)
 
                     named_set_value, type = self.get_value(id_list)
-                    if id_part in named_set_value:
+                    if item_id in named_set_value.keys():
+                        result = named_set_value[item_id]
+                        # If the item is a list and we have indices in the
+                        # identifier part, continue with the item pointed to
+                        # by those indices
+                        if list_indices is not None:
+                            while len(list_indices) > 0:
+                                result = result[list_indices.pop(0)]
+
                         if len(id_parts) > 0:
                             # we are looking for the *default* value.
                             # so if not present in here, we need to
                             # lookup the one from the spec
                             rest_of_id = "/".join(id_parts)
-                            result = isc.cc.data.find_no_exc(named_set_value[id_part], rest_of_id)
+                            result = isc.cc.data.find_no_exc(result, rest_of_id)
                             if result is None:
                                 spec_part = self.find_spec_part(identifier)
                                 if 'item_default' in spec_part:
                                     return spec_part['item_default']
                             return result
                         else:
-                            return named_set_value[id_part]
+                            return result
                     else:
                         return None
                 elif list_indices is not None:
@@ -512,7 +522,7 @@ class MultiConfigData:
                     # So if the list item *itself* is a default,
                     # we need to get the value out of that. If not, we
                     # need to find the default for the specific element.
-                    list_value, type = self.get_value(id_list) 
+                    list_value, type = self.get_value(id_list)
                     list_spec = find_spec_part(self._specifications[module].get_config_spec(), id_prefix)
                     if type == self.DEFAULT:
                         if 'item_default' in list_spec:
@@ -523,7 +533,7 @@ class MultiConfigData:
                                 else:
                                     # out of range, return None
                                     return None
-                                
+
                             if len(id_parts) > 0:
                                 rest_of_id = "/".join(id_parts)
                                 return isc.cc.data.find(list_value, rest_of_id)
@@ -538,7 +548,7 @@ class MultiConfigData:
                             else:
                                 # out of range, return None
                                 return None
-                    
+
             spec = find_spec_part(self._specifications[module].get_config_spec(), id)
             if 'item_default' in spec:
                 # one special case, named_set

+ 23 - 14
src/lib/python/isc/config/tests/config_data_test.py

@@ -47,7 +47,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, "a")
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, [ 1, 2 ])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "a": 1 })
-        
+
         spec_part = find_spec_part(config_spec, "value2")
         check_type(spec_part, 1.1)
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, 1)
@@ -55,7 +55,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, "a")
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, [ 1, 2 ])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "a": 1 })
-        
+
         spec_part = find_spec_part(config_spec, "value3")
         check_type(spec_part, True)
         check_type(spec_part, False)
@@ -64,7 +64,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, "a")
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, [ 1, 2 ])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "a": 1 })
-        
+
         spec_part = find_spec_part(config_spec, "value4")
         check_type(spec_part, "asdf")
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, 1)
@@ -72,7 +72,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, True)
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, [ 1, 2 ])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "a": 1 })
-        
+
         spec_part = find_spec_part(config_spec, "value5")
         check_type(spec_part, [1, 2])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, 1)
@@ -81,7 +81,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, "a")
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, [ "a", "b" ])
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "a": 1 })
-        
+
         spec_part = find_spec_part(config_spec, "value6")
         check_type(spec_part, { "value1": "aaa", "value2": 2 })
         self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, 1)
@@ -107,7 +107,7 @@ class TestConfigData(unittest.TestCase):
         self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, { "a": 1 })
         self.assertRaises(isc.cc.data.DataTypeError, convert_type, 1, "a")
         self.assertRaises(isc.cc.data.DataTypeError, convert_type, { 'somedict': 'somevalue' }, "a")
-        
+
         spec_part = find_spec_part(config_spec, "value2")
         self.assertEqual(1.1, convert_type(spec_part, '1.1'))
         self.assertEqual(123.0, convert_type(spec_part, '123'))
@@ -130,7 +130,7 @@ class TestConfigData(unittest.TestCase):
         self.assertEqual('1', convert_type(spec_part, 1))
         self.assertEqual('1.1', convert_type(spec_part, 1.1))
         self.assertEqual('True', convert_type(spec_part, True))
-        
+
         spec_part = find_spec_part(config_spec, "value5")
         self.assertEqual([1, 2], convert_type(spec_part, '1, 2'))
         self.assertEqual([1, 2, 3], convert_type(spec_part, '1 2  3'))
@@ -254,7 +254,7 @@ class TestConfigData(unittest.TestCase):
 
     def test_init(self):
         self.assertRaises(ConfigDataError, ConfigData, "asdf")
-        
+
     def test_get_value(self):
         value, default = self.cd.get_value("item1")
         self.assertEqual(1, value)
@@ -337,7 +337,7 @@ class TestMultiConfigData(unittest.TestCase):
         else:
             self.data_path = "../../../testdata"
         self.mcd = MultiConfigData()
-        
+
     def test_init(self):
         self.assertEqual({}, self.mcd._specifications)
         self.assertEqual({}, self.mcd._current_config)
@@ -491,6 +491,12 @@ class TestMultiConfigData(unittest.TestCase):
         self.assertEqual(2, value)
         value = self.mcd.get_default_value("Spec32/named_set_item/no_such_item")
         self.assertEqual(None, value)
+        # Check that top-level default value works when named set contains list
+        # (issue #2114)
+        value = self.mcd.get_default_value("Spec32/named_set_item3/values[2]")
+        self.assertEqual(3, value)
+        self.assertRaises(IndexError, self.mcd.get_default_value,
+                          "Spec32/named_set_item3/values[5]")
 
     def test_get_value(self):
         module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
@@ -535,7 +541,7 @@ class TestMultiConfigData(unittest.TestCase):
     def test_get_value_maps(self):
         maps = self.mcd.get_value_maps()
         self.assertEqual([], maps)
-        
+
         module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
         self.mcd.set_specification(module_spec)
 
@@ -557,7 +563,7 @@ class TestMultiConfigData(unittest.TestCase):
         self.assertEqual([], maps)
         self.mcd.remove_specification("Spec1")
         self.mcd.remove_specification("foo")
-        
+
         module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
         self.mcd.set_specification(module_spec)
         maps = self.mcd.get_value_maps()
@@ -749,9 +755,12 @@ class TestMultiConfigData(unittest.TestCase):
         config_items = self.mcd.get_config_item_list(None, False)
         self.assertEqual(['Spec32'], config_items)
         config_items = self.mcd.get_config_item_list(None, True)
-        self.assertEqual(['Spec32/named_set_item', 'Spec32/named_set_item2'], config_items)
-        self.mcd.set_value('Spec32/named_set_item', { "aaaa": 4, "aabb": 5, "bbbb": 6})
-        config_items = self.mcd.get_config_item_list("/Spec32/named_set_item", True)
+        self.assertEqual(['Spec32/named_set_item', 'Spec32/named_set_item2',
+                          'Spec32/named_set_item3'], config_items)
+        self.mcd.set_value('Spec32/named_set_item', { "aaaa": 4, "aabb": 5,
+                                                      "bbbb": 6})
+        config_items = self.mcd.get_config_item_list("/Spec32/named_set_item",
+                                                     True)
         self.assertEqual(['Spec32/named_set_item/aaaa',
                           'Spec32/named_set_item/aabb',
                           'Spec32/named_set_item/bbbb',