Merge "Initial implementation of the ClusteredDataStore"
authorEd Warnicke <eaw@cisco.com>
Fri, 8 Nov 2013 19:36:19 +0000 (19:36 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 8 Nov 2013 19:36:19 +0000 (19:36 +0000)
opendaylight/md-sal/clustered-data-store/implementation/pom.xml
opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/ClusteredDataStore.java [new file with mode: 0644]
opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/Activator.java
opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStore.java [deleted file]
opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImpl.java [new file with mode: 0644]
opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreManager.java [new file with mode: 0644]
opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ActivatorTest.java
opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImplTest.java [new file with mode: 0644]
opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreTest.java [deleted file]

index f822ac5..bb43809 100644 (file)
     </plugins>
   </build>
   <dependencies>
+
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
     <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-common-api</artifactId>
         <version>1.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-util</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal</artifactId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+       <groupId>org.mockito</groupId>
+       <artifactId>mockito-all</artifactId>
+       <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>equinoxSDK381</groupId>
       <artifactId>org.eclipse.osgi</artifactId>
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/ClusteredDataStore.java b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/ClusteredDataStore.java
new file mode 100644 (file)
index 0000000..0a577ad
--- /dev/null
@@ -0,0 +1,18 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+package org.opendaylight.controller.datastore;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface ClusteredDataStore extends DataReader<InstanceIdentifier<? extends Object>, Object>, DataCommitHandler<InstanceIdentifier<? extends Object>,Object> {
+}
index 101da7f..c94355d 100644 (file)
@@ -9,14 +9,46 @@
 
 package org.opendaylight.controller.datastore.internal;
 
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.datastore.ClusteredDataStore;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Set;
+
 public class Activator extends ComponentActivatorAbstractBase {
     protected static final Logger logger = LoggerFactory
             .getLogger(Activator.class);
 
 
+    @Override
+    protected Object[] getGlobalImplementations(){
+       logger.debug("Calling getGlobalImplementations to return:", ClusteredDataStoreManager.class);
+        return new Object[] {
+            ClusteredDataStoreManager.class
+        };
+    }
+
+
+    @Override
+    protected void configureGlobalInstance(Component c, Object imp){
+        if (imp.equals(ClusteredDataStoreManager.class)) {
+            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
+
+            c.setInterface(new String[] { ClusteredDataStore.class.getName() }, props);
+            logger.debug("configureGlobalInstance adding dependency:", IClusterGlobalServices.class);
+            
+            c.add(createServiceDependency().setService(
+                    IClusterGlobalServices.class).setCallbacks(
+                    "setClusterGlobalServices",
+                    "unsetClusterGlobalServices").setRequired(true));
+
+        }
+    }
+
 
 }
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStore.java b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStore.java
deleted file mode 100644 (file)
index 7c25b14..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.opendaylight.controller.datastore.internal;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public class ClusteredDataStore implements DataReader<InstanceIdentifier<? extends Object>, Object>, DataCommitHandler<InstanceIdentifier<? extends Object>,Object> {
-    @Override
-    public DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> requestCommit(DataModification<InstanceIdentifier<? extends Object>, Object> modification) {
-        return null;
-    }
-
-    @Override
-    public Object readOperationalData(InstanceIdentifier<? extends Object> path) {
-        return null;
-    }
-
-    @Override
-    public Object readConfigurationData(InstanceIdentifier<? extends Object> path) {
-        return null;
-    }
-}
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImpl.java b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImpl.java
new file mode 100644 (file)
index 0000000..f2e7773
--- /dev/null
@@ -0,0 +1,122 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.datastore.internal;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.datastore.ClusteredDataStore;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * The ClusteredDataStoreImpl stores global data to be shared across a controller cluster. It uses Clustering Services.
+ */
+public class ClusteredDataStoreImpl implements ClusteredDataStore {
+
+
+    public static final String OPERATIONAL_DATA_CACHE = "clustered_data_store.operational_data_cache";
+    public static final String CONFIGURATION_DATA_CACHE = "clustered_data_store.configuration_data_cache";
+
+    private ConcurrentMap operationalDataCache;
+    private ConcurrentMap configurationDataCache;
+
+    public ClusteredDataStoreImpl(IClusterGlobalServices clusterGlobalServices) throws CacheExistException, CacheConfigException {
+        Preconditions.checkNotNull(clusterGlobalServices, "clusterGlobalServices cannot be null");
+
+        operationalDataCache = clusterGlobalServices.createCache(OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+
+        if(operationalDataCache == null){
+            Preconditions.checkNotNull(operationalDataCache, "operationalDataCache cannot be null");
+        }
+
+        configurationDataCache = clusterGlobalServices.createCache(CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+
+        if(configurationDataCache == null){
+            Preconditions.checkNotNull(configurationDataCache, "configurationDataCache cannot be null");
+        }
+
+    }
+
+    @Override
+    public DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> requestCommit(DataModification<InstanceIdentifier<? extends Object>, Object> modification) {
+        return new ClusteredDataStoreTransaction(modification);
+    }
+
+    @Override
+    public Object readOperationalData(InstanceIdentifier<? extends Object> path) {
+        Preconditions.checkNotNull(path, "path cannot be null");
+        return operationalDataCache.get(path);
+    }
+
+    @Override
+    public Object readConfigurationData(InstanceIdentifier<? extends Object> path) {
+        Preconditions.checkNotNull(path, "path cannot be null");
+        return configurationDataCache.get(path);
+    }
+
+    private RpcResult<Void> finish(final ClusteredDataStoreTransaction transaction) {
+      final DataModification<InstanceIdentifier<? extends Object>,Object> modification = transaction.getModification();
+
+      this.configurationDataCache.putAll(modification.getUpdatedConfigurationData());
+      this.operationalDataCache.putAll(modification.getUpdatedOperationalData());
+
+      for (final InstanceIdentifier<? extends Object> removal : modification.getRemovedConfigurationData()) {
+        this.configurationDataCache.remove(removal);
+      }
+
+      for (final InstanceIdentifier<? extends Object> removal : modification.getRemovedOperationalData()) {
+        this.operationalDataCache.remove(removal  );
+      }
+
+      Set<RpcError> _emptySet = Collections.<RpcError>emptySet();
+      return Rpcs.<Void>getRpcResult(true, null, _emptySet);
+    }
+
+    private RpcResult<Void> rollback(final ClusteredDataStoreTransaction transaction) {
+      Set<RpcError> _emptySet = Collections.<RpcError>emptySet();
+      return Rpcs.<Void>getRpcResult(true, null, _emptySet);
+    }
+
+    private class ClusteredDataStoreTransaction implements DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> {
+        private final DataModification<InstanceIdentifier<? extends Object>,Object> modification;
+
+        public ClusteredDataStoreTransaction(DataModification<InstanceIdentifier<? extends Object>,Object> modification){
+            Preconditions.checkNotNull(modification, "modification cannot be null");
+
+            this.modification = modification;
+        }
+
+        @Override
+        public DataModification<InstanceIdentifier<? extends Object>, Object> getModification() {
+            return this.modification;
+        }
+
+        @Override
+        public RpcResult<Void> finish() throws IllegalStateException {
+            return ClusteredDataStoreImpl.this.finish(this);
+        }
+
+        @Override
+        public RpcResult<Void> rollback() throws IllegalStateException {
+            return ClusteredDataStoreImpl.this.rollback(this);
+        }
+    }
+}
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreManager.java b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreManager.java
new file mode 100644 (file)
index 0000000..42ed2bb
--- /dev/null
@@ -0,0 +1,71 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+
+package org.opendaylight.controller.datastore.internal;
+
+import com.google.common.base.Preconditions;
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.datastore.ClusteredDataStore;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class ClusteredDataStoreManager implements ClusteredDataStore {
+
+    private ClusteredDataStoreImpl clusteredDataStore = null;
+    private IClusterGlobalServices clusterGlobalServices = null;
+
+    @Override
+    public DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> requestCommit(DataModification<InstanceIdentifier<? extends Object>, Object> modification) {
+        Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
+        return clusteredDataStore.requestCommit(modification);
+    }
+
+    @Override
+    public Object readOperationalData(InstanceIdentifier<? extends Object> path) {
+        Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
+        return clusteredDataStore.readOperationalData(path);
+    }
+
+    @Override
+    public Object readConfigurationData(InstanceIdentifier<? extends Object> path) {
+        Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
+        return clusteredDataStore.readConfigurationData(path);
+    }
+
+
+    public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices){
+        this.clusterGlobalServices = clusterGlobalServices;
+    }
+
+    public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices){
+        this.clusterGlobalServices = null;
+        this.clusteredDataStore = null;
+    }
+
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init(Component c) {
+        try {
+            clusteredDataStore = new ClusteredDataStoreImpl(clusterGlobalServices);
+        } catch (CacheExistException e) {
+            throw new IllegalStateException("could not construct clusteredDataStore");
+        } catch (CacheConfigException e) {
+            throw new IllegalStateException("could not construct clusteredDataStore");
+        }
+    }
+}
index d36e9ba..5ced9d9 100644 (file)
@@ -1,13 +1,70 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
 package org.opendaylight.controller.datastore.internal;
 
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ServiceDependency;
+
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 
 import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class ActivatorTest {
 
+       private static  ServiceDependency serviceDependency;
+       
+       @BeforeClass 
+       public static void initialize(){
+               serviceDependency = mock(ServiceDependency.class);
+       }
+       
+       private class ActivatorTestImpl extends Activator{
+                protected ServiceDependency createServiceDependency() {
+                       return ActivatorTest.serviceDependency;
+                   }
+       }
+       
     @Test
     public void construct(){
         assertNotNull(new Activator());
     }
+    
+    @Test
+    public void construct_OnInvokeOfGlobalImpl_ShouldReturnNotNullObject(){
+        Activator activator = new Activator();
+        
+        assertNotNull(activator.getGlobalImplementations());
+        assertEquals(ClusteredDataStoreManager.class,activator.getGlobalImplementations()[0]);
+    }
+    
+    @Test
+    public void construct_OnInvokeOfConfigGlobalInstance_ShouldNotThrowAnyExceptions(){
+       Activator activator = new ActivatorTestImpl();
+       
+       Component c = mock(Component.class);
+       Object clusterDataStoreMgr = ClusteredDataStoreManager.class;
+       
+       when(serviceDependency.setService(IClusterGlobalServices.class)).thenReturn(serviceDependency);
+       when(serviceDependency.setCallbacks("setClusterGlobalServices",
+                    "unsetClusterGlobalServices")).thenReturn(serviceDependency);
+       when(serviceDependency.setRequired(true)).thenReturn(serviceDependency);
+       
+       
+       activator.configureGlobalInstance(c, clusterDataStoreMgr);
+       
+       
+    }
+    
 }
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImplTest.java b/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImplTest.java
new file mode 100644 (file)
index 0000000..8049bae
--- /dev/null
@@ -0,0 +1,248 @@
+package org.opendaylight.controller.datastore.internal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ClusteredDataStoreImplTest {
+    @Before
+    public void setUp(){
+
+    }
+
+    @Test
+    public void constructor_WhenPassedANullClusteringServices_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
+        try {
+            new ClusteredDataStoreImpl(null);
+        } catch(NullPointerException npe){
+            assertEquals("clusterGlobalServices cannot be null", npe.getMessage());
+        }
+    }
+
+    @Test
+    public void constructor_WhenClusteringServicesReturnsANullOperationalDataCache_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
+        try {
+            new ClusteredDataStoreImpl(mock(IClusterGlobalServices.class));
+        } catch(NullPointerException npe){
+            assertEquals("operationalDataCache cannot be null", npe.getMessage());
+        }
+    }
+
+    @Test
+    public void constructor_WhenClusteringServicesReturnsANullOConfigurationDataCache_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+        // Confused about the following line?
+        // See this http://stackoverflow.com/questions/10952629/a-strange-generics-edge-case-with-mockito-when-and-generic-type-inference
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap<Object, Object>());
+
+
+        try {
+            new ClusteredDataStoreImpl(mockClusterGlobalServices);
+        } catch(NullPointerException npe){
+            assertEquals("configurationDataCache cannot be null", npe.getMessage());
+        }
+    }
+
+    @Test
+    public void constructor_WhenPassedAValidClusteringServices_ShouldNotThrowAnyExceptions() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        new ClusteredDataStoreImpl(mockClusterGlobalServices);
+    }
+
+
+    @Test
+    public void readOperationalData_WhenPassedANullPath_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        try {
+            store.readOperationalData(null);
+        } catch(NullPointerException npe){
+            assertEquals("path cannot be null", npe.getMessage());
+        }
+    }
+
+    @Test
+    public void readOperationalData_WhenPassedAKeyThatDoesNotExistInTheCache_ShouldReturnNull() throws CacheExistException, CacheConfigException {
+        InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
+
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        assertNull(store.readOperationalData(path));
+    }
+
+    @Test
+    public void readOperationalData_WhenPassedAKeyThatDoesExistInTheCache_ShouldReturnTheValueObject() throws CacheExistException, CacheConfigException {
+        InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
+
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ConcurrentMap mockOperationalDataCache = mock(ConcurrentMap.class);
+
+        Object valueObject = mock(Object.class);
+
+        when(mockOperationalDataCache.get(path)).thenReturn(valueObject);
+
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap<Object, Object>());
+
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        assertEquals(valueObject, store.readOperationalData(path));
+    }
+
+
+
+    @Test
+    public void readConfigurationData_WhenPassedANullPath_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
+
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        try {
+            store.readConfigurationData(null);
+        } catch(NullPointerException npe){
+            assertEquals("path cannot be null", npe.getMessage());
+        }
+    }
+
+
+    @Test
+    public void readConfigurationData_WhenPassedAKeyThatDoesNotExistInTheCache_ShouldReturnNull() throws CacheExistException, CacheConfigException {
+        InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
+
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        assertNull(store.readConfigurationData(path));
+    }
+
+    @Test
+    public void readConfigurationData_WhenPassedAKeyThatDoesExistInTheCache_ShouldReturnTheValueObject() throws CacheExistException, CacheConfigException {
+        InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
+
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ConcurrentMap mockConfigurationDataCache = mock(ConcurrentMap.class);
+
+        Object valueObject = mock(Object.class);
+
+        when(mockConfigurationDataCache.get(path)).thenReturn(valueObject);
+
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
+
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        assertEquals(valueObject, store.readConfigurationData(path));
+    }
+
+
+    @Test
+    public void requestCommit_ShouldReturnADataTransaction() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        assertNotNull(store.requestCommit(mock(DataModification.class)));
+
+
+    }
+
+    @Test
+    public void finishingADataTransaction_ShouldUpdateTheUnderlyingCache() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+        ConcurrentMap mockConfigurationDataCache = mock(ConcurrentMap.class);
+        ConcurrentMap mockOperationalDataCache = mock(ConcurrentMap.class);
+
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        DataModification mockModification = mock(DataModification.class);
+
+        Map configurationData = mock(Map.class);
+        Map operationalData = mock(Map.class);
+
+        when(mockModification.getUpdatedConfigurationData()).thenReturn(configurationData);
+        when(mockModification.getUpdatedOperationalData()).thenReturn(operationalData);
+
+        DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> transaction = store.requestCommit(mockModification);
+
+        transaction.finish();
+
+        verify(mockConfigurationDataCache).putAll(mockModification.getUpdatedConfigurationData());
+        verify(mockOperationalDataCache).putAll(mockModification.getUpdatedOperationalData());
+    }
+
+
+    @Test
+    public void rollingBackADataTransaction_ShouldDoNothing() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+        ConcurrentMap mockConfigurationDataCache = mock(ConcurrentMap.class);
+        ConcurrentMap mockOperationalDataCache = mock(ConcurrentMap.class);
+
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
+
+        ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+        DataModification mockModification = mock(DataModification.class);
+
+        Map configurationData = mock(Map.class);
+        Map operationalData = mock(Map.class);
+
+        when(mockModification.getUpdatedConfigurationData()).thenReturn(configurationData);
+        when(mockModification.getUpdatedOperationalData()).thenReturn(operationalData);
+
+        DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> transaction = store.requestCommit(mockModification);
+
+        transaction.rollback();
+
+        verify(mockConfigurationDataCache, never()).putAll(mockModification.getUpdatedConfigurationData());
+        verify(mockOperationalDataCache, never()).putAll(mockModification.getUpdatedOperationalData());
+
+    }
+
+
+    private IClusterGlobalServices createClusterGlobalServices() throws CacheExistException, CacheConfigException {
+        IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
+        Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
+
+        return mockClusterGlobalServices;
+    }
+}
diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreTest.java b/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreTest.java
deleted file mode 100644 (file)
index 7a8e8e8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.opendaylight.controller.datastore.internal;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotNull;
-
-public class ClusteredDataStoreTest {
-    @Test
-    public void construct(){
-        assertNotNull(new ClusteredDataStore());
-    }
-}

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.