]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Add tests for resource-data delete bug.
authorRandall Burt <randall.burt@rackspace.com>
Wed, 17 Jul 2013 00:31:25 +0000 (19:31 -0500)
committerRandall Burt <randall.burt@rackspace.com>
Wed, 17 Jul 2013 00:31:25 +0000 (19:31 -0500)
Fixes bug 1201974

Change-Id: Id5fdfcde8541e83f68406c67250b815b35fbbf54

heat/db/api.py
heat/db/sqlalchemy/api.py
heat/tests/test_nested_stack.py

index 23cc8b9bdfdc71a5e743d5afabad5c946bb98fff..e48161202f7db67305b75886735367a70d77b456 100644 (file)
@@ -66,6 +66,18 @@ def raw_template_create(context, values):
     return IMPL.raw_template_create(context, values)
 
 
+def resource_data_get(resource, key):
+    return IMPL.resource_data_get(resource, key)
+
+
+def resource_data_set(resource, key, value, redact=False):
+    return IMPL.resource_data_set(resource, key, value, redact=redact)
+
+
+def resource_data_get_by_key(context, resource_id, key):
+    return IMPL.resource_data_get_by_key(context, resource_id, key)
+
+
 def resource_get(context, resource_id):
     return IMPL.resource_get(context, resource_id)
 
index 98e85c8a7e393291122a73fb7ea4105627f1d7a9..72aa18a834fc40e9e16a86241a12d9361a7d04f2 100644 (file)
@@ -99,50 +99,36 @@ def resource_get_all(context):
 
 def resource_data_get(resource, key):
     """Lookup value of resource's data by key."""
-    data_lst = filter(lambda x: x.key == key, resource.data)
-    if not data_lst:
-        return None
-    assert len(data_lst) == 1
-    data = data_lst[0]
+    result = resource_data_get_by_key(resource.context, resource.id, key)
+    return result.value
+
 
-    if data.redact:
-        return crypt.decrypt(data.value)
-    else:
-        return data.value
+def resource_data_get_by_key(context, resource_id, key):
+    result = (model_query(context, models.ResourceData)
+              .filter_by(resource_id=resource_id)
+              .filter_by(key=key)
+              .first())
+    if not result:
+        raise exception.NotFound('No resource data found')
+    if result.redact and result.value:
+        result.value = crypt.decrypt(result.value)
+    return result
 
 
 def resource_data_set(resource, key, value, redact=False):
     """Save resource's key/value pair to database."""
     if redact:
         value = crypt.encrypt(value)
-    data_lst = filter(lambda x: x.key == key, resource.data)
-
-    if data_lst:  # Key exists in db, so check value & replace if necessary
-        assert len(data_lst) == 1
-        resource_data = data_lst[0]
-
-        # If the new value is the same, do nothing
-        if value == resource_data.value:
-            return None
-
-        # Otherwise, delete the old value
-        for i, d in enumerate(resource.data):
-            if d.key == key:
-                index = i
-        del(resource.data[index])
-
-    else:  # Build a new key/value
-        resource_data = models.ResourceData()
-        resource_data.key = key
-        resource_data.resource_id = resource.id
-        resource_data.redact = True
-
-    resource_data.value = value
-    resource.data.append(resource_data)
-
-    # Save to new key/value pair to database
-    rs = model_query(resource.context, models.Resource).get(resource.id)
-    rs.update_and_save({'data': resource.data})
+    try:
+        current = resource_data_get_by_key(resource.context, resource.id, key)
+    except exception.NotFound:
+        current = models.ResourceData()
+        current.key = key
+        current.resource_id = resource.id
+    current.redact = redact
+    current.value = value
+    current.save()
+    return current
 
 
 def resource_create(context, values):
index 45fef55e6e7489406cf036421986935a0b1de506..9de472be107f2bf3d97c6b57ba9f6126c34bdb39 100644 (file)
 from heat.common import context
 from heat.common import exception
 from heat.common import template_format
+from heat.common import urlfetch
+from heat.db import api as db_api
 from heat.engine import parser
 from heat.engine import resource
 from heat.engine import scheduler
-from heat.common import urlfetch
-from heat.tests.common import HeatTestCase
+from heat.tests import generic_resource as generic_rsrc
 from heat.tests import utils
+from heat.tests.common import HeatTestCase
 from heat.tests.utils import setup_dummy_db
 
 
@@ -113,3 +115,39 @@ Outputs:
 
         rsrc.delete()
         self.m.VerifyAll()
+
+
+class ResDataResource(generic_rsrc.GenericResource):
+    def handle_create(self):
+        db_api.resource_data_set(self, "test", 'A secret value', True)
+
+
+class ResDataNestedStackTest(NestedStackTest):
+
+    nested_template = '''
+HeatTemplateFormatVersion: "2012-12-12"
+Parameters:
+  KeyName:
+    Type: String
+Resources:
+  nested_res:
+    Type: "res.data.resource"
+Outputs:
+  Foo:
+    Value: bar
+'''
+
+    def setUp(self):
+        resource._register_class("res.data.resource", ResDataResource)
+        super(ResDataNestedStackTest, self).setUp()
+
+    def test_res_data_delete(self):
+        urlfetch.get('https://localhost/the.template').AndReturn(
+            self.nested_template)
+        self.m.ReplayAll()
+        stack = self.create_stack(self.test_template)
+        res = stack['the_nested'].nested()['nested_res']
+        stack.delete()
+        self.assertEqual(stack.state, (stack.DELETE, stack.COMPLETE))
+        self.assertRaises(exception.NotFound, db_api.resource_data_get, res,
+                          'test')