]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Define behaviour for properties with None values.
authorSteve Baker <sbaker@redhat.com>
Wed, 3 Jul 2013 03:21:23 +0000 (15:21 +1200)
committerSteve Baker <sbaker@redhat.com>
Mon, 8 Jul 2013 22:02:15 +0000 (10:02 +1200)
Now that Ref and Fn::GetAtt might return None values, behaviour for
properties with None values needs definition.

This change will treat a None value in the following way:
- if there is a default in the schema, that value will be used
- otherwise a default is used depending on the type ('', False, 0, [] {})

Fixes bug: #1192142

Change-Id: I59ae32c1c32b1bfede7d775aa845cd14246040e1

heat/engine/properties.py
heat/tests/test_properties.py

index 462752d93942c9f768e67b34dc79f6752ccd6994..e71a54da53d5e39dc525cfaa1a293441905b5eeb 100644 (file)
@@ -79,7 +79,16 @@ class Property(object):
         except ValueError:
             return float(value)
 
+    def _validate_integer(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or 0
+        if not isinstance(value, int):
+            raise TypeError('value is not an integer')
+        return self._validate_number(value)
+
     def _validate_number(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or 0
         self._check_allowed(value)
 
         num = self.str_to_num(value)
@@ -93,6 +102,8 @@ class Property(object):
         return value
 
     def _validate_string(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or ''
         if not isinstance(value, basestring):
             raise ValueError('Value must be a string')
 
@@ -119,6 +130,8 @@ class Property(object):
         return value
 
     def _validate_map(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or {}
         if not isinstance(value, collections.Mapping):
             raise TypeError('"%s" is not a map' % value)
 
@@ -131,6 +144,8 @@ class Property(object):
         return children
 
     def _validate_list(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or []
         if (not isinstance(value, collections.Sequence) or
                 isinstance(value, basestring)):
             raise TypeError('"%s" is not a list' % repr(value))
@@ -147,6 +162,8 @@ class Property(object):
         return children
 
     def _validate_bool(self, value):
+        if value is None:
+            value = self.has_default() and self.default() or False
         if isinstance(value, bool):
             return value
         normalised = value.lower()
@@ -160,9 +177,7 @@ class Property(object):
         if t == STRING:
             return self._validate_string(value)
         elif t == INTEGER:
-            if not isinstance(value, int):
-                raise TypeError('value is not an integer')
-            return self._validate_number(value)
+            return self._validate_integer(value)
         elif t == NUMBER:
             return self._validate_number(value)
         elif t == MAP:
index 0d537b1aa4e023d5c20e19b9e7e3edc59c1688d8..4bdf9f46b509787973f09d31cb2d26f6a95abd75 100644 (file)
@@ -332,6 +332,82 @@ class PropertiesTest(testtools.TestCase):
     def test_bad_key(self):
         self.assertEqual(self.props.get('foo', 'wibble'), 'wibble')
 
+    def test_none_string(self):
+        schema = {'foo': {'Type': 'String'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual('', props['foo'])
+
+    def test_none_integer(self):
+        schema = {'foo': {'Type': 'Integer'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(0, props['foo'])
+
+    def test_none_number(self):
+        schema = {'foo': {'Type': 'Number'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(0, props['foo'])
+
+    def test_none_boolean(self):
+        schema = {'foo': {'Type': 'Boolean'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(False, props['foo'])
+
+    def test_none_map(self):
+        schema = {'foo': {'Type': 'Map'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual({}, props['foo'])
+
+    def test_none_list(self):
+        schema = {'foo': {'Type': 'List'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual([], props['foo'])
+
+    def test_none_default_string(self):
+        schema = {'foo': {'Type': 'String', 'Default': 'bar'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual('bar', props['foo'])
+
+    def test_none_default_integer(self):
+        schema = {'foo': {'Type': 'Integer', 'Default': 42}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(42, props['foo'])
+
+        schema = {'foo': {'Type': 'Integer', 'Default': 0}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(0, props['foo'])
+
+        schema = {'foo': {'Type': 'Integer', 'Default': -273}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(-273, props['foo'])
+
+    def test_none_default_number(self):
+        schema = {'foo': {'Type': 'Number', 'Default': 42.0}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(42.0, props['foo'])
+
+        schema = {'foo': {'Type': 'Number', 'Default': 0.0}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(0.0, props['foo'])
+
+        schema = {'foo': {'Type': 'Number', 'Default': -273.15}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(-273.15, props['foo'])
+
+    def test_none_default_boolean(self):
+        schema = {'foo': {'Type': 'Boolean', 'Default': True}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(True, props['foo'])
+
+    def test_none_default_map(self):
+        schema = {'foo': {'Type': 'Map', 'Default': {'bar': 'baz'}}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual({'bar': 'baz'}, props['foo'])
+
+    def test_none_default_list(self):
+        schema = {'foo': {'Type': 'List', 'Default': ['one', 'two']}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(['one', 'two'], props['foo'])
+
 
 class PropertiesValidationTest(testtools.TestCase):
     def test_required(self):
@@ -368,3 +444,63 @@ class PropertiesValidationTest(testtools.TestCase):
         schema = {'foo': {'Type': 'String'}}
         props = properties.Properties(schema, {'food': 42})
         self.assertRaises(exception.StackValidationFailed, props.validate)
+
+    def test_none_string(self):
+        schema = {'foo': {'Type': 'String'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_integer(self):
+        schema = {'foo': {'Type': 'Integer'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_number(self):
+        schema = {'foo': {'Type': 'Number'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_boolean(self):
+        schema = {'foo': {'Type': 'Boolean'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_map(self):
+        schema = {'foo': {'Type': 'Map'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_list(self):
+        schema = {'foo': {'Type': 'List'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_string(self):
+        schema = {'foo': {'Type': 'String', 'Default': 'bar'}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_integer(self):
+        schema = {'foo': {'Type': 'Integer', 'Default': 42}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_number(self):
+        schema = {'foo': {'Type': 'Number', 'Default': 42.0}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_boolean(self):
+        schema = {'foo': {'Type': 'Boolean', 'Default': True}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_map(self):
+        schema = {'foo': {'Type': 'Map', 'Default': {'bar': 'baz'}}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)
+
+    def test_none_default_list(self):
+        schema = {'foo': {'Type': 'List', 'Default': ['one', 'two']}}
+        props = properties.Properties(schema, {'foo': None})
+        self.assertEqual(props.validate(), None)