Refactor data types cache 06/120906/5
authorandre.schmid <andre.schmid@est.tech>
Thu, 22 Apr 2021 11:33:04 +0000 (12:33 +0100)
committerChristophe Closset <christophe.closset@intl.att.com>
Thu, 29 Apr 2021 15:15:34 +0000 (15:15 +0000)
Avoids potential issue of data type cache changes by external parties,
by returning copies from the cache instead of the original.
Refactors the code for more clarity.

Change-Id: Ibb518bf638f2f4ee1f5e3869baaace374efb632a
Issue-ID: SDC-3569
Signed-off-by: André Schmid <andre.schmid@est.tech>
catalog-model/pom.xml
catalog-model/src/main/java/org/openecomp/sdc/be/model/DataTypeDefinition.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/cache/ApplicationCache.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/cache/ApplicationDataTypeCache.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AbstractOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/cache/ApplicationDataTypeCacheTest.java

index 17b1a0e..7666076 100644 (file)
     <version>1.9.0-SNAPSHOT</version>
   </parent>
 
+  <properties>
+    <awaitility.version>4.0.3</awaitility.version>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <scope>test</scope>
     </dependency>
 
+    <dependency>
+      <groupId>org.awaitility</groupId>
+      <artifactId>awaitility</artifactId>
+      <version>${awaitility.version}</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.codehaus.groovy</groupId>
       <artifactId>groovy</artifactId>
index 6c28580..b61aa5a 100644 (file)
@@ -37,17 +37,18 @@ public class DataTypeDefinition extends DataTypeDataDefinition {
     private List<PropertyConstraint> constraints;
     private List<PropertyDefinition> properties;
 
-    public DataTypeDefinition(DataTypeDataDefinition p) {
-        super(p);
+    public DataTypeDefinition(final DataTypeDataDefinition dataTypeDataDefinition) {
+        super(dataTypeDataDefinition);
     }
 
-    public DataTypeDefinition(DataTypeDefinition pd) {
-        this.setName(pd.getName());
-        this.setDerivedFrom(pd.getDerivedFrom());
-        this.setDerivedFromName(pd.getDerivedFromName());
-        this.setUniqueId(pd.getUniqueId());
-        this.setConstraints(pd.getConstraints());
-        this.setDescription(pd.getDescription());
+    public DataTypeDefinition(final DataTypeDefinition dataTypeDefinition) {
+        super(dataTypeDefinition);
+        this.setName(dataTypeDefinition.getName());
+        this.setDerivedFrom(dataTypeDefinition.getDerivedFrom());
+        this.setDerivedFromName(dataTypeDefinition.getDerivedFromName());
+        this.setUniqueId(dataTypeDefinition.getUniqueId());
+        this.setConstraints(dataTypeDefinition.getConstraints());
+        this.setDescription(dataTypeDefinition.getDescription());
     }
 
     public List<PropertyConstraint> safeGetConstraints() {
index 4c58285..d0a0719 100644 (file)
@@ -25,7 +25,7 @@ import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 
 public interface ApplicationCache<T> {
 
-    public abstract Either<Map<String, T>, JanusGraphOperationStatus> getAll();
+    Either<Map<String, T>, JanusGraphOperationStatus> getAll();
 
-    public abstract Either<T, JanusGraphOperationStatus> get(String uniqueId);
+    Either<T, JanusGraphOperationStatus> get(String uniqueId);
 }
index d6cc01b..a1bafbc 100644 (file)
 package org.openecomp.sdc.be.model.cache;
 
 import fj.data.Either;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
+import java.util.Optional;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.stream.Collectors;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
-import javax.annotation.Resource;
+import lombok.AccessLevel;
 import lombok.Getter;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
-import org.openecomp.sdc.be.config.Configuration.ApplicationL1CacheConfig;
 import org.openecomp.sdc.be.config.Configuration.ApplicationL1CacheInfo;
 import org.openecomp.sdc.be.config.ConfigurationManager;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
-import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEvent;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Component;
@@ -58,49 +55,68 @@ import org.springframework.stereotype.Component;
 public class ApplicationDataTypeCache implements ApplicationCache<DataTypeDefinition>, Runnable {
 
     private static final String APPLICATION_DATA_TYPES_CACHE = "ApplicationDataTypesCache";
-    private static final Logger log = Logger.getLogger(ApplicationDataTypeCache.class.getName());
-    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
-    private final Lock r = rwl.readLock();
-    private final Lock w = rwl.writeLock();
-    ScheduledFuture<?> scheduledFuture = null;
-    private Map<String, DataTypeDefinition> data = new HashMap<>();
-    private ScheduledExecutorService scheduledPollingService = Executors
-        .newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("ApplicationDataTypeCacheThread-%d").build());
+    private static final Logger log = Logger.getLogger(ApplicationDataTypeCache.class);
+
+    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+    private final PropertyOperation propertyOperation;
+    private final ApplicationEventPublisher applicationEventPublisher;
+    @Getter(AccessLevel.PACKAGE)
+    private final ScheduledExecutorService scheduledPollingService;
+    @Getter(AccessLevel.PACKAGE)
+    private ScheduledFuture<?> scheduledFuture = null;
+    private Map<String, DataTypeDefinition> dataTypesCacheMap = new HashMap<>();
     private int firstRunDelayInSec = 30;
     private int pollingIntervalInSec = 60;
-    @Resource
-    private PropertyOperation propertyOperation;
-    @Autowired
-    private ApplicationEventPublisher applicationEventPublisher;
+
+    public ApplicationDataTypeCache(final PropertyOperation propertyOperation, final ApplicationEventPublisher applicationEventPublisher) {
+        this.propertyOperation = propertyOperation;
+        this.applicationEventPublisher = applicationEventPublisher;
+        scheduledPollingService = Executors
+            .newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("ApplicationDataTypeCacheThread-%d").build());
+    }
 
     @PostConstruct
-    public void init() {
-        ApplicationL1CacheConfig applicationL1CacheConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getApplicationL1Cache();
-        if (applicationL1CacheConfig != null) {
-            if (applicationL1CacheConfig.getDatatypes() != null) {
-                ApplicationL1CacheInfo datatypesInfo = applicationL1CacheConfig.getDatatypes();
-                if (datatypesInfo.getEnabled()) {
-                    Integer intervalInSec = datatypesInfo.getPollIntervalInSec();
-                    if (intervalInSec != null) {
-                        pollingIntervalInSec = intervalInSec;
-                    }
-                    Integer firstRunDelay = datatypesInfo.getFirstRunDelay();
-                    if (firstRunDelay != null) {
-                        firstRunDelayInSec = firstRunDelay;
-                    }
-                    log.trace("ApplicationDataTypesCache polling interval is {} seconds.", pollingIntervalInSec);
-                    if (scheduledPollingService != null) {
-                        log.debug("Start ApplicationDataTypeCache polling task. polling interval {} seconds", pollingIntervalInSec);
-                        scheduledFuture = scheduledPollingService
-                            .scheduleAtFixedRate(this, firstRunDelayInSec, pollingIntervalInSec, TimeUnit.SECONDS);
-                    }
-                }
-            } else {
-                BeEcompErrorManager.getInstance().logInternalFlowError(APPLICATION_DATA_TYPES_CACHE, "Cache is disabled", ErrorSeverity.INFO);
-            }
-        } else {
-            BeEcompErrorManager.getInstance().logInternalFlowError(APPLICATION_DATA_TYPES_CACHE, "Cache is disabled", ErrorSeverity.INFO);
+    void init() {
+        final Optional<ApplicationL1CacheInfo> dataTypeCacheConfigOptional = getDataTypeCacheConfig();
+        if (dataTypeCacheConfigOptional.isEmpty()) {
+            BeEcompErrorManager.getInstance()
+                .logInternalFlowError(APPLICATION_DATA_TYPES_CACHE, "Data types cache is not configured and will be disabled", ErrorSeverity.INFO);
+            return;
+        }
+        final ApplicationL1CacheInfo dataTypesCacheInfo = dataTypeCacheConfigOptional.get();
+        if (!Boolean.TRUE.equals(dataTypesCacheInfo.getEnabled())) {
+            BeEcompErrorManager.getInstance().logInternalFlowError(APPLICATION_DATA_TYPES_CACHE, "Data types cache is disabled", ErrorSeverity.INFO);
+            return;
+        }
+        loadConfigurationValues(dataTypesCacheInfo);
+        if (scheduledPollingService != null) {
+            log.debug("Starting ApplicationDataTypeCache polling task. Initial delay {}s and polling interval {}s",
+                firstRunDelayInSec, pollingIntervalInSec);
+            scheduledFuture = scheduledPollingService
+                .scheduleAtFixedRate(this, firstRunDelayInSec, pollingIntervalInSec, TimeUnit.SECONDS);
+        }
+    }
+
+    private void loadConfigurationValues(final ApplicationL1CacheInfo dataTypesCacheInfo) {
+        final Integer firstRunDelay = dataTypesCacheInfo.getFirstRunDelay();
+        if (firstRunDelay != null) {
+            firstRunDelayInSec = firstRunDelay;
+        }
+        log.trace("ApplicationDataTypesCache initial delay configured to {} seconds.", firstRunDelayInSec);
+
+        final Integer intervalInSec = dataTypesCacheInfo.getPollIntervalInSec();
+        if (intervalInSec != null) {
+            pollingIntervalInSec = intervalInSec;
         }
+        log.trace("ApplicationDataTypesCache polling interval configured to {} seconds.", pollingIntervalInSec);
+    }
+
+    private Optional<ApplicationL1CacheInfo> getDataTypeCacheConfig() {
+        final var applicationL1CacheConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getApplicationL1Cache();
+        if (applicationL1CacheConfig == null || applicationL1CacheConfig.getDatatypes() == null) {
+            return Optional.empty();
+        }
+        return Optional.ofNullable(applicationL1CacheConfig.getDatatypes());
     }
 
     @PreDestroy
@@ -147,138 +163,164 @@ public class ApplicationDataTypeCache implements ApplicationCache<DataTypeDefini
     @Override
     public Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> getAll() {
         try {
-            r.lock();
-            if (data == null || data.isEmpty()) {
+            readWriteLock.readLock().lock();
+            if (MapUtils.isEmpty(dataTypesCacheMap)) {
                 return getAllDataTypesFromGraph();
             }
-            return Either.left(data);
+            return Either.left(new HashMap<>(dataTypesCacheMap));
         } finally {
-            r.unlock();
+            readWriteLock.readLock().unlock();
         }
     }
 
     @Override
     public Either<DataTypeDefinition, JanusGraphOperationStatus> get(String uniqueId) {
         try {
-            r.lock();
-            if (data == null || data.isEmpty()) {
+            readWriteLock.readLock().lock();
+            if (MapUtils.isEmpty(dataTypesCacheMap)) {
+                return propertyOperation.getDataTypeByUid(uniqueId);
+            }
+
+            final Optional<DataTypeDefinition> dataTypeDefinition = dataTypesCacheMap.values().stream()
+                .filter(p -> p.getUniqueId().equals(uniqueId)).findFirst();
+            if (dataTypeDefinition.isEmpty()) {
                 return propertyOperation.getDataTypeByUid(uniqueId);
-            } else {
-                DataTypeDefinition dataTypeDefinition = data.values().stream().filter(p -> p.getUniqueId().equals(uniqueId)).findFirst().orElse(null);
-                if (dataTypeDefinition == null) {
-                    return propertyOperation.getDataTypeByUid(uniqueId);
-                } else {
-                    return Either.left(dataTypeDefinition);
-                }
             }
+            return Either.left(new DataTypeDefinition(dataTypeDefinition.get()));
         } finally {
-            r.unlock();
+            readWriteLock.readLock().unlock();
         }
     }
 
     @Override
     public void run() {
-        log.trace("run() method. polling db to fetch data types");
         try {
-            Long start = System.currentTimeMillis();
-            log.trace("Start fetching all data types from db");
-            Either<List<DataTypeData>, JanusGraphOperationStatus> allDataTypeNodes = propertyOperation.getAllDataTypeNodes();
-            Long end = System.currentTimeMillis();
-            log.trace("Finish fetching all data types from db. Took {} Milliseconds", (end - start));
-            if (allDataTypeNodes.isRight()) {
-                JanusGraphOperationStatus status = allDataTypeNodes.right().value();
-                if (status != JanusGraphOperationStatus.OK) {
-                    log.debug("ApplicationDataTypesCache - Failed to fetch all data types nodes");
-                    BeEcompErrorManager.getInstance()
-                        .logInternalConnectionError("FetchDataTypes", "Failed to fetch data types from graph(cache)", ErrorSeverity.INFO);
-                }
-            } else {
-                List<DataTypeData> list = allDataTypeNodes.left().value();
-                if (list != null) {
-                    Map<String, ImmutablePair<Long, Long>> dataTypeNameToModificationTime = list.stream().collect(Collectors
-                        .toMap(p -> p.getDataTypeDataDefinition().getName(), p -> new ImmutablePair<>(p.getDataTypeDataDefinition().getCreationTime(),
-                            p.getDataTypeDataDefinition().getModificationTime())));
-                    Map<String, ImmutablePair<Long, Long>> currentDataTypeToModificationTime = new HashMap<>();
-                    try {
-                        r.lock();
-                        if (data != null) {
-                            currentDataTypeToModificationTime = data.values().stream().collect(Collectors
-                                .toMap(DataTypeDataDefinition::getName, p -> new ImmutablePair<>(p.getCreationTime(), p.getModificationTime())));
-                        }
-                    } finally {
-                        r.unlock();
-                    }
-                    boolean isChanged = compareDataTypes(dataTypeNameToModificationTime, currentDataTypeToModificationTime);
-                    if (isChanged) {
-                        replaceAllData();
-                    }
-                }
+            final long startTime = System.currentTimeMillis();
+            log.trace("Starting refresh data types cache job");
+            if (hasDataTypesChanged()) {
+                log.info("Detected changes in the data types, updating the data type cache.");
+                refreshDataTypesCache();
             }
-        } catch (Exception e) {
-            log.debug("unexpected error occured", e);
-            BeEcompErrorManager.getInstance()
-                .logInternalUnexpectedError(APPLICATION_DATA_TYPES_CACHE, "Failed to run refresh data types job", ErrorSeverity.INFO);
+            log.trace("Finished refresh data types cache job. Finished in {}ms", (System.currentTimeMillis() - startTime));
+        } catch (final Exception e) {
+            var errorMsg = "Failed to run refresh data types cache job";
+            log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, ApplicationDataTypeCache.class.getName(), errorMsg, e);
+            BeEcompErrorManager.getInstance().logInternalUnexpectedError(APPLICATION_DATA_TYPES_CACHE, errorMsg, ErrorSeverity.INFO);
         } finally {
             try {
                 propertyOperation.getJanusGraphGenericDao().commit();
-            } catch (Exception e) {
-                log.trace("Failed to commit ApplicationDataTypeCache", e);
+            } catch (final Exception e) {
+                log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, ApplicationDataTypeCache.class.getName(),
+                    "Failed to commit ApplicationDataTypeCache", e);
             }
         }
     }
 
-    private boolean compareDataTypes(Map<String, ImmutablePair<Long, Long>> dataTypeNameToModificationTime,
-                                     Map<String, ImmutablePair<Long, Long>> currentDataTypeToModificationTime) {
-        if (dataTypeNameToModificationTime.size() != currentDataTypeToModificationTime.size()) {
+    private boolean hasDataTypesChanged() {
+        final List<DataTypeData> dataTypeListFromDatabase = findAllDataTypesLazy();
+        final Map<String, DataTypeDefinition> dataTypesCacheCopyMap = copyDataTypeCache();
+
+        if (dataTypeListFromDatabase.size() != dataTypesCacheCopyMap.size()) {
+            log.debug("Total of cached data types '{}' differs from the actual '{}'", dataTypeListFromDatabase.size(),  dataTypesCacheCopyMap.size());
             return true;
-        } else {
-            Set<String> currentkeySet = currentDataTypeToModificationTime.keySet();
-            Set<String> keySet = dataTypeNameToModificationTime.keySet();
-            if (currentkeySet.containsAll(keySet)) {
-                for (Entry<String, ImmutablePair<Long, Long>> entry : dataTypeNameToModificationTime.entrySet()) {
-                    String dataTypeName = entry.getKey();
-                    ImmutablePair<Long, Long> creationAndModificationTimes = entry.getValue();
-                    long creationTime = creationAndModificationTimes.getLeft() == null ? 0 : creationAndModificationTimes.getLeft().longValue();
-                    long modificationTime = creationAndModificationTimes.getRight() == null ? 0 : creationAndModificationTimes.getRight().longValue();
-                    ImmutablePair<Long, Long> currentEntry = currentDataTypeToModificationTime.get(dataTypeName);
-                    long currentCreationTime = currentEntry.getLeft() == null ? 0 : currentEntry.getLeft().longValue();
-                    long currentModificationTime = currentEntry.getRight() == null ? 0 : currentEntry.getRight().longValue();
-                    if (creationTime > currentCreationTime || modificationTime > currentModificationTime) {
-                        log.debug("Datatype {} was updated. Creation Time  {} vs {}. Modification Time {} vs {}", dataTypeName, currentCreationTime,
-                            creationTime, currentModificationTime, modificationTime);
-                        return true;
-                    }
-                }
-            } else {
+        }
+
+        if (CollectionUtils.isEmpty(dataTypeListFromDatabase)) {
+            log.debug("Both data type cache and database are empty");
+            return false;
+        }
+
+        return hasDataTypesChanged(dataTypeListFromDatabase, dataTypesCacheCopyMap);
+    }
+
+    private boolean hasDataTypesChanged(final List<DataTypeData> dataTypeListFromDatabase, final Map<String, DataTypeDefinition> dataTypesCacheCopyMap) {
+        return dataTypeListFromDatabase.stream().map(DataTypeData::getDataTypeDataDefinition).anyMatch(actualDataTypeDefinition -> {
+            final String dataTypeName = actualDataTypeDefinition.getName();
+            final DataTypeDefinition cachedDataTypeDefinition = dataTypesCacheCopyMap.get(dataTypeName);
+            if (cachedDataTypeDefinition == null) {
+                log.debug("Datatype '{}' is not present in the cache. ", dataTypeName);
                 return true;
             }
+
+            final long cachedCreationTime = cachedDataTypeDefinition.getCreationTime() == null ? 0 : cachedDataTypeDefinition.getCreationTime();
+            final long actualCreationTime = actualDataTypeDefinition.getCreationTime() == null ? 0 : actualDataTypeDefinition.getCreationTime();
+            if (cachedCreationTime != actualCreationTime) {
+                log.debug("Datatype '{}' was updated. Cache/database creation time '{}'/'{}'.",
+                    dataTypeName, cachedCreationTime, actualCreationTime);
+                return true;
+            }
+            final long cachedModificationTime =
+                cachedDataTypeDefinition.getModificationTime() == null ? 0 : cachedDataTypeDefinition.getModificationTime();
+            final long actualModificationTime =
+                actualDataTypeDefinition.getModificationTime() == null ? 0 : actualDataTypeDefinition.getModificationTime();
+            if (cachedModificationTime != actualModificationTime) {
+                log.debug("Datatype '{}' was updated. Cache/database modification time '{}'/'{}'.",
+                    dataTypeName, cachedModificationTime, actualModificationTime);
+                return true;
+            }
+
+            return false;
+        });
+    }
+
+    private Map<String, DataTypeDefinition> copyDataTypeCache() {
+        try {
+            readWriteLock.readLock().lock();
+            return new HashMap<>(this.dataTypesCacheMap);
+        } finally {
+            readWriteLock.readLock().unlock();
         }
-        return false;
     }
 
-    private void replaceAllData() {
-        Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = propertyOperation.getAllDataTypes();
+    private void refreshDataTypesCache() {
+        final Map<String, DataTypeDefinition> dataTypesDefinitionMap = findAllDataTypesEager();
+        if (dataTypesDefinitionMap.isEmpty()) {
+            return;
+        }
+        try {
+            readWriteLock.writeLock().lock();
+            dataTypesCacheMap = dataTypesDefinitionMap;
+            onDataChangeEventEmit();
+            BeEcompErrorManager.getInstance()
+                .logInternalFlowError("ReplaceDataTypesCache", "Succeed to replace the data types cache", ErrorSeverity.INFO);
+        } finally {
+            readWriteLock.writeLock().unlock();
+        }
+    }
+
+    private Map<String, DataTypeDefinition> findAllDataTypesEager() {
+        log.trace("Fetching data types from database, eager mode");
+        final long startTime = System.currentTimeMillis();
+        final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = propertyOperation.getAllDataTypes();
+        log.trace("Finish fetching data types from database. Took {}ms", (System.currentTimeMillis() - startTime));
         if (allDataTypes.isRight()) {
-            JanusGraphOperationStatus status = allDataTypes.right().value();
-            log.debug("Failed to fetch all data types from db. Status is {}", status);
-        } else {
-            try {
-                w.lock();
-                data = allDataTypes.left().value();
-                // send notification on data types change
-                onDataChangeEventEmit(data);
-                BeEcompErrorManager.getInstance()
-                    .logInternalFlowError("ReplaceDataTypesCache", "Succeed to replace the data types cache", ErrorSeverity.INFO);
-            } finally {
-                w.unlock();
-            }
+            final JanusGraphOperationStatus status = allDataTypes.right().value();
+            var errorMsg= String.format("Failed to fetch data types from database. Status is %s", status);
+            log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, ApplicationDataTypeCache.class.getName(), errorMsg);
+            BeEcompErrorManager.getInstance().logInternalConnectionError(APPLICATION_DATA_TYPES_CACHE, errorMsg, ErrorSeverity.ERROR);
+            return Collections.emptyMap();
         }
+        return allDataTypes.left().value();
     }
 
-    private void onDataChangeEventEmit(Map<String, DataTypeDefinition> newData) {
-        log.trace("Cache data has changed, sending event to all listening for this change.");
-        DataTypesCacheChangedEvent dataTypesCacheChangedEvent = new DataTypesCacheChangedEvent(this, newData);
-        applicationEventPublisher.publishEvent(dataTypesCacheChangedEvent);
+    private List<DataTypeData> findAllDataTypesLazy() {
+        log.trace("Fetching data types from database, lazy mode");
+        final long startTime = System.currentTimeMillis();
+        final Either<List<DataTypeData>, JanusGraphOperationStatus> allDataTypes = propertyOperation.getAllDataTypeNodes();
+        log.trace("Finish fetching data types from database. Took {}ms", (System.currentTimeMillis() - startTime));
+        if (allDataTypes.isRight()) {
+            final JanusGraphOperationStatus status = allDataTypes.right().value();
+            var errorMsg= String.format("Failed to fetch data types from database. Status is %s", status);
+            log.error(EcompLoggerErrorCode.UNKNOWN_ERROR, ApplicationDataTypeCache.class.getName(), errorMsg);
+            BeEcompErrorManager.getInstance().logInternalConnectionError(APPLICATION_DATA_TYPES_CACHE, errorMsg, ErrorSeverity.ERROR);
+            return Collections.emptyList();
+        }
+        return allDataTypes.left().value();
+    }
+
+    private void onDataChangeEventEmit() {
+        log.trace("Data type cache has changed, sending DataTypesCacheChangedEvent.");
+        applicationEventPublisher.publishEvent(new DataTypesCacheChangedEvent(this, copyDataTypeCache()));
     }
 
     /**
@@ -287,11 +329,12 @@ public class ApplicationDataTypeCache implements ApplicationCache<DataTypeDefini
     public static class DataTypesCacheChangedEvent extends ApplicationEvent {
 
         @Getter
-        private Map<String, DataTypeDefinition> newData;
+        private final Map<String, DataTypeDefinition> newData;
 
-        public DataTypesCacheChangedEvent(Object source, Map<String, DataTypeDefinition> newData) {
+        public DataTypesCacheChangedEvent(final Object source, final Map<String, DataTypeDefinition> newData) {
             super(source);
             this.newData = newData;
         }
     }
+
 }
index 1592782..db379f5 100644 (file)
@@ -42,7 +42,6 @@ import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.IComplexDefaultValue;
 import org.openecomp.sdc.be.model.PropertyConstraint;
-import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
@@ -60,8 +59,6 @@ public abstract class AbstractOperation {
     @Autowired
     protected HealingJanusGraphGenericDao janusGraphGenericDao;
     protected Gson gson = new Gson();
-    @Autowired
-    protected ApplicationDataTypeCache applicationDataTypeCache;
     protected DataTypeValidatorConverter dataTypeValidatorConverter = DataTypeValidatorConverter.getInstance();
 
     public <ElementDefinition> JanusGraphOperationStatus findAllResourceElementsDefinitionRecursively(String resourceId,
index 7906467..0632364 100644 (file)
@@ -1562,14 +1562,10 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe
     }
 
     public Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypeNodes() {
-        Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypes = janusGraphGenericDao
-            .getByCriteria(NodeTypeEnum.DataType, null, DataTypeData.class);
-        if (getAllDataTypes.isRight()) {
-            JanusGraphOperationStatus status = getAllDataTypes.right().value();
-            if (status == JanusGraphOperationStatus.NOT_FOUND) {
-                status = JanusGraphOperationStatus.OK;
-                return Either.right(status);
-            }
+        final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypes =
+            janusGraphGenericDao.getByCriteria(NodeTypeEnum.DataType, null, DataTypeData.class);
+        if (getAllDataTypes.isRight() && getAllDataTypes.right().value() == JanusGraphOperationStatus.NOT_FOUND) {
+            return Either.left(Collections.emptyList());
         }
         return getAllDataTypes;
     }
index 7186d2a..9126b64 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed 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.
 
 package org.openecomp.sdc.be.model.cache;
 
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
 import fj.data.Either;
-import mockit.Deencapsulation;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.junit.Before;
-import org.junit.Test;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.config.Configuration;
+import org.openecomp.sdc.be.config.Configuration.ApplicationL1CacheConfig;
+import org.openecomp.sdc.be.config.Configuration.ApplicationL1CacheInfo;
+import org.openecomp.sdc.be.config.ConfigurationManager;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
-import org.openecomp.sdc.be.unittests.utils.ModelConfDependentTest;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
 import org.springframework.context.ApplicationEventPublisher;
 
-public class ApplicationDataTypeCacheTest extends ModelConfDependentTest{
+class ApplicationDataTypeCacheTest {
+
+    @Mock
+    private PropertyOperation propertyOperation;
+
+    @Mock
+       private ApplicationEventPublisher applicationEventPublisher;
 
-       @InjectMocks
-       private ApplicationDataTypeCache testSubject;
-       
-       @Mock
-       PropertyOperation propertyOperation;
+    @InjectMocks
+    private ApplicationDataTypeCache applicationDataTypeCache;
 
-       @Mock
-       ApplicationEventPublisher applicationEventPublisher;
+    private Map<String, DataTypeDefinition> dataTypeDefinitionMap;
 
-       @Before
-       public void setUpMocks() throws Exception {
-               MockitoAnnotations.initMocks(this);
+    private int schedulerFirstRunDelay = 0;
+    private int schedulerPollIntervalInSec = 2;
+    private boolean schedulerIsEnabled = true;
+
+       @BeforeEach
+       public void beforeEach() {
+               MockitoAnnotations.openMocks(this);
        }
 
+       @AfterEach
+       public void afterEach() {
+               final ScheduledExecutorService scheduledPollingService = applicationDataTypeCache.getScheduledPollingService();
+               if (scheduledPollingService == null) {
+                       return;
+               }
+
+               if (scheduledPollingService.isShutdown()) {
+                       return;
+               }
+
+               scheduledPollingService.shutdownNow();
+       }
 
        @Test
-       public void testInit() throws Exception {
-               testSubject.init();
+       void testInitSuccess() {
+               defaultInit();
+               assertNotNull(applicationDataTypeCache.getScheduledFuture(), "The job should have been triggered");
        }
 
        @Test
-       public void testDestroy() throws Exception {
-               testSubject.init();
-               Deencapsulation.invoke(testSubject, "destroy");
+       void testDestroySuccess() {
+               defaultInit();
+               assertNotNull(applicationDataTypeCache.getScheduledFuture(), "The job should have been triggered");
+               applicationDataTypeCache.destroy();
+               assertNull(applicationDataTypeCache.getScheduledFuture(), "The job should have been stopped");
+               assertTrue(applicationDataTypeCache.getScheduledPollingService().isShutdown(), "The scheduler should have been stopped");
        }
 
        @Test
-       public void testShutdownExecutor() throws Exception {
+       void testDestroyWithoutSchedulerInitialization() {
+               mockEmptyConfiguration();
+               applicationDataTypeCache.init();
+               assertNotNull(applicationDataTypeCache.getScheduledPollingService(), "The scheduler should have been created");
+               assertFalse(applicationDataTypeCache.getScheduledPollingService().isShutdown(), "The scheduler should have been running");
+               assertNull(applicationDataTypeCache.getScheduledFuture(), "The job should not have been triggered");
+               applicationDataTypeCache.destroy();
+               assertTrue(applicationDataTypeCache.getScheduledPollingService().isShutdown(), "The scheduler should have been stopped");
+       }
 
-               // default test
-               Deencapsulation.invoke(testSubject, "shutdownExecutor");
+       @Test
+       void testInitEmptyConfiguration() {
+               mockEmptyConfiguration();
+               applicationDataTypeCache.init();
+               assertNull(applicationDataTypeCache.getScheduledFuture(), "The scheduler should not have started");
        }
 
        @Test
-       public void testGetAllDataTypesFromGraph() throws Exception {
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> result;
+       void testInitCacheDisabled() {
+               final var applicationL1CacheInfo = new ApplicationL1CacheInfo();
+               applicationL1CacheInfo.setEnabled(false);
+               mockConfiguration(applicationL1CacheInfo);
+               applicationDataTypeCache.init();
+               assertNull(applicationDataTypeCache.getScheduledFuture(), "The scheduler should not have started");
+       }
 
-               // default test
-               result = Deencapsulation.invoke(testSubject, "getAllDataTypesFromGraph");
+       @Test
+       void testGetAllAfterInitialization() {
+               defaultInit();
+               final ScheduledFuture<?> scheduledFuture = applicationDataTypeCache.getScheduledFuture();
+               //waiting the cache to be filled
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               assertDataTypeCache(dataTypeDefinitionMap);
        }
 
        @Test
-       public void testGetAll() throws Exception {
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> result;
+       void testCacheChangeWithDataTypeChange() {
+               defaultInit();
+               final ScheduledFuture<?> scheduledFuture = applicationDataTypeCache.getScheduledFuture();
+               //waiting the cache to be filled
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               assertDataTypeCache(dataTypeDefinitionMap);
+
+               final DataTypeDefinition testDataType1 = createDataTypeDefinition("test.data.type1", "test.data.type1", 101L, 1000L);
+               final DataTypeDefinition testDataType2 = createDataTypeDefinition("test.data.type2", "test.data.type2", 101L, 1002L);
+               final Map<String, DataTypeDefinition> modifiedDataTypeDefinitionMap =
+                       Map.of(testDataType1.getName(), testDataType1, testDataType2.getName(), testDataType2);
+               when(propertyOperation.getAllDataTypes()).thenReturn(Either.left(modifiedDataTypeDefinitionMap));
+
+               final DataTypeData dataTypeData1 = createDataTypeData("test.data.type1", "test.data.type1", 101L, 101L);
+               final DataTypeData dataTypeData2 = createDataTypeData("test.data.type2", "test.data.type2", 101L, 1002L);
 
-               // default test
-               result = testSubject.getAll();
+               when(propertyOperation.getAllDataTypeNodes()).thenReturn(Either.left(List.of(dataTypeData1, dataTypeData2)));
+
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) == 0);
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               assertDataTypeCache(modifiedDataTypeDefinitionMap);
        }
 
        @Test
-       public void testGet() throws Exception {
-               String uniqueId = "";
-               Either<DataTypeDefinition, JanusGraphOperationStatus> result;
+       void testCacheChangeWithAddedDataType() {
+               defaultInit();
+               final ScheduledFuture<?> scheduledFuture = applicationDataTypeCache.getScheduledFuture();
+               //waiting the cache to be filled
+               await().until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               assertDataTypeCache(dataTypeDefinitionMap);
+
+               final Map<String, DataTypeDefinition> modifiedDataTypeDefinitionMap = new HashMap<>();
+               final DataTypeDefinition testDataType1 = createDataTypeDefinition("test.data.type1", "test.data.type1", 1L, 1L);
+               modifiedDataTypeDefinitionMap.put(testDataType1.getName(), testDataType1);
+               final DataTypeDefinition testDataType3 = createDataTypeDefinition("test.data.type3", "test.data.type3", 1L, 1L);
+               modifiedDataTypeDefinitionMap.put(testDataType3.getName(), testDataType3);
+               when(propertyOperation.getAllDataTypes()).thenReturn(Either.left(modifiedDataTypeDefinitionMap));
+
+               final DataTypeData dataTypeData1 = createDataTypeData("test.data.type1", "test.data.type1", 1L, 1L);
+               final DataTypeData dataTypeData3 = createDataTypeData("test.data.type3", "test.data.type3", 1L, 1L);
 
-               // default test
-               result = testSubject.get(uniqueId);
+               when(propertyOperation.getAllDataTypeNodes()).thenReturn(Either.left(List.of(dataTypeData1, dataTypeData3)));
+
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) == 0);
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               assertDataTypeCache(modifiedDataTypeDefinitionMap);
        }
 
        @Test
-       public void testGet2() throws Exception {
-               String uniqueId = "";
-               Either<DataTypeDefinition, JanusGraphOperationStatus> result;
-
-               HashMap<String, DataTypeDefinition> a = new HashMap<>();
-               DataTypeDefinition value1 = new DataTypeDefinition();
-               value1.setUniqueId("mock");
-               a.put("mock", value1);
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> value = Either.left(a);
-               Mockito.when(propertyOperation.getAllDataTypes()).thenReturn(value);
-               // default test
-               Deencapsulation.invoke(testSubject, "replaceAllData");
-               result = testSubject.get(uniqueId);
-       }
-       
-       @Test
-       public void testRun() throws Exception {
-               testSubject.run();
+       void testGetAllWithNoInitialization() {
+               final Map<String, DataTypeDefinition> dataTypeDefinitionMap = new HashMap<>();
+               when(propertyOperation.getAllDataTypes()).thenReturn(Either.left(dataTypeDefinitionMap));
+               final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> response = applicationDataTypeCache.getAll();
+               assertNotNull(response);
+               assertTrue(response.isLeft());
        }
 
        @Test
-       public void testRun2() throws Exception {
-               Either<List<DataTypeData>, JanusGraphOperationStatus> value = Either.right(
-        JanusGraphOperationStatus.GENERAL_ERROR);
-               Mockito.when(propertyOperation.getAllDataTypeNodes()).thenReturn(value);
-               testSubject.run();
+       void testGetWhenCacheIsEmpty() {
+               var dataTypeDefinition = new DataTypeDefinition();
+               when(propertyOperation.getDataTypeByUid("uniqueId")).thenReturn(Either.left(dataTypeDefinition));
+               final Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeEither = applicationDataTypeCache.get("uniqueId");
+               assertNotNull(dataTypeEither);
+               assertTrue(dataTypeEither.isLeft());
+               assertEquals(dataTypeDefinition, dataTypeEither.left().value());
        }
-       
-       @Test
-       public void testRun3() throws Exception {
-               LinkedList<DataTypeData> a = new LinkedList<>();
-               a.add(new DataTypeData());
-               Either<List<DataTypeData>, JanusGraphOperationStatus> value = Either.left(a);
-               Mockito.when(propertyOperation.getAllDataTypeNodes()).thenReturn(value);
-               
-               HashMap<String, DataTypeDefinition> a1 = new HashMap<>();
-               DataTypeDefinition value1 = new DataTypeDefinition();
-               value1.setUniqueId("mock");
-               a1.put("mock", value1);
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> value2 = Either.left(a1);
-               Mockito.when(propertyOperation.getAllDataTypes()).thenReturn(value2);
-               
-               Deencapsulation.invoke(testSubject, "replaceAllData");
-               testSubject.run();
-       }
-       
+
        @Test
-       public void testCompareDataTypes() throws Exception {
-               Map<String, ImmutablePair<Long, Long>> dataTypeNameToModificationTime = new HashMap<>();
-               Map<String, ImmutablePair<Long, Long>> currentDataTypeToModificationTime = new HashMap<>();
-               boolean result;
+       void testGetCacheHit() {
+               defaultInit();
+               final ScheduledFuture<?> scheduledFuture = applicationDataTypeCache.getScheduledFuture();
+               await().atMost(Duration.ofSeconds(schedulerPollIntervalInSec + 1)).until(() -> scheduledFuture.getDelay(TimeUnit.SECONDS) != 0);
+               final Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeEither = applicationDataTypeCache.get("test.data.type1");
+               assertNotNull(dataTypeEither);
+               assertTrue(dataTypeEither.isLeft());
+               final DataTypeDefinition actualDataTypeDefinition = dataTypeEither.left().value();
+               final DataTypeDefinition expectedDataTypeDefinition = dataTypeDefinitionMap.get("test.data.type1");
+               assertEquals(expectedDataTypeDefinition.getName(), actualDataTypeDefinition.getName());
+               assertEquals(expectedDataTypeDefinition.getUniqueId(), actualDataTypeDefinition.getUniqueId());
+               assertEquals(expectedDataTypeDefinition.getCreationTime(), actualDataTypeDefinition.getCreationTime());
+               assertEquals(expectedDataTypeDefinition.getModificationTime(), actualDataTypeDefinition.getModificationTime());
+       }
+
+    private void defaultInit() {
+        var applicationL1CacheInfo = new ApplicationL1CacheInfo();
+        applicationL1CacheInfo.setEnabled(schedulerIsEnabled);
+        applicationL1CacheInfo.setFirstRunDelay(schedulerFirstRunDelay);
+        applicationL1CacheInfo.setPollIntervalInSec(schedulerPollIntervalInSec);
+        mockConfiguration(applicationL1CacheInfo);
+
+        dataTypeDefinitionMap = new HashMap<>();
+        final DataTypeDefinition testDataType1 = createDataTypeDefinition("test.data.type1", "test.data.type1", 100L, 1000L);
+        dataTypeDefinitionMap.put(testDataType1.getName(), testDataType1);
+        final DataTypeDefinition testDataType2 = createDataTypeDefinition("test.data.type2", "test.data.type2", 101L, 1001L);
+        dataTypeDefinitionMap.put(testDataType2.getName(), testDataType2);
+        when(propertyOperation.getAllDataTypes()).thenReturn(Either.left(dataTypeDefinitionMap));
 
-               // default test
-               result = Deencapsulation.invoke(testSubject, "compareDataTypes", dataTypeNameToModificationTime, currentDataTypeToModificationTime);
+        final DataTypeData dataTypeData1 = createDataTypeData("test.data.type1", testDataType1.getName(), 100L, 1000L);
+        final DataTypeData dataTypeData2 = createDataTypeData("test.data.type2", testDataType2.getName(), 101L, 1001L);
+
+        when(propertyOperation.getAllDataTypeNodes()).thenReturn(Either.left(List.of(dataTypeData1, dataTypeData2)));
+        applicationDataTypeCache.init();
+    }
+
+    private DataTypeDefinition createDataTypeDefinition(String name, String uniqueId, long creationTime, long modificationTime) {
+        final DataTypeDefinition dataTypeDefinition = new DataTypeDefinition();
+        dataTypeDefinition.setName(name);
+        dataTypeDefinition.setUniqueId(uniqueId);
+        dataTypeDefinition.setCreationTime(creationTime);
+        dataTypeDefinition.setModificationTime(modificationTime);
+        return dataTypeDefinition;
+    }
+
+    private DataTypeData createDataTypeData(String name, String uniqueId, long creationTime, long modificationTime) {
+        final DataTypeData dataTypeData1 = new DataTypeData();
+        dataTypeData1.setDataTypeDataDefinition(createDataTypeDataDefinition(name, uniqueId, creationTime, modificationTime));
+        return dataTypeData1;
+    }
+    private DataTypeDataDefinition createDataTypeDataDefinition(String name, String uniqueId, long creationTime, long modificationTime) {
+        final DataTypeDataDefinition testDataType1DataDefinition = new DataTypeDataDefinition();
+        testDataType1DataDefinition.setName(name);
+        testDataType1DataDefinition.setUniqueId(uniqueId);
+        testDataType1DataDefinition.setCreationTime(creationTime);
+        testDataType1DataDefinition.setModificationTime(modificationTime);
+        return testDataType1DataDefinition;
+    }
+
+       private void mockConfiguration(final ApplicationL1CacheInfo applicationL1CacheInfo) {
+               final var applicationL1CacheConfig = new ApplicationL1CacheConfig();
+               applicationL1CacheConfig.setDatatypes(applicationL1CacheInfo);
+               final var configuration = new Configuration();
+               configuration.setApplicationL1Cache(applicationL1CacheConfig);
+               final var configurationManager = new ConfigurationManager();
+               configurationManager.setConfiguration(configuration);
        }
 
-       @Test
-       public void testCompareDataTypes2() throws Exception {
-               Map<String, ImmutablePair<Long, Long>> dataTypeNameToModificationTime = new HashMap<>();
-               Map<String, ImmutablePair<Long, Long>> currentDataTypeToModificationTime = new HashMap<>();
-               boolean result;
-               
-               currentDataTypeToModificationTime.put("mock", ImmutablePair.of(1L, 2L));
-               dataTypeNameToModificationTime.put("mock", ImmutablePair.of(5L, 6L));
-               
-               // default test
-               result = Deencapsulation.invoke(testSubject, "compareDataTypes", dataTypeNameToModificationTime, currentDataTypeToModificationTime);
-       }
-       
-       @Test
-       public void testReplaceAllData() throws Exception {
-               HashMap<String, DataTypeDefinition> a = new HashMap<>();
-               DataTypeDefinition value1 = new DataTypeDefinition();
-               value1.setUniqueId("mock");
-               a.put("mock", value1);
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> value = Either.left(a);
-               Mockito.when(propertyOperation.getAllDataTypes()).thenReturn(value);
-               // default test
-               Deencapsulation.invoke(testSubject, "replaceAllData");
-       }
-       
-       @Test
-       public void testReplaceAllData2() throws Exception {
-               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> value = Either.right(
-        JanusGraphOperationStatus.GENERAL_ERROR);
-               Mockito.when(propertyOperation.getAllDataTypes()).thenReturn(value);
-               // default test
-               Deencapsulation.invoke(testSubject, "replaceAllData");
+       private void mockEmptyConfiguration() {
+               final var applicationL1CacheConfig = new ApplicationL1CacheConfig();
+               final var configuration = new Configuration();
+               configuration.setApplicationL1Cache(applicationL1CacheConfig);
+               final var configurationManager = new ConfigurationManager();
+               configurationManager.setConfiguration(configuration);
+       }
+
+       public void assertDataTypeCache(final Map<String, DataTypeDefinition> expectedDataTypeCache) {
+               Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> dataTypeCacheMapEither = applicationDataTypeCache.getAll();
+               assertNotNull(dataTypeCacheMapEither);
+               assertTrue(dataTypeCacheMapEither.isLeft());
+               final Map<String, DataTypeDefinition> actualDataTypeMap = dataTypeCacheMapEither.left().value();
+               expectedDataTypeCache.forEach((dataType, dataTypeDefinition) -> {
+                       final DataTypeDefinition actualDataTypeDefinition = actualDataTypeMap.get(dataType);
+                       assertNotNull(actualDataTypeDefinition);
+                       assertEquals(dataTypeDefinition.getCreationTime(), actualDataTypeDefinition.getCreationTime());
+                       assertEquals(dataTypeDefinition.getModificationTime(), actualDataTypeDefinition.getModificationTime());
+               });
        }
 }