You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2015/05/19 00:29:49 UTC

svn commit: r1680116 - in /sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src: main/java/org/apache/sling/nosql/generic/adapter/ main/java/org/apache/sling/nosql/generic/resource/impl/ test/java/org/apache/sling/nosql/generic/resource/impl/ t...

Author: sseifert
Date: Mon May 18 22:29:48 2015
New Revision: 1680116

URL: http://svn.apache.org/r1680116
Log:
unit tests

Added:
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java   (with props)
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java   (with props)
Modified:
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderFactory.java
    sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory.xml

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java Mon May 18 22:29:48 2015
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.nosql.generic.adapter;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -30,7 +31,7 @@ public final class NoSqlData {
     
     public NoSqlData(String path, Map<String, Object> properties) {
         this.path = path;
-        this.properties = properties;
+        this.properties = new HashMap<String, Object>(properties);
     }
 
     public String getPath() {

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java Mon May 18 22:29:48 2015
@@ -33,15 +33,17 @@ import org.apache.sling.nosql.generic.ad
 /**
  * Generic implementation of a NoSQL database resource.
  */
-public class NoSqlResource extends AbstractResource {
+class NoSqlResource extends AbstractResource {
     
     private final NoSqlData data;
     private final ResourceResolver resourceResolver;
+    private final NoSqlResourceProvider resourceProvider;
     private final ResourceMetadata metadata;
     
-    public NoSqlResource(NoSqlData data, ResourceResolver resourceResolver) {
+    public NoSqlResource(NoSqlData data, ResourceResolver resourceResolver, NoSqlResourceProvider resourceProvider) {
         this.data = data;
         this.resourceResolver = resourceResolver;
+        this.resourceProvider = resourceProvider;
         this.metadata = new ResourceMetadata();
     }
 
@@ -69,12 +71,20 @@ public class NoSqlResource extends Abstr
     @Override
     public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
         if (type == ValueMap.class || type == Map.class) {
-            return (AdapterType)new DeepReadValueMapDecorator(this, new NoSqlValueMap(data.getProperties()));
+            return (AdapterType)new DeepReadValueMapDecorator(this, new NoSqlValueMap(data.getProperties(), this, resourceProvider));
         }
         if (type == ModifiableValueMap.class) {
-            return (AdapterType)new DeepReadModifiableValueMapDecorator(this, new NoSqlValueMap(data.getProperties()));
+            return (AdapterType)new DeepReadModifiableValueMapDecorator(this, new NoSqlValueMap(data.getProperties(), this, resourceProvider));
         }
         return super.adaptTo(type);
     }
 
+    @Override
+    public String toString() {
+        return getClass().getSimpleName()
+            + ", type=" + getResourceType()
+            + ", superType=" + getResourceSuperType()
+            + ", path=" + getPath();
+    }
+
 }

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java Mon May 18 22:29:48 2015
@@ -67,15 +67,20 @@ public class NoSqlResourceProvider imple
         if (!adapter.validPath(path)) {
             return null;
         }
-        if (this.deletedResources.contains(path)) {
-            return null;
+        if (!this.deletedResources.isEmpty()) {
+            for (String deletedPath : deletedResources) {
+                Pattern deletedPathPattern = PathUtil.getSameOrDescendantPathPattern(deletedPath);
+                if (deletedPathPattern.matcher(path).matches()) {
+                    return null;
+                }
+            }
         }
         if (this.changedResources.containsKey(path)) {
-            return new NoSqlResource(this.changedResources.get(path), resourceResolver);
+            return new NoSqlResource(this.changedResources.get(path), resourceResolver, this);
         }
         NoSqlData data = adapter.get(path);
         if (data != null) {
-            return new NoSqlResource(data, resourceResolver);
+            return new NoSqlResource(data, resourceResolver, this);
         }
         return null;
     }
@@ -96,13 +101,13 @@ public class NoSqlResourceProvider imple
             if (isDeleted(item.getPath()) || changedResources.containsKey(item.getPath())) {
                 continue;
             }
-            children.put(item.getPath(), new NoSqlResource(item, parent.getResourceResolver()));
+            children.put(item.getPath(), new NoSqlResource(item, parent.getResourceResolver(), this));
         }
         
         Pattern childPathPattern = PathUtil.getChildPathPattern(parent.getPath());
         for (NoSqlData item : changedResources.values()) {
             if (childPathPattern.matcher(item.getPath()).matches()) {
-                children.put(item.getPath(), new NoSqlResource(item, parent.getResourceResolver()));
+                children.put(item.getPath(), new NoSqlResource(item, parent.getResourceResolver(), this));
             }
         }
         
@@ -135,7 +140,7 @@ public class NoSqlResourceProvider imple
         // create new resource in changeset
         NoSqlData data = new NoSqlData(path, properties);
         changedResources.put(path, data);
-        return new NoSqlResource(data, resolver);
+        return new NoSqlResource(data, resolver, this);
     }
     
     public void delete(ResourceResolver resolver, String path) throws PersistenceException {
@@ -197,6 +202,10 @@ public class NoSqlResourceProvider imple
         return !(changedResources.isEmpty() && deletedResources.isEmpty());
     }
     
+    void markAsChanged(Resource resource) {
+        changedResources.put(resource.getPath(), new NoSqlData(resource.getPath(), resource.getValueMap()));
+    }
+    
     private void notifyAdded(String path) {
         final Dictionary<String, Object> props = new Hashtable<String, Object>();
         props.put(SlingConstants.PROPERTY_PATH, path);
@@ -234,7 +243,7 @@ public class NoSqlResourceProvider imple
                 return result.hasNext();
             }
             public Resource next() {
-                return new NoSqlResource(result.next(), resolver);
+                return new NoSqlResource(result.next(), resolver, NoSqlResourceProvider.this);
             }
             public void remove() {
                 throw new UnsupportedOperationException();

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java Mon May 18 22:29:48 2015
@@ -26,7 +26,6 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 
@@ -34,6 +33,7 @@ import javax.xml.bind.DatatypeConverter;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
 
 /**
@@ -43,8 +43,13 @@ import org.apache.sling.api.wrappers.Val
  */
 class NoSqlValueMap extends ValueMapDecorator implements ModifiableValueMap {
     
-    public NoSqlValueMap(Map<String,Object> map) {
+    private final Resource resource;
+    private final NoSqlResourceProvider resourceProvider;
+    
+    public NoSqlValueMap(Map<String,Object> map, Resource resource, NoSqlResourceProvider resourceProvider) {
         super(convertForWriteAll(map));
+        this.resource = resource;
+        this.resourceProvider = resourceProvider;
     }
 
     @SuppressWarnings("unchecked")
@@ -97,15 +102,31 @@ class NoSqlValueMap extends ValueMapDeco
     
     @Override
     public Object put(String key, Object value) {
-        return super.put(key, convertForWrite(value));
+        Object result = super.put(key, convertForWrite(value));
+        resourceProvider.markAsChanged(resource);
+        return result;
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public void putAll(Map<? extends String, ?> map) {
         super.putAll((Map<? extends String, ?>)convertForWriteAll((Map<String, Object>)map));
+        resourceProvider.markAsChanged(resource);
     }
     
+    @Override
+    public Object remove(Object key) {
+        Object result = super.remove(key);
+        resourceProvider.markAsChanged(resource);
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        super.clear();
+        resourceProvider.markAsChanged(resource);
+    }
+
     private static Object convertForWrite(Object value) {
         if (value instanceof Calendar) {
             value = getISO8601Format().format(((Calendar)value).getTime());
@@ -144,11 +165,10 @@ class NoSqlValueMap extends ValueMapDeco
     }
     
     private static Map<String, Object> convertForWriteAll(Map<String, Object> map) {
-        Map<String,Object> newMap = new HashMap<String, Object>();
         for (Map.Entry<String, Object> entry : map.entrySet()) {
-            newMap.put(entry.getKey(), convertForWrite(entry.getValue()));
+            map.put(entry.getKey(), convertForWrite(entry.getValue()));
         }
-        return newMap;
+        return map;
     }
 
     private static DateFormat getISO8601Format() {

Added: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java?rev=1680116&view=auto
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java (added)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java Mon May 18 22:29:48 2015
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.nosql.generic.resource.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class NoSqlResourceProviderQueryTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK);
+    
+    private Resource testRoot;
+
+    @Before
+    public void setUp() throws Exception {
+        context.registerInjectActivateService(new SimpleNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/nosql-simple")
+                .build());
+        
+        // prepare some test data using Sling CRUD API
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        final Resource root = context.resourceResolver().getResource("/");
+        Resource noSqlRoot = context.resourceResolver().create(root, "nosql-simple", props);
+        this.testRoot = context.resourceResolver().create(noSqlRoot, "test", props);
+        
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of("prop1", "value1"));
+        context.resourceResolver().create(testRoot, "node2", ImmutableMap.<String, Object>of("prop1", "value2"));
+        
+        context.resourceResolver().commit();
+    }
+
+    @Test
+    public void testRootNode() {
+        assertTrue(testRoot instanceof NoSqlResource);
+    }
+
+    @Test
+    public void testFindResources_ValidQuery() {
+        Iterator<Resource> result = context.resourceResolver().findResources("all", "simple");
+        assertEquals("/nosql-simple", result.next().getPath());
+        assertEquals("/nosql-simple/test", result.next().getPath());
+        assertEquals("/nosql-simple/test/node1", result.next().getPath());
+        assertEquals("/nosql-simple/test/node2", result.next().getPath());
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testFindResources_InvalidQuery() {
+        Iterator<Resource> result = context.resourceResolver().findResources("all", "invalid");
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testQueryResources_ValidQuery() {
+        Iterator<Map<String, Object>> result = context.resourceResolver().queryResources("all", "simple");
+        assertNull(result.next().get("prop1"));
+        assertNull(result.next().get("prop1"));
+        assertEquals("value1", result.next().get("prop1"));
+        assertEquals("value2", result.next().get("prop1"));
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testQueryResources_InvalidQuery() {
+        Iterator<Map<String, Object>> result = context.resourceResolver().queryResources("all", "invalid");
+        assertFalse(result.hasNext());
+    }
+
+}

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 18 22:29:48 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java?rev=1680116&view=auto
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java (added)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java Mon May 18 22:29:48 2015
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.nosql.generic.resource.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class NoSqlResourceProviderTransactionalTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK);
+    
+    private Resource testRoot;
+
+    @Before
+    public void setUp() throws Exception {
+        context.registerInjectActivateService(new SimpleNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/nosql-simple")
+                .build());
+        
+        // prepare some test data using Sling CRUD API
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        final Resource root = context.resourceResolver().getResource("/");
+        Resource noSqlRoot = context.resourceResolver().create(root, "nosql-simple", props);
+        this.testRoot = context.resourceResolver().create(noSqlRoot, "test", props);
+        context.resourceResolver().commit();
+    }
+
+    @Test
+    public void testRootNode() {
+        assertTrue(testRoot instanceof NoSqlResource);
+    }
+
+    @Test
+    public void testGetInvalidPath() {
+        assertNull(context.resourceResolver().getResource(testRoot.getPath() + "/invalid/1"));
+    }
+
+    @Test(expected = PersistenceException.class)
+    public void testCreateInvalidPath() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "invalid", ImmutableMap.<String, Object>of());
+    }
+
+    @Test
+    public void testAddDeleteNodesPartialCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "node0", ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().create(testRoot, "node2", ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot, "node3", ImmutableMap.<String, Object>of());
+
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot.getChild("node0"));
+        assertNotNull(testRoot.getChild("node1"));
+        assertNotNull(testRoot.getChild("node2"));
+        assertNotNull(testRoot.getChild("node3"));
+        
+        context.resourceResolver().delete(testRoot.getChild("node0"));
+        context.resourceResolver().delete(testRoot.getChild("node2"));
+
+        assertNull(testRoot.getChild("node0"));
+        assertNotNull(testRoot.getChild("node1"));
+        assertNull(testRoot.getChild("node2"));
+        assertNotNull(testRoot.getChild("node3"));
+        
+        Iterator<Resource> children = testRoot.listChildren();
+        assertEquals("node1", children.next().getName());
+        assertEquals("node3", children.next().getName());
+        assertFalse(children.hasNext());
+        
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().revert();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot.getChild("node1"));
+        assertNull(testRoot.getChild("node2"));
+        assertNull(testRoot.getChild("node3"));
+        
+        children = testRoot.listChildren();
+        assertEquals("node0", children.next().getName());
+        assertEquals("node1", children.next().getName());
+        assertFalse(children.hasNext());
+    }
+
+    @Test
+    public void testRecursiveDeleteWithoutCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        Resource node11 = context.resourceResolver().create(node1, "node11", ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(node11, "node111", ImmutableMap.<String, Object>of());
+
+        assertNotNull(testRoot.getChild("node1"));
+        assertNotNull(testRoot.getChild("node1/node11"));
+        assertNotNull(testRoot.getChild("node1/node11/node111"));
+        
+        context.resourceResolver().delete(node1);
+
+        assertNull(testRoot.getChild("node1"));
+        assertNull(testRoot.getChild("node1/node11"));
+        assertNull(testRoot.getChild("node1/node11/node111"));
+    }
+
+    @Test
+    public void testRecursiveDeleteWithCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        Resource node11 = context.resourceResolver().create(node1, "node11", ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(node11, "node111", ImmutableMap.<String, Object>of());
+        
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot.getChild("node1"));
+        assertNotNull(testRoot.getChild("node1/node11"));
+        assertNotNull(testRoot.getChild("node1/node11/node111"));
+        
+        context.resourceResolver().delete(node1);
+
+        assertNull(testRoot.getChild("node1"));
+        assertNull(testRoot.getChild("node1/node11"));
+        assertNull(testRoot.getChild("node1/node11/node111"));
+
+        assertTrue(context.resourceResolver().hasChanges());
+
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+
+        assertNull(testRoot.getChild("node1"));
+        assertNull(testRoot.getChild("node1/node11"));
+        assertNull(testRoot.getChild("node1/node11/node111"));
+    }
+
+    @Test(expected = PersistenceException.class)
+    public void testCreateAlreadyExistWithoutCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+    }
+    
+    @Test(expected = PersistenceException.class)
+    public void testCreateAlreadyExistWithCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testCreateAlreadyExistDeletedWithoutCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        context.resourceResolver().delete(testRoot.getChild("node1"));
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testCreateAlreadyExistDeletedWithCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+        context.resourceResolver().delete(testRoot.getChild("node1"));
+        context.resourceResolver().commit();
+        context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testUpdateWithoutCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of("prop1", "value1"));
+        assertEquals("value1", node1.getValueMap().get("prop1", String.class));
+        
+        ModifiableValueMap props = node1.adaptTo(ModifiableValueMap.class);
+        props.put("prop1", "value2");
+        
+        node1 = testRoot.getChild("node1");
+        assertEquals("value2", node1.getValueMap().get("prop1", String.class));
+    }
+    
+    @Test
+    public void testUpdateWithCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot, "node1", ImmutableMap.<String, Object>of("prop1", "value1"));
+        assertEquals("value1", node1.getValueMap().get("prop1", String.class));
+        context.resourceResolver().commit();
+        
+        ModifiableValueMap props = node1.adaptTo(ModifiableValueMap.class);
+        props.put("prop1", "value2");
+        context.resourceResolver().commit();
+        
+        node1 = testRoot.getChild("node1");
+        assertEquals("value2", node1.getValueMap().get("prop1", String.class));
+    }
+    
+}

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 18 22:29:48 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java Mon May 18 22:29:48 2015
@@ -23,6 +23,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang3.StringUtils;
@@ -39,10 +41,10 @@ import com.google.common.collect.Iterato
  */
 public class SimpleNoSqlAdapter implements NoSqlAdapter {
     
-    private final Map<String, Map<String,Object>> store = new HashMap<String, Map<String,Object>>();
+    private final SortedMap<String, Map<String,Object>> store = new TreeMap<String, Map<String,Object>>();
 
     public boolean validPath(String path) {
-        return true;
+        return !(StringUtils.contains(path, "/invalid/") || StringUtils.endsWith(path, "/invalid"));
     }
 
     public NoSqlData get(String path) {

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderFactory.java?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderFactory.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderFactory.java Mon May 18 22:29:48 2015
@@ -23,9 +23,11 @@ import java.util.Map;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.QueriableResourceProvider;
 import org.apache.sling.api.resource.ResourceProvider;
 import org.apache.sling.api.resource.ResourceProviderFactory;
 import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
@@ -38,7 +40,10 @@ import org.osgi.service.event.EventAdmin
  */
 @Component(configurationFactory = true, policy = ConfigurationPolicy.REQUIRE, metatype = true)
 @Service(value = ResourceProviderFactory.class)
-@Property(name = ResourceProvider.ROOTS, value = "")
+@Properties({
+    @Property(name = ResourceProvider.ROOTS, value = ""),
+    @Property(name = QueriableResourceProvider.LANGUAGES, value = { "simple" })
+})
 public class SimpleNoSqlResourceProviderFactory extends AbstractNoSqlResourceProviderFactory {
 
     @Reference

Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory.xml
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory.xml?rev=1680116&r1=1680115&r2=1680116&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory.xml (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory.xml Mon May 18 22:29:48 2015
@@ -24,6 +24,7 @@
             <provide interface="org.apache.sling.api.resource.ResourceProviderFactory"/>
         </service>
         <property name="provider.roots" value=""/>
+        <property name="provider.query.languages" value="simple"/>
         <property name="service.vendor" value="The Apache Software Foundation"/>
         <property name="service.pid" value="org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory"/>
         <reference name="eventAdmin" interface="org.osgi.service.event.EventAdmin" cardinality="1..1" policy="static" bind="bindEventAdmin" unbind="unbindEventAdmin"/>