From 615bd465f9582fc62aa435381197dd92fb6d4069 Mon Sep 17 00:00:00 2001 From: Moiz Raja Date: Wed, 6 Nov 2013 15:38:13 -0800 Subject: [PATCH] Initial implementation of the ClusteredDataStore Please review and see if this implementation is headed in the right direction. At this point this is mostly unit testing. This should give an idea of what the code intends to do. The ClusteredDataStore is dependent on IClusterGlobalServices and provides a simple pass through mechanism. Change-Id: I2ab628a40fa8a44ae85be3ad678717ae139faa59 Signed-off-by: Moiz Raja --- .../implementation/pom.xml | 15 ++ .../datastore/ClusteredDataStore.java | 18 ++ .../datastore/internal/Activator.java | 32 +++ .../internal/ClusteredDataStore.java | 23 -- .../internal/ClusteredDataStoreImpl.java | 122 +++++++++ .../internal/ClusteredDataStoreManager.java | 71 +++++ .../datastore/internal/ActivatorTest.java | 57 ++++ .../internal/ClusteredDataStoreImplTest.java | 248 ++++++++++++++++++ .../internal/ClusteredDataStoreTest.java | 12 - 9 files changed, 563 insertions(+), 35 deletions(-) create mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/ClusteredDataStore.java delete mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStore.java create mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImpl.java create mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/main/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreManager.java create mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreImplTest.java delete mode 100644 opendaylight/md-sal/clustered-data-store/implementation/src/test/java/org/opendaylight/controller/datastore/internal/ClusteredDataStoreTest.java 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()); - } -} -- 2.36.6