From ef683d7a6ba9b208a9974721f2c269cb4f965062 Mon Sep 17 00:00:00 2001
From: Jedrzej Nowak <jnowak@mirantis.com>
Date: Fri, 4 Mar 2016 17:14:14 +0100
Subject: [PATCH] Added naive method to check if object already exists

Change-Id: Iefc1e3d2d6062fbe9375187472fd867db8d60c8c
---
 solar/dblayer/model.py        |  7 ++++++-
 solar/dblayer/solar_models.py | 12 ++++++++++++
 solar/test/test_resource.py   | 31 +++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/solar/dblayer/model.py b/solar/dblayer/model.py
index 19b21efd..a359412a 100644
--- a/solar/dblayer/model.py
+++ b/solar/dblayer/model.py
@@ -852,7 +852,7 @@ class Model(object):
         return cache.get(riak_obj.key)
 
     @classmethod
-    def from_dict(cls, key, data=None):
+    def _pre_from_dict_check(cls, key, data=None):
         if isinstance(key, dict) and data is None:
             data = key
             try:
@@ -866,6 +866,11 @@ class Model(object):
         if key in cls._c.obj_cache:
             raise DBLayerException("Object already exists in cache"
                                    " cannot create second")
+        return key, data
+
+    @classmethod
+    def from_dict(cls, key, data=None):
+        key, data = cls._pre_from_dict_check(key, data)
         data['key'] = key
 
         with cls._c.obj_cache._lock:
diff --git a/solar/dblayer/solar_models.py b/solar/dblayer/solar_models.py
index 80a0578e..cd445cb4 100644
--- a/solar/dblayer/solar_models.py
+++ b/solar/dblayer/solar_models.py
@@ -828,6 +828,18 @@ class Resource(Model):
 
     updated = IndexedField(StrInt)
 
+    @classmethod
+    def _pre_from_dict_check(cls, key, data=None):
+        # NOTE(jnowak): it's a bit naive implementation, we will
+        # introduce something smarter instead based on conflict
+        # resolution.
+        ret = super(Resource, cls)._pre_from_dict_check(key, data)
+        robj = cls.bucket.get(key)
+        if robj.exists:
+            raise DBLayerException("Object already exists in "
+                                   "database cannot create second")
+        return ret
+
     def _connect_single(self, other_inputs, other_name, my_name):
         if isinstance(other_name, (list, tuple)):
             # XXX: could be paralelized
diff --git a/solar/test/test_resource.py b/solar/test/test_resource.py
index 522f7dbc..73ee63a8 100644
--- a/solar/test/test_resource.py
+++ b/solar/test/test_resource.py
@@ -15,6 +15,8 @@
 import base
 from solar.core import resource
 from solar.core import signals
+from solar.dblayer.model import clear_cache
+from solar.dblayer.model import DBLayerException
 
 
 class TestResource(base.BaseResourceTest):
@@ -112,6 +114,35 @@ input:
         sample1.delete()
         self.assertEqual(sample2.args['value'], 0)
 
+    def test_double_create(self):
+        sample_meta_dir = self.make_resource_meta("""
+id: sample
+handler: ansible
+version: 1.0.0
+input:
+  value:
+    schema: int
+    value: 0
+        """)
+
+        self.create_resource('sample1', sample_meta_dir,
+                             {'value': 1})
+        with self.assertRaisesRegexp(
+                DBLayerException,
+                "Object already exists in cache cannot create second"
+        ):
+            self.create_resource('sample1', sample_meta_dir,
+                                 {'value': 1})
+
+        clear_cache()
+
+        with self.assertRaisesRegexp(
+                DBLayerException,
+                "Object already exists in database cannot create second"
+        ):
+            self.create_resource('sample1', sample_meta_dir,
+                                 {'value': 1})
+
     def test_computable_input(self):
         """Test that connection removed with resource."""
         sample_meta_dir = self.make_resource_meta("""