From: Ed Warnicke Date: Fri, 8 Nov 2013 19:36:19 +0000 (+0000) Subject: Merge "Initial implementation of the ClusteredDataStore" X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~446 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=a1b55fb491e235c028e1d451aff4b1d261d5a86c;hp=ae9ef45ceff09b2ce7943e3be569ea217464b8bd Merge "Initial implementation of the ClusteredDataStore" --- diff --git a/opendaylight/md-sal/clustered-data-store/implementation/pom.xml b/opendaylight/md-sal/clustered-data-store/implementation/pom.xml index f822ac5d38..bb43809a5c 100644 --- a/opendaylight/md-sal/clustered-data-store/implementation/pom.xml +++ b/opendaylight/md-sal/clustered-data-store/implementation/pom.xml @@ -57,11 +57,21 @@ + + + com.google.guava + guava + org.opendaylight.controller sal-common-api 1.0-SNAPSHOT + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + org.opendaylight.controller sal @@ -77,6 +87,11 @@ junit test + + org.mockito + mockito-all + test + equinoxSDK381 org.eclipse.osgi 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 index 0000000000..0a577ad999 --- /dev/null +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/ClusteredDataStore.java @@ -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, Object>, DataCommitHandler,Object> { +} diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/Activator.java b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/Activator.java index 101da7ffa3..c94355d4f6 100644 --- a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/Activator.java +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/Activator.java @@ -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> props = new Hashtable>(); + + 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 index 7c25b14ea3..0000000000 --- a/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStore.java +++ /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, Object>, DataCommitHandler,Object> { - @Override - public DataCommitTransaction, Object> requestCommit(DataModification, Object> modification) { - return null; - } - - @Override - public Object readOperationalData(InstanceIdentifier path) { - return null; - } - - @Override - public Object readConfigurationData(InstanceIdentifier 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 index 0000000000..f2e7773a45 --- /dev/null +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImpl.java @@ -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, Object> requestCommit(DataModification, Object> modification) { + return new ClusteredDataStoreTransaction(modification); + } + + @Override + public Object readOperationalData(InstanceIdentifier path) { + Preconditions.checkNotNull(path, "path cannot be null"); + return operationalDataCache.get(path); + } + + @Override + public Object readConfigurationData(InstanceIdentifier path) { + Preconditions.checkNotNull(path, "path cannot be null"); + return configurationDataCache.get(path); + } + + private RpcResult finish(final ClusteredDataStoreTransaction transaction) { + final DataModification,Object> modification = transaction.getModification(); + + this.configurationDataCache.putAll(modification.getUpdatedConfigurationData()); + this.operationalDataCache.putAll(modification.getUpdatedOperationalData()); + + for (final InstanceIdentifier removal : modification.getRemovedConfigurationData()) { + this.configurationDataCache.remove(removal); + } + + for (final InstanceIdentifier removal : modification.getRemovedOperationalData()) { + this.operationalDataCache.remove(removal ); + } + + Set _emptySet = Collections.emptySet(); + return Rpcs.getRpcResult(true, null, _emptySet); + } + + private RpcResult rollback(final ClusteredDataStoreTransaction transaction) { + Set _emptySet = Collections.emptySet(); + return Rpcs.getRpcResult(true, null, _emptySet); + } + + private class ClusteredDataStoreTransaction implements DataCommitTransaction, Object> { + private final DataModification,Object> modification; + + public ClusteredDataStoreTransaction(DataModification,Object> modification){ + Preconditions.checkNotNull(modification, "modification cannot be null"); + + this.modification = modification; + } + + @Override + public DataModification, Object> getModification() { + return this.modification; + } + + @Override + public RpcResult finish() throws IllegalStateException { + return ClusteredDataStoreImpl.this.finish(this); + } + + @Override + public RpcResult 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 index 0000000000..42ed2bb98a --- /dev/null +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreManager.java @@ -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, Object> requestCommit(DataModification, Object> modification) { + Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null"); + return clusteredDataStore.requestCommit(modification); + } + + @Override + public Object readOperationalData(InstanceIdentifier path) { + Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null"); + return clusteredDataStore.readOperationalData(path); + } + + @Override + public Object readConfigurationData(InstanceIdentifier 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"); + } + } +} diff --git a/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ActivatorTest.java b/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ActivatorTest.java index d36e9baf2c..5ced9d9a41 100644 --- a/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ActivatorTest.java +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ActivatorTest.java @@ -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 index 0000000000..8049bae5af --- /dev/null +++ b/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImplTest.java @@ -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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap()); + + + 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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache); + Mockito.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap()); + + + 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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class)); + Mockito.>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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache); + Mockito.>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, 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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache); + Mockito.>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, 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.>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class)); + Mockito.>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 index 7a8e8e8d10..0000000000 --- a/opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreTest.java +++ /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()); - } -}