summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java186
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java25
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfig.java59
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfig.java46
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java12
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java39
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java21
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java129
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java142
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java95
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java1
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy38
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy34
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy44
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfigSpec.groovy59
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfigSpec.groovy76
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy49
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy16
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy97
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy126
-rw-r--r--docs/deployment.rst6
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy70
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy134
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy141
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy196
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json12
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResourcesResponse.json52
-rw-r--r--integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResponse.json44
34 files changed, 995 insertions, 1002 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
index 05b83b98e4..1f2748b4af 100755
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
@@ -35,11 +35,9 @@ import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.vali
import com.google.common.collect.Lists;
import com.hazelcast.map.IMap;
-import java.text.MessageFormat;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -50,7 +48,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.onap.cps.api.CpsDataService;
-import org.onap.cps.ncmp.api.NcmpResponseStatus;
import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler;
@@ -66,7 +63,7 @@ import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
import org.onap.cps.ncmp.api.impl.operations.OperationType;
import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager;
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper;
+import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker;
import org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions;
import org.onap.cps.ncmp.api.impl.utils.InventoryQueryConditions;
import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
@@ -106,37 +103,24 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
private final IMap<String, Object> moduleSyncStartedOnCmHandles;
private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
private final TrustLevelManager trustLevelManager;
- private final CmHandleIdMapper cmHandleIdMapper;
- private final Map<String, Collection<ModuleReference>> moduleSetTagCache;
+ private final AlternateIdChecker alternateIdChecker;
@Override
public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
final DmiPluginRegistration dmiPluginRegistration) {
- cacheAlternateIds(dmiPluginRegistration.getCreatedCmHandles());
+
dmiPluginRegistration.validateDmiPluginRegistration();
final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
setTrustLevelPerDmiPlugin(dmiPluginRegistration);
- if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) {
- dmiPluginRegistrationResponse.setRemovedCmHandles(
- parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles()));
- }
+ processRemovedCmHandles(dmiPluginRegistration, dmiPluginRegistrationResponse);
- if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
- dmiPluginRegistrationResponse.setCreatedCmHandles(
- parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration));
- }
- if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
- dmiPluginRegistrationResponse.setUpdatedCmHandles(
- networkCmProxyDataServicePropertyHandler
- .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
- }
- if (dmiPluginRegistration.getUpgradedCmHandles() != null
- && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) {
- dmiPluginRegistrationResponse.setUpgradedCmHandles(
- parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration));
- }
+ processCreatedCmHandles(dmiPluginRegistration, dmiPluginRegistrationResponse);
+
+ processUpdatedCmHandles(dmiPluginRegistration, dmiPluginRegistrationResponse);
+
+ processUpgradedCmHandles(dmiPluginRegistration, dmiPluginRegistrationResponse);
return dmiPluginRegistrationResponse;
}
@@ -329,21 +313,24 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
* @return cm-handle registration response for create cm-handle requests.
*/
public List<CmHandleRegistrationResponse> parseAndProcessCreatedCmHandlesInRegistration(
- final DmiPluginRegistration dmiPluginRegistration) {
+ final DmiPluginRegistration dmiPluginRegistration, final Collection<String> acceptedCmHandleIds) {
final List<NcmpServiceCmHandle> cmHandlesToBeCreated = dmiPluginRegistration.getCreatedCmHandles();
final Map<String, TrustLevel> initialTrustLevelPerCmHandleId = new HashMap<>(cmHandlesToBeCreated.size());
final List<YangModelCmHandle> yangModelCmHandles = new ArrayList<>(cmHandlesToBeCreated.size());
cmHandlesToBeCreated
.forEach(cmHandle -> {
- final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(
- dmiPluginRegistration.getDmiPlugin(),
- dmiPluginRegistration.getDmiDataPlugin(),
- dmiPluginRegistration.getDmiModelPlugin(),
- cmHandle,
- cmHandle.getModuleSetTag(),
- cmHandle.getAlternateId());
- yangModelCmHandles.add(yangModelCmHandle);
- initialTrustLevelPerCmHandleId.put(cmHandle.getCmHandleId(), cmHandle.getRegistrationTrustLevel());
+ if (acceptedCmHandleIds.contains(cmHandle.getCmHandleId())) {
+ final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(
+ dmiPluginRegistration.getDmiPlugin(),
+ dmiPluginRegistration.getDmiDataPlugin(),
+ dmiPluginRegistration.getDmiModelPlugin(),
+ cmHandle,
+ cmHandle.getModuleSetTag(),
+ cmHandle.getAlternateId());
+ yangModelCmHandles.add(yangModelCmHandle);
+ initialTrustLevelPerCmHandleId.put(cmHandle.getCmHandleId(),
+ cmHandle.getRegistrationTrustLevel());
+ }
});
return registerNewCmHandles(yangModelCmHandles, initialTrustLevelPerCmHandleId);
}
@@ -354,16 +341,12 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
new ArrayList<>(tobeRemovedCmHandles.size());
final Collection<YangModelCmHandle> yangModelCmHandles =
inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
- final Set<String> moduleSetTags = yangModelCmHandles.stream().map(YangModelCmHandle::getModuleSetTag)
- .collect(Collectors.toSet());
updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING);
final Set<String> notDeletedCmHandles = new HashSet<>();
for (final List<String> tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandles, DELETE_BATCH_SIZE)) {
try {
batchDeleteCmHandlesFromDbAndModuleSyncMap(tobeRemovedCmHandleBatch);
- moduleSetTags.forEach(moduleSetTagCache::remove);
- log.debug("Removed module set tags: {}", moduleSetTags);
tobeRemovedCmHandleBatch.forEach(cmHandleId ->
cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)));
@@ -382,68 +365,100 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
yangModelCmHandles.removeIf(yangModelCmHandle -> notDeletedCmHandles.contains(yangModelCmHandle.getId()));
updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETED);
- removeEntriesFromAlternateIdCache(yangModelCmHandles);
return cmHandleRegistrationResponses;
}
- private void removeEntriesFromAlternateIdCache(final Collection<YangModelCmHandle> yangModelCmHandles) {
- for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) {
- cmHandleIdMapper.removeMapping(yangModelCmHandle.getId());
+ private void processRemovedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) {
+ dmiPluginRegistrationResponse.setRemovedCmHandles(
+ parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles()));
+ }
+ }
+
+ private void processCreatedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ final Collection<String> acceptedCmHandleIds = alternateIdChecker
+ .getIdsOfCmHandlesWithAcceptableAlternateId(dmiPluginRegistration.getCreatedCmHandles());
+ if (!acceptedCmHandleIds.isEmpty()) {
+ dmiPluginRegistrationResponse.setCreatedCmHandles(
+ parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration, acceptedCmHandleIds));
+ }
+ }
+
+ private void processUpdatedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
+ dmiPluginRegistrationResponse.setUpdatedCmHandles(
+ networkCmProxyDataServicePropertyHandler
+ .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
}
}
+ private void processUpgradedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ if (dmiPluginRegistration.getUpgradedCmHandles() != null
+ && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) {
+ dmiPluginRegistrationResponse.setUpgradedCmHandles(
+ parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration));
+ }
+ }
+
+
protected List<CmHandleRegistrationResponse> parseAndProcessUpgradedCmHandlesInRegistration(
final DmiPluginRegistration dmiPluginRegistration) {
final List<String> upgradedCmHandleIds = dmiPluginRegistration.getUpgradedCmHandles().getCmHandles();
-
+ final String upgradedModuleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag();
final Map<YangModelCmHandle, CmHandleState> acceptedCmHandleStatePerCmHandle
= new HashMap<>(upgradedCmHandleIds.size());
+ final List<CmHandleRegistrationResponse> cmHandleUpgradeResponses = new ArrayList<>(upgradedCmHandleIds.size());
- final Map<NcmpResponseStatus, List<String>> failedCmHandlesPerResponseStatus
- = new EnumMap<>(NcmpResponseStatus.class);
- final List<String> nonExistingCmHandleIds = new ArrayList<>();
- final List<String> nonReadyCmHandleIds = new ArrayList<>();
- final List<String> invalidCmHandleIds = new ArrayList<>();
-
- upgradedCmHandleIds.forEach(cmHandleId -> {
+ for (final String cmHandleId : upgradedCmHandleIds) {
try {
- if (cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY)) {
- final YangModelCmHandle yangModelCmHandleWithUpgradeDetails
- = createYangModelCmHandle(dmiPluginRegistration, cmHandleId);
- acceptedCmHandleStatePerCmHandle.put(yangModelCmHandleWithUpgradeDetails, CmHandleState.LOCKED);
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ if (yangModelCmHandle.getCompositeState().getCmHandleState() == CmHandleState.READY) {
+ if (moduleUpgradeCanBeSkipped(yangModelCmHandle, upgradedModuleSetTag)) {
+ cmHandleUpgradeResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
+ } else {
+ updateYangModelCmHandleForUpgrade(yangModelCmHandle, upgradedModuleSetTag);
+ acceptedCmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED);
+ }
} else {
- nonReadyCmHandleIds.add(cmHandleId);
+ cmHandleUpgradeResponses.add(
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_READY));
}
} catch (final DataNodeNotFoundException dataNodeNotFoundException) {
log.error("Unable to find data node for cm handle id : {} , caused by : {}",
cmHandleId, dataNodeNotFoundException.getMessage());
- nonExistingCmHandleIds.add(cmHandleId);
+ cmHandleUpgradeResponses.add(
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
} catch (final DataValidationException dataValidationException) {
log.error("Unable to upgrade cm handle id: {}, caused by : {}",
cmHandleId, dataValidationException.getMessage());
- invalidCmHandleIds.add(cmHandleId);
+ cmHandleUpgradeResponses.add(
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
}
- });
- failedCmHandlesPerResponseStatus.put(CM_HANDLES_NOT_READY, nonReadyCmHandleIds);
- failedCmHandlesPerResponseStatus.put(CM_HANDLES_NOT_FOUND, nonExistingCmHandleIds);
- failedCmHandlesPerResponseStatus.put(CM_HANDLE_INVALID_ID, invalidCmHandleIds);
- return mergeAllCmHandleResponses(acceptedCmHandleStatePerCmHandle, failedCmHandlesPerResponseStatus);
- }
-
- private static YangModelCmHandle createYangModelCmHandle(final DmiPluginRegistration dmiPluginRegistration,
- final String cmHandleId) {
- final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
- ncmpServiceCmHandle.setCmHandleId(cmHandleId);
- final String moduleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag();
- final String lockReasonWithModuleSetTag = MessageFormat.format(
- ModuleOperationsUtils.MODULE_SET_TAG_MESSAGE_FORMAT, moduleSetTag);
- ncmpServiceCmHandle.setCompositeState(new CompositeStateBuilder().withCmHandleState(CmHandleState.READY)
+ }
+ cmHandleUpgradeResponses.addAll(upgradeCmHandles(acceptedCmHandleStatePerCmHandle));
+ return cmHandleUpgradeResponses;
+ }
+
+ private static boolean moduleUpgradeCanBeSkipped(final YangModelCmHandle yangModelCmHandle,
+ final String upgradedModuleSetTag) {
+ if (StringUtils.isBlank(upgradedModuleSetTag)) {
+ return false;
+ }
+ return yangModelCmHandle.getModuleSetTag().equals(upgradedModuleSetTag);
+ }
+
+ private static void updateYangModelCmHandleForUpgrade(final YangModelCmHandle yangModelCmHandle,
+ final String upgradedModuleSetTag) {
+ final String lockReasonWithModuleSetTag = String.format(ModuleOperationsUtils.MODULE_SET_TAG_MESSAGE_FORMAT,
+ upgradedModuleSetTag);
+ yangModelCmHandle.setCompositeState(new CompositeStateBuilder().withCmHandleState(CmHandleState.READY)
.withLockReason(MODULE_UPGRADE, lockReasonWithModuleSetTag).build());
- return YangModelCmHandle.toYangModelCmHandle(dmiPluginRegistration.getDmiPlugin(),
- dmiPluginRegistration.getDmiDataPlugin(), dmiPluginRegistration.getDmiModelPlugin(),
- ncmpServiceCmHandle, moduleSetTag, ncmpServiceCmHandle.getAlternateId());
}
private CmHandleRegistrationResponse deleteCmHandleAndGetCmHandleRegistrationResponse(final String cmHandleId) {
@@ -513,17 +528,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
}
- private List<CmHandleRegistrationResponse> mergeAllCmHandleResponses(
- final Map<YangModelCmHandle, CmHandleState> acceptedCmHandleStatePerCmHandle,
- final Map<NcmpResponseStatus, List<String>> failedCmHandlesPerResponseStatus) {
- final List<CmHandleRegistrationResponse> cmHandleUpgradeResponses
- = upgradeCmHandles(acceptedCmHandleStatePerCmHandle);
- failedCmHandlesPerResponseStatus.forEach((ncmpResponseStatus, cmHandleIds) ->
- cmHandleIds.forEach(cmHandleId -> cmHandleUpgradeResponses.add(CmHandleRegistrationResponse
- .createFailureResponse(cmHandleId, ncmpResponseStatus))));
- return cmHandleUpgradeResponses;
- }
-
private List<CmHandleRegistrationResponse> upgradeCmHandles(final Map<YangModelCmHandle, CmHandleState>
cmHandleStatePerCmHandle) {
final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle);
@@ -549,12 +553,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
}
- private void cacheAlternateIds(final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) {
- for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) {
- if (!StringUtils.isEmpty(ncmpServiceCmHandle.getAlternateId())) {
- cmHandleIdMapper.addMapping(ncmpServiceCmHandle.getCmHandleId(), ncmpServiceCmHandle.getAlternateId());
- }
- }
- }
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
index 13b3fcafb1..84075a4897 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
@@ -45,7 +45,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper;
+import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker;
import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
@@ -67,7 +67,7 @@ public class NetworkCmProxyDataServicePropertyHandler {
private final InventoryPersistence inventoryPersistence;
private final CpsDataService cpsDataService;
private final JsonObjectMapper jsonObjectMapper;
- private final CmHandleIdMapper cmHandleIdMapper;
+ private final AlternateIdChecker alternateIdChecker;
/**
* Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes.
@@ -81,8 +81,8 @@ public class NetworkCmProxyDataServicePropertyHandler {
for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) {
final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
try {
- final DataNode existingCmHandleDataNode = inventoryPersistence.getCmHandleDataNode(cmHandleId)
- .iterator().next();
+ final DataNode existingCmHandleDataNode = inventoryPersistence
+ .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next();
updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle);
processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle);
cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
@@ -105,17 +105,14 @@ public class NetworkCmProxyDataServicePropertyHandler {
private void updateAlternateId(final DataNode existingCmHandleDataNode,
final NcmpServiceCmHandle ncmpServiceCmHandle) {
+ final YangModelCmHandle yangModelCmHandle =
+ YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode,
+ ncmpServiceCmHandle.getCmHandleId());
+ final String currentAlternateId = yangModelCmHandle.getAlternateId();
final String newAlternateId = ncmpServiceCmHandle.getAlternateId();
- if (cmHandleIdMapper.addMapping(ncmpServiceCmHandle.getCmHandleId(), newAlternateId)) {
- try {
- final YangModelCmHandle yangModelCmHandle =
- YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode,
- ncmpServiceCmHandle.getCmHandleId());
- setAndUpdateAlternateId(yangModelCmHandle, newAlternateId);
- } catch (final Exception e) {
- cmHandleIdMapper.removeMapping(ncmpServiceCmHandle.getCmHandleId());
- throw e;
- }
+ if (alternateIdChecker.canApplyAlternateId(ncmpServiceCmHandle.getCmHandleId(),
+ currentAlternateId, newAlternateId)) {
+ setAndUpdateAlternateId(yangModelCmHandle, newAlternateId);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfig.java
deleted file mode 100644
index a69d144766..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfig.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * ============LICENSE_START========================================================
- * Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config.embeddedcache;
-
-import com.hazelcast.config.MapConfig;
-import java.util.Map;
-import org.onap.cps.cache.HazelcastCacheConfig;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class AlternateIdCacheConfig extends HazelcastCacheConfig {
-
- private static final MapConfig alternateIdPerCmHandleIdMapConfig =
- createMapConfig("alternateIdPerCmHandleIdMapConfig");
-
- private static final MapConfig cmHandleIdPerAlternateIdMapConfig =
- createMapConfig("cmHandleIdPerAlternateIdMapConfig");
-
- /**
- * Distributed instance of alternate id cache containing the alternate id per cm handle id.
- *
- * @return the cached map.
- */
- @Bean
- public Map<String, String> alternateIdPerCmHandleId() {
- return createHazelcastInstance("hazelcastInstanceAlternateIdPerCmHandleIdMap",
- alternateIdPerCmHandleIdMapConfig).getMap("alternateIdPerCmHandleId");
- }
-
- /**
- * Distributed instance of alternate id cache containing the cm handle id per alternate id.
- *
- * @return the cached map.
- */
- @Bean
- public Map<String, String> cmHandleIdPerAlternateId() {
- return createHazelcastInstance("hazelcastInstanceCmHandleIdPerAlternateIdMap",
- cmHandleIdPerAlternateIdMapConfig).getMap("cmHandleIdPerAlternateId");
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfig.java
deleted file mode 100644
index a791a3bbd1..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfig.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config.embeddedcache;
-
-import com.hazelcast.config.MapConfig;
-import java.util.Collection;
-import java.util.Map;
-import org.onap.cps.cache.HazelcastCacheConfig;
-import org.onap.cps.spi.model.ModuleReference;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class ModuleSetTagCacheConfig extends HazelcastCacheConfig {
-
- private static final MapConfig moduleSetTagCacheMapConfig = createMapConfig("moduleSetTagCacheMapConfig");
-
- /**
- * Map instance for cached ModulesSetTags.
- *
- * @return configured map of ModuleSetTags
- */
- @Bean
- public Map<String, Collection<ModuleReference>> moduleSetTagCache() {
- return createHazelcastInstance("moduleSetTags", moduleSetTagCacheMapConfig)
- .getMap("moduleSetTagCache");
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
index dcd0368700..e230b3fcb3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
@@ -114,12 +114,20 @@ public interface InventoryPersistence extends NcmpPersistence {
void saveCmHandleBatch(List<YangModelCmHandle> yangModelCmHandles);
/**
- * Get data node of given cm handle.
+ * Get data node with the given cm handle id.
*
* @param cmHandleId cmHandle ID
* @return data node
*/
- Collection<DataNode> getCmHandleDataNode(String cmHandleId);
+ Collection<DataNode> getCmHandleDataNodeByCmHandleId(String cmHandleId);
+
+ /**
+ * Get data node with the given alternate id.
+ *
+ * @param alternateId alternate ID
+ * @return data node
+ */
+ DataNode getCmHandleDataNodeByAlternateId(String alternateId);
/**
* Get collection of data nodes of given cm handles.
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
index 3b70786038..08ab15eaa7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
@@ -22,6 +22,8 @@
package org.onap.cps.ncmp.api.impl.inventory;
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
+
import com.google.common.collect.Lists;
import java.time.OffsetDateTime;
import java.util.ArrayList;
@@ -37,6 +39,7 @@ import org.onap.cps.api.CpsModuleService;
import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleDefinition;
@@ -54,6 +57,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
private final CpsModuleService cpsModuleService;
private final CpsAnchorService cpsAnchorService;
private final CpsValidator cpsValidator;
+ private final CmHandleQueries cmHandleQueries;
/**
* initialize an inventory persistence object.
@@ -66,18 +70,19 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
*/
public InventoryPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
final CpsModuleService cpsModuleService, final CpsValidator cpsValidator,
- final CpsAnchorService cpsAnchorService) {
+ final CpsAnchorService cpsAnchorService, final CmHandleQueries cmHandleQueries) {
super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
this.cpsModuleService = cpsModuleService;
this.cpsAnchorService = cpsAnchorService;
this.cpsValidator = cpsValidator;
+ this.cmHandleQueries = cmHandleQueries;
}
@Override
public CompositeState getCmHandleState(final String cmHandleId) {
final DataNode stateAsDataNode = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- createCmHandleXPath(cmHandleId) + "/state", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ getXPathForCmHandleById(cmHandleId) + "/state", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
.iterator().next();
cpsValidator.validateNameCharacters(cmHandleId);
return new CompositeStateBuilder().fromDataNode(stateAsDataNode).build();
@@ -87,14 +92,14 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
final String cmHandleJsonData = createStateJsonData(jsonObjectMapper.asJsonString(compositeState));
cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- createCmHandleXPath(cmHandleId), cmHandleJsonData, OffsetDateTime.now());
+ getXPathForCmHandleById(cmHandleId), cmHandleJsonData, OffsetDateTime.now());
}
@Override
public void saveCmHandleStateBatch(final Map<String, CompositeState> cmHandleStatePerCmHandleId) {
final Map<String, String> cmHandlesJsonDataMap = new HashMap<>();
cmHandleStatePerCmHandleId.forEach((cmHandleId, compositeState) -> cmHandlesJsonDataMap.put(
- createCmHandleXPath(cmHandleId),
+ getXPathForCmHandleById(cmHandleId),
createStateJsonData(jsonObjectMapper.asJsonString(compositeState))));
cpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
cmHandlesJsonDataMap, OffsetDateTime.now());
@@ -103,7 +108,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
@Override
public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
cpsValidator.validateNameCharacters(cmHandleId);
- final DataNode dataNode = getCmHandleDataNode(cmHandleId).iterator().next();
+ final DataNode dataNode = getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next();
return YangDataConverter.convertCmHandleToYangModel(dataNode, cmHandleId);
}
@@ -158,14 +163,26 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
}
@Override
- public Collection<DataNode> getCmHandleDataNode(final String cmHandleId) {
- return this.getDataNode(createCmHandleXPath(cmHandleId));
+ public Collection<DataNode> getCmHandleDataNodeByCmHandleId(final String cmHandleId) {
+ return this.getDataNode(getXPathForCmHandleById(cmHandleId));
+ }
+
+ @Override
+ public DataNode getCmHandleDataNodeByAlternateId(final String alternateId) {
+ final String xPathForCmHandleByAlternateId = getXPathForCmHandleByAlternateId(alternateId);
+ final Collection<DataNode> dataNodes = cmHandleQueries
+ .queryNcmpRegistryByCpsPath(xPathForCmHandleByAlternateId, OMIT_DESCENDANTS);
+ if (dataNodes.isEmpty()) {
+ throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ xPathForCmHandleByAlternateId);
+ }
+ return dataNodes.iterator().next();
}
@Override
public Collection<DataNode> getCmHandleDataNodes(final Collection<String> cmHandleIds) {
final Collection<String> xpaths = new ArrayList<>(cmHandleIds.size());
- cmHandleIds.forEach(cmHandleId -> xpaths.add(createCmHandleXPath(cmHandleId)));
+ cmHandleIds.forEach(cmHandleId -> xpaths.add(getXPathForCmHandleById(cmHandleId)));
return this.getDataNodes(xpaths);
}
@@ -174,10 +191,14 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
return cpsAnchorService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
}
- private static String createCmHandleXPath(final String cmHandleId) {
+ private static String getXPathForCmHandleById(final String cmHandleId) {
return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']";
}
+ private static String getXPathForCmHandleByAlternateId(final String alternateId) {
+ return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@alternate-id='" + alternateId + "']";
+ }
+
private static String createStateJsonData(final String state) {
return "{\"state\":" + state + "}";
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
index 22bbc73833..9f95131cf1 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
@@ -38,7 +38,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
@@ -62,10 +61,10 @@ public class ModuleOperationsUtils {
private final DmiDataOperations dmiDataOperations;
private final JsonObjectMapper jsonObjectMapper;
private static final String RETRY_ATTEMPT_KEY = "attempt";
- public static final String MODULE_SET_TAG_KEY = "moduleSetTag";
- public static final String MODULE_SET_TAG_MESSAGE_FORMAT = "Upgrade to ModuleSetTag: {0}";
- private static final String UPGRADE_FORMAT = "Upgrade to ModuleSetTag: %s";
- private static final String LOCK_REASON_DETAILS_MSG_FORMAT = UPGRADE_FORMAT + " Attempt #%d failed: %s";
+ private static final String MODULE_SET_TAG_KEY = "moduleSetTag";
+ public static final String MODULE_SET_TAG_MESSAGE_FORMAT = "Upgrade to ModuleSetTag: %s";
+ private static final String LOCK_REASON_DETAILS_MSG_FORMAT =
+ MODULE_SET_TAG_MESSAGE_FORMAT + " Attempt #%d failed: %s";
private static final Pattern retryAttemptPattern = Pattern.compile("Attempt #(\\d+) failed:.+");
private static final Pattern moduleSetTagPattern = Pattern.compile("Upgrade to ModuleSetTag: (\\S+)");
private static final String CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE = """
@@ -134,10 +133,10 @@ public class ModuleOperationsUtils {
if (!compositeStateDetails.isEmpty() && compositeStateDetails.containsKey(RETRY_ATTEMPT_KEY)) {
attempt = 1 + Integer.parseInt(compositeStateDetails.get(RETRY_ATTEMPT_KEY));
}
- final String moduleSetTag = compositeStateDetails.get(MODULE_SET_TAG_KEY);
+ final String moduleSetTag = compositeStateDetails.getOrDefault(MODULE_SET_TAG_KEY, "");
compositeState.setLockReason(CompositeState.LockReason.builder()
- .details(String.format(LOCK_REASON_DETAILS_MSG_FORMAT, StringUtils.isNotBlank(moduleSetTag)
- ? moduleSetTag : "not-specified", attempt, errorMessage)).lockReasonCategory(lockReasonCategory)
+ .details(String.format(LOCK_REASON_DETAILS_MSG_FORMAT, moduleSetTag, attempt, errorMessage))
+ .lockReasonCategory(lockReasonCategory)
.build());
}
@@ -221,13 +220,17 @@ public class ModuleOperationsUtils {
* @param compositeState current lock reason of cm handle
* @return true or false based on lock reason category
*/
- public static boolean isInUpgradeOrUpgradeFailed(final CompositeState compositeState) {
+ public static boolean inUpgradeOrUpgradeFailed(final CompositeState compositeState) {
return compositeState.getLockReason() != null
&& (LockReasonCategory.MODULE_UPGRADE.equals(compositeState.getLockReason().getLockReasonCategory())
|| LockReasonCategory.MODULE_UPGRADE_FAILED.equals(compositeState.getLockReason()
.getLockReasonCategory()));
}
+ public static String getUpgradedModuleSetTagFromLockReason(final CompositeState.LockReason lockReason) {
+ return getLockedCompositeStateDetails(lockReason).getOrDefault(MODULE_SET_TAG_KEY, "");
+ }
+
private String getFirstResource(final Object responseBody) {
final String jsonObjectAsString = jsonObjectMapper.asJsonString(responseBody);
final JsonNode overallJsonNode = jsonObjectMapper.convertToJsonNode(jsonObjectAsString);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
index 72d322605f..8b70798eb1 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
@@ -35,12 +35,12 @@ import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
@@ -63,7 +63,6 @@ public class ModuleSyncService {
private final CpsDataService cpsDataService;
private final CpsAnchorService cpsAnchorService;
private final JsonObjectMapper jsonObjectMapper;
- private final Map<String, Collection<ModuleReference>> moduleSetTagCache;
private static final Map<String, String> NO_NEW_MODULES = Collections.emptyMap();
/**
@@ -73,44 +72,27 @@ public class ModuleSyncService {
*/
public void syncAndCreateOrUpgradeSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
+ final boolean inUpgrade = ModuleOperationsUtils.inUpgradeOrUpgradeFailed(yangModelCmHandle.getCompositeState());
+
+ final ImmutableTriple<String, Map<String, String>, Collection<ModuleReference>>
+ allModuleReferencesAndNewModuleNameByModuleSetTag
+ = getAllModuleReferencesAndNewYangResourcesByModuleSetTag(yangModelCmHandle, inUpgrade);
+
+ final String moduleSetTag = allModuleReferencesAndNewModuleNameByModuleSetTag.getLeft();
+ final Map<String, String> newYangResources = allModuleReferencesAndNewModuleNameByModuleSetTag.getMiddle();
+ final Collection<ModuleReference> allModuleReferences
+ = allModuleReferencesAndNewModuleNameByModuleSetTag.getRight();
final String cmHandleId = yangModelCmHandle.getId();
- final CompositeState compositeState = yangModelCmHandle.getCompositeState();
- final boolean inUpgrade = ModuleOperationsUtils.isInUpgradeOrUpgradeFailed(compositeState);
- final String moduleSetTag = getModuleSetTag(yangModelCmHandle, compositeState, inUpgrade);
-
- final Collection<ModuleReference> moduleReferencesFromCache = moduleSetTagCache.get(moduleSetTag);
-
- if (moduleReferencesFromCache == null) {
- final Optional<DataNode> existingCmHandleWithSameModuleSetTag
- = getFirstReadyDataNodeWithModuleSetTag(moduleSetTag);
-
- if (existingCmHandleWithSameModuleSetTag.isPresent()) {
- final String existingAnchorName = existingCmHandleWithSameModuleSetTag.get().getAnchorName();
- final Collection<ModuleReference> moduleReferencesFromExistingCmHandle =
- upgradeOrCreateSchemaSetUsingModuleSetTag(yangModelCmHandle.getId(), moduleSetTag,
- existingAnchorName, inUpgrade);
- updateModuleSetTagCache(moduleSetTag, moduleReferencesFromExistingCmHandle);
- } else {
- if (inUpgrade) {
- deleteSchemaSetIfExists(cmHandleId);
- }
- final Collection<ModuleReference> allModuleReferencesFromCmHandle
- = syncAndCreateSchemaSet(yangModelCmHandle);
- updateModuleSetTagCache(moduleSetTag, allModuleReferencesFromCmHandle);
- }
+
+ if (inUpgrade) {
+ cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
+ newYangResources, allModuleReferences);
+ setCmHandleModuleSetTag(yangModelCmHandle, moduleSetTag);
} else {
- if (inUpgrade) {
- cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
- NO_NEW_MODULES, moduleReferencesFromCache);
- } else {
- cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
- cmHandleId, NO_NEW_MODULES, moduleReferencesFromCache);
- }
- }
- if (!inUpgrade) {
+ cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
+ newYangResources, allModuleReferences);
cpsAnchorService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, cmHandleId);
}
- setCmHandleModuleSetTag(yangModelCmHandle, moduleSetTag);
}
/**
@@ -128,7 +110,30 @@ public class ModuleSyncService {
}
}
- private Optional<DataNode> getFirstReadyDataNodeWithModuleSetTag(final String moduleSetTag) {
+ private ImmutableTriple<String, Map<String, String>, Collection<ModuleReference>>
+ getAllModuleReferencesAndNewYangResourcesByModuleSetTag(final YangModelCmHandle yangModelCmHandle,
+ final boolean inUpgrade) {
+
+ final String moduleSetTag = getModuleSetTag(yangModelCmHandle, inUpgrade);
+ final Collection<ModuleReference> allModuleReferences;
+ Map<String, String> newYangResources = Collections.emptyMap();
+
+ final Optional<DataNode> optionalDataNode = getFirstReadyDataNodeByModuleSetTagProvidedInDb(moduleSetTag);
+
+ if (optionalDataNode.isPresent()) {
+ log.info("Found other cm handle having same module set tag: {}", moduleSetTag);
+ final String otherAnchorWithSameModuleSetTag
+ = YangDataConverter.extractCmHandleIdFromXpath(optionalDataNode.get().getXpath());
+ allModuleReferences = cpsModuleService.getYangResourcesModuleReferences(
+ NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, otherAnchorWithSameModuleSetTag);
+ } else {
+ allModuleReferences = dmiModelOperations.getModuleReferences(yangModelCmHandle);
+ newYangResources = getNewModuleNameToContentMap(yangModelCmHandle, allModuleReferences);
+ }
+ return ImmutableTriple.of(moduleSetTag, newYangResources, allModuleReferences);
+ }
+
+ private Optional<DataNode> getFirstReadyDataNodeByModuleSetTagProvidedInDb(final String moduleSetTag) {
final List<DataNode> dataNodes = StringUtils.isNotBlank(moduleSetTag) ? cmHandleQueries
.queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='" + moduleSetTag + "']",
FetchDescendantsOption.OMIT_DESCENDANTS) : Collections.emptyList();
@@ -148,56 +153,26 @@ public class ModuleSyncService {
jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now());
}
- private Collection<ModuleReference> syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle) {
- final Collection<ModuleReference> allModuleReferencesFromCmHandle =
- dmiModelOperations.getModuleReferences(yangModelCmHandle);
- final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
- .identifyNewModuleReferences(allModuleReferencesFromCmHandle);
+ private Map<String, String> getNewModuleNameToContentMap(final YangModelCmHandle yangModelCmHandle,
+ final Collection<ModuleReference> moduleReferences) {
+ final Collection<ModuleReference> identifiedNewModuleReferences = cpsModuleService
+ .identifyNewModuleReferences(moduleReferences);
final Map<String, String> newModuleNameToContentMap;
- if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
+ if (identifiedNewModuleReferences.isEmpty()) {
newModuleNameToContentMap = NO_NEW_MODULES;
} else {
newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
- identifiedNewModuleReferencesFromCmHandle);
- }
- cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
- yangModelCmHandle.getId(), newModuleNameToContentMap, allModuleReferencesFromCmHandle);
- return allModuleReferencesFromCmHandle;
- }
-
- private Collection<ModuleReference> upgradeOrCreateSchemaSetUsingModuleSetTag(final String schemaSetName,
- final String moduleSetTag,
- final String existingAnchorName,
- final boolean inUpgrade) {
- log.info("Found cm handle having module set tag: {}", moduleSetTag);
- final Collection<ModuleReference> moduleReferencesFromExistingCmHandle =
- cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
- existingAnchorName);
- if (inUpgrade) {
- cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
- NO_NEW_MODULES, moduleReferencesFromExistingCmHandle);
- } else {
- cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
- schemaSetName, NO_NEW_MODULES, moduleReferencesFromExistingCmHandle);
+ identifiedNewModuleReferences);
}
- return moduleReferencesFromExistingCmHandle;
+ return newModuleNameToContentMap;
}
- private String getModuleSetTag(final YangModelCmHandle yangModelCmHandle,
- final CompositeState compositeState,
- final boolean inUpgrade) {
+ private String getModuleSetTag(final YangModelCmHandle yangModelCmHandle, final boolean inUpgrade) {
if (inUpgrade) {
- return ModuleOperationsUtils.getLockedCompositeStateDetails(compositeState.getLockReason())
- .get(ModuleOperationsUtils.MODULE_SET_TAG_KEY);
+ return ModuleOperationsUtils.getUpgradedModuleSetTagFromLockReason(
+ yangModelCmHandle.getCompositeState().getLockReason());
}
return yangModelCmHandle.getModuleSetTag();
}
- private void updateModuleSetTagCache(final String moduleSetTag,
- final Collection<ModuleReference> allModuleReferencesFromCmHandle) {
- if (StringUtils.isNotBlank(moduleSetTag)) {
- moduleSetTagCache.putIfAbsent(moduleSetTag, allModuleReferencesFromCmHandle);
- }
- }
-
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java
index e214044189..804653a168 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java
@@ -67,7 +67,7 @@ public class ModuleSyncTasks {
final YangModelCmHandle yangModelCmHandle =
YangDataConverter.convertCmHandleToYangModel(cmHandleAsDataNode, cmHandleId);
final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
- final boolean inUpgrade = ModuleOperationsUtils.isInUpgradeOrUpgradeFailed(compositeState);
+ final boolean inUpgrade = ModuleOperationsUtils.inUpgradeOrUpgradeFailed(compositeState);
try {
if (!inUpgrade) {
moduleSyncService.deleteSchemaSetIfExists(cmHandleId);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java
new file mode 100644
index 0000000000..1be1a90853
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java
@@ -0,0 +1,142 @@
+/*
+ * ============LICENSE_START========================================================
+ * Copyright (c) 2024 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class AlternateIdChecker {
+
+ private final InventoryPersistence inventoryPersistence;
+
+ private static final String NO_CURRENT_ALTERNATE_ID = "";
+
+ /**
+ * Check if the alternate can be applied to the given cm handle (id).
+ * Conditions:
+ * - proposed alternate is blank (it wil be ignored)
+ * - proposed alternate is same as current (no change)
+ * - proposed alternate is not in use for a different cm handle (in the DB)
+ *
+ * @param cmHandleId cm handle id
+ * @param proposedAlternateId proposed alternate id
+ * @return true if the new alternate id not in use or equal to current alternate id, false otherwise
+ */
+ public boolean canApplyAlternateId(final String cmHandleId, final String proposedAlternateId) {
+ String currentAlternateId = "";
+ try {
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ currentAlternateId = yangModelCmHandle.getAlternateId();
+ } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
+ // work with blank current alternate id
+ }
+ return this.canApplyAlternateId(cmHandleId, currentAlternateId, proposedAlternateId);
+ }
+
+ /**
+ * Check if the alternate can be applied to the given cm handle.
+ * Conditions:
+ * - proposed alternate is blank (it wil be ignored)
+ * - proposed alternate is same as current (no change)
+ * - proposed alternate is not in use for a different cm handle (in the DB)
+ *
+ * @param cmHandleId cm handle id
+ * @param currentAlternateId current alternate id
+ * @param proposedAlternateId new alternate id
+ * @return true if the new alternate id not in use or equal to current alternate id, false otherwise
+ */
+ public boolean canApplyAlternateId(final String cmHandleId,
+ final String currentAlternateId,
+ final String proposedAlternateId) {
+ if (StringUtils.isBlank(currentAlternateId)) {
+ if (alternateIdAlreadyInDb(proposedAlternateId)) {
+ log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
+ + "assigned to a different cm handle", cmHandleId);
+ return false;
+ }
+ return true;
+ }
+ if (currentAlternateId.equals(proposedAlternateId)) {
+ return true;
+ }
+ log.warn("Alternate id update ignored, cannot update cm handle {}, already has an alternate id of {}",
+ cmHandleId, currentAlternateId);
+ return false;
+ }
+
+ /**
+ * Check all alternate ids of a batch of NEW cm handles.
+ * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted.
+ * This method can only be used for NEW cm handle registrations NOT for updating existing ones
+ *
+ * @param newNcmpServiceCmHandles the proposed new cm handles
+ * @return collection of cm handles ids which are acceptable
+ */
+ public Collection<String> getIdsOfCmHandlesWithAcceptableAlternateId(
+ final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) {
+ final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size());
+ final Collection<String> acceptedCmHandleIds = new ArrayList<>(newNcmpServiceCmHandles.size());
+ for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) {
+ final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
+ final String proposedAlternateId = ncmpServiceCmHandle.getAlternateId();
+ final boolean isAcceptable;
+ if (StringUtils.isEmpty(proposedAlternateId)) {
+ isAcceptable = true;
+ } else {
+ if (acceptedAlternateIds.contains(proposedAlternateId)) {
+ isAcceptable = false;
+ log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
+ + "assigned to a different cm handle (in this batch)", cmHandleId);
+ } else {
+ isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId);
+ }
+ }
+ if (isAcceptable) {
+ acceptedAlternateIds.add(proposedAlternateId);
+ acceptedCmHandleIds.add(cmHandleId);
+ }
+ }
+ return acceptedCmHandleIds;
+ }
+
+ private boolean alternateIdAlreadyInDb(final String alternateId) {
+ try {
+ inventoryPersistence.getCmHandleDataNodeByAlternateId(alternateId);
+ } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
deleted file mode 100644
index a88adbd110..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ============LICENSE_START========================================================
- * Copyright (c) 2024 Nordix Foundation.
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.utils;
-
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService;
-import org.springframework.stereotype.Service;
-
-@Service
-@Slf4j
-@RequiredArgsConstructor
-public class CmHandleIdMapper {
-
- private final Map<String, String> alternateIdPerCmHandleId;
- private final Map<String, String> cmHandleIdPerAlternateId;
- private final NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService;
-
- private boolean cacheIsInitialized = false;
-
- public String cmHandleIdToAlternateId(final String cmHandleId) {
- initializeCache();
- return alternateIdPerCmHandleId.get(cmHandleId);
- }
-
- public String alternateIdToCmHandleId(final String alternateId) {
- initializeCache();
- return cmHandleIdPerAlternateId.get(alternateId);
- }
-
- public boolean addMapping(final String cmHandleId, final String alternateId) {
- initializeCache();
- return addMappingWithValidation(cmHandleId, alternateId);
- }
-
-
- private boolean addMappingWithValidation(final String cmHandleId, final String alternateId) {
- if (alternateIdPerCmHandleId.containsKey(cmHandleId)) {
- final String originalAlternateId = alternateIdPerCmHandleId.get(cmHandleId);
- if (!originalAlternateId.equals(alternateId)) {
- log.warn("Alternate id update ignored, cannot update cm handle {}, already has an alternate id of {}",
- cmHandleId, originalAlternateId);
- }
- return false;
- }
- if (StringUtils.isBlank(alternateId)) {
- return false;
- }
- alternateIdPerCmHandleId.put(cmHandleId, alternateId);
- cmHandleIdPerAlternateId.put(alternateId, cmHandleId);
- return true;
- }
-
- public void removeMapping(final String cmHandleId) {
- final String alternateId = alternateIdPerCmHandleId.remove(cmHandleId);
- removeAlternateIdWithValidation(alternateId);
- }
-
- private void removeAlternateIdWithValidation(final String alternateId) {
- if (alternateId != null) {
- cmHandleIdPerAlternateId.remove(alternateId);
- }
- }
-
- private void initializeCache() {
- if (!cacheIsInitialized) {
- networkCmProxyCmHandleQueryService.getAllCmHandles().forEach(cmHandle ->
- addMappingWithValidation(cmHandle.getCmHandleId(), cmHandle.getAlternateId())
- );
- log.info("Alternate ID cache initialized from DB with {} cm handle/alternate id pairs ",
- alternateIdPerCmHandleId.size());
- cacheIsInitialized = true;
- }
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
index 3be97e8ee1..c77e9aa7a6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
@@ -54,6 +54,7 @@ public class YangDataConverter {
final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
ncmpServiceCmHandle.setCmHandleId(yangModelCmHandle.getId());
ncmpServiceCmHandle.setCompositeState(yangModelCmHandle.getCompositeState());
+ ncmpServiceCmHandle.setModuleSetTag(yangModelCmHandle.getModuleSetTag());
ncmpServiceCmHandle.setAlternateId(yangModelCmHandle.getAlternateId());
setDmiProperties(dmiProperties, ncmpServiceCmHandle);
setPublicProperties(publicProperties, ncmpServiceCmHandle);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
index 03e53fc427..b2758d9d5f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
@@ -24,7 +24,6 @@ package org.onap.cps.ncmp.api.impl.yangmodels;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -94,6 +93,7 @@ public class YangModelCmHandle {
copy.dmiProperties = original.getDmiProperties() == null ? null : new ArrayList<>(original.getDmiProperties());
copy.publicProperties =
original.getPublicProperties() == null ? null : new ArrayList<>(original.getPublicProperties());
+ copy.moduleSetTag = original.getModuleSetTag();
copy.alternateId = original.getAlternateId();
return copy;
}
@@ -134,7 +134,7 @@ public class YangModelCmHandle {
* @return dmi service name
*/
public String resolveDmiServiceName(final RequiredDmiService requiredService) {
- if (isNullEmptyOrBlank(dmiServiceName)) {
+ if (StringUtils.isBlank(dmiServiceName)) {
if (RequiredDmiService.DATA.equals(requiredService)) {
return dmiDataServiceName;
}
@@ -151,10 +151,6 @@ public class YangModelCmHandle {
return yangModelCmHandleProperties;
}
- private static boolean isNullEmptyOrBlank(final String serviceName) {
- return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
- }
-
@AllArgsConstructor
@Data
public static class Property {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index c7ac8ab8b6..313d1b4afd 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -27,8 +27,10 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import java.util.stream.Collectors
+import org.onap.cps.ncmp.api.impl.inventory.CompositeState
import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
+import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
import org.onap.cps.ncmp.api.models.UpgradedCmHandles
import com.fasterxml.jackson.databind.ObjectMapper
import com.hazelcast.map.IMap
@@ -68,9 +70,14 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def mockModuleSyncStartedOnCmHandles = Mock(IMap<String, Object>)
def trustLevelPerDmiPlugin = [:]
def mockTrustLevelManager = Mock(TrustLevelManager)
- def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
+ def mockAlternateIdChecker = Mock(AlternateIdChecker)
def objectUnderTest = getObjectUnderTest()
- def mockModuleSetTagCache = [:]
+
+ def setup() {
+ // always accept all cm handles
+ mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(_) >>
+ { args -> args[0].stream().map(it -> it.cmHandleId).collect(Collectors.toList()) }
+ }
def 'DMI Registration: Create, Update, Delete & Upgrade operations are processed in the right order'() {
given: 'a registration with operations of all types'
@@ -81,6 +88,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
and: 'cm handles are persisted'
mockInventoryPersistence.getYangModelCmHandles(['cmhandle-2']) >> [new YangModelCmHandle()]
+ mockInventoryPersistence.getYangModelCmHandle('cmhandle-3') >> new YangModelCmHandle(id: 'cmhandle-3', moduleSetTag: '', compositeState: new CompositeState(cmHandleState: CmHandleState.READY))
and: 'cm handle is in READY state'
mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> true
when: 'registration is processed'
@@ -88,7 +96,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
then: 'cm-handles are removed first'
1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_)
and: 'de-registered cm handle entry is removed from in progress map'
- 2 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
+ 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
then: 'cm-handles are created'
1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_)
then: 'cm-handles are updated'
@@ -102,15 +110,15 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
and: 'exception while checking cm handle state'
- mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> isReady
+ mockInventoryPersistence.getYangModelCmHandle('cmhandle-3') >> new YangModelCmHandle(id: 'cmhandle-3', moduleSetTag: '', compositeState: new CompositeState(cmHandleState: cmHandleState))
when: 'registration is processed'
def result = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'upgrade operation contains expected error code'
- assert result.upgradedCmHandles.status[0] == expectedResponseStatus
+ assert result.upgradedCmHandles[0].status == expectedResponseStatus
where: 'the following parameters are used'
- scenario | isReady || expectedResponseStatus
- 'READY' | true || Status.SUCCESS
- 'Not READY' | false || Status.FAILURE
+ scenario | cmHandleState || expectedResponseStatus
+ 'READY' | CmHandleState.READY || Status.SUCCESS
+ 'Not READY' | CmHandleState.LOCKED || Status.FAILURE
}
def 'DMI Registration upgrade with exception #scenario'() {
@@ -118,7 +126,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def dmiRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
dmiRegistration.setUpgradedCmHandles(new UpgradedCmHandles(cmHandles: ['cmhandle-3'], moduleSetTag: 'some-module-set-tag'))
and: 'exception while checking cm handle state'
- mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> { throw exception }
+ mockInventoryPersistence.getYangModelCmHandle('cmhandle-3') >> { throw exception }
when: 'registration is processed'
def result = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'upgrade operation contains expected error code'
@@ -160,7 +168,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
when: 'update registration and sync module is called with correct DMI plugin information'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'create cm handles registration and sync modules is called with the correct plugin information'
- 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
+ 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration, _)
and: 'dmi is added to the dmi trustLevel map'
assert trustLevelPerDmiPlugin.size() == 1
assert trustLevelPerDmiPlugin.containsKey(expectedDmiPluginRegisteredName)
@@ -433,19 +441,19 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def 'Adding data to alternate id caches.'() {
given: 'a registration with three CM Handles to be created'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server',
- createdCmHandles: [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')])
+ def ncmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')]
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', createdCmHandles: ncmpServiceCmHandles)
when: 'the DMI plugin registration happens'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'the new alternate id is added to the cache'
- 1 * mockCmHandleIdMapper.addMapping('cmhandle1', 'my-alternate-id-1')
+ 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithAcceptableAlternateId(ncmpServiceCmHandles) >> ['cmhandle1']
}
def getObjectUnderTest() {
return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries,
stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService,
- mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockCmHandleIdMapper, mockModuleSetTagCache))
+ mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockAlternateIdChecker))
}
def addPersistedYangModelCmHandles(ids) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index c835056f37..fc548ebe9b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -32,7 +32,7 @@ import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RU
import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
+import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
import com.hazelcast.map.IMap
import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
@@ -54,7 +54,7 @@ import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.api.models.DataOperationRequest
import org.onap.cps.spi.exceptions.CpsException
import org.onap.cps.spi.model.ConditionProperties
-import spock.lang.Shared
+
import java.util.stream.Collectors
import org.onap.cps.utils.JsonObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper
@@ -80,14 +80,11 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
def mockTrustLevelManager = Mock(TrustLevelManager)
- def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
- def mockModuleSetTagCache = [:]
+ def mockAlternateIdChecker = Mock(AlternateIdChecker)
def NO_TOPIC = null
def NO_REQUEST_ID = null
- @Shared
def OPTIONS_PARAM = '(a=1,b=2)'
- @Shared
def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id')
def objectUnderTest = new NetworkCmProxyDataServiceImpl(
@@ -102,8 +99,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
stubModuleSyncStartedOnCmHandles,
stubTrustLevelPerDmiPlugin,
mockTrustLevelManager,
- mockCmHandleIdMapper,
- mockModuleSetTagCache)
+ mockAlternateIdChecker)
def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
@@ -177,14 +173,17 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
given: 'the system returns a yang modelled cm handle'
def dmiServiceName = 'some service name'
def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
- lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
- lastUpdateTime: 'some-timestamp',
- dataSyncEnabled: false,
- dataStores: dataStores())
+ lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
+ lastUpdateTime: 'some-timestamp',
+ dataSyncEnabled: false,
+ dataStores: dataStores())
def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
+ def moduleSetTag = 'some-module-set-tag'
+ def alternateId = 'some-alternate-id'
def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
- dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
+ dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState,
+ moduleSetTag: moduleSetTag, alternateId: alternateId)
1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
when: 'getting cm handle details for a given cm handle id from ncmp service'
def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
@@ -192,13 +191,16 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
result.class == NcmpServiceCmHandle.class
and: 'the cm handle contains the cm handle id'
result.cmHandleId == 'some-cm-handle'
+ and: 'the cm handle contains the alternate id'
+ result.alternateId == 'some-alternate-id'
+ and: 'the cm handle contains the module-set-tag'
+ result.moduleSetTag == 'some-module-set-tag'
and: 'the cm handle contains the DMI Properties'
result.dmiProperties ==[ Book:'Romance Novel' ]
and: 'the cm handle contains the public Properties'
result.publicProperties == [ "Public Book":'Public Romance Novel' ]
and: 'the cm handle contains the cm handle composite state'
result.compositeState == compositeState
-
}
def 'Get cm handle public properties'() {
@@ -269,7 +271,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
when: 'parse and create cm handle in dmi registration then sync module'
- objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration)
+ objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration, ['test-cm-handle-id'])
then: 'system persists the cm handle state'
1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> {
args -> {
@@ -280,7 +282,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
}
}
}
-
+
def 'Execute cm handle id search'() {
given: 'valid CmHandleQueryApiParameters input'
def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
index f94c34c589..d822f2e639 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
@@ -22,35 +22,33 @@
package org.onap.cps.ncmp.api.impl
-
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
-
import org.onap.cps.api.CpsDataService
-import org.onap.cps.utils.JsonObjectMapper
import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.spi.exceptions.DataValidationException
+import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
+import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
+
class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
def mockCpsDataService = Mock(CpsDataService)
def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
+ def mockAlternateIdChecker = Mock(AlternateIdChecker)
- def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockCmHandleIdMapper)
+ def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker)
def static cmHandleId = 'myHandle1'
def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']"
@@ -62,7 +60,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
def 'Update CM Handle Public Properties: #scenario'() {
given: 'the CPS service return a CM handle'
- mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> cmHandleDataNodeAsCollection
+ mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> cmHandleDataNodeAsCollection
and: 'an update cm handle request with public properties updates'
def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: updatedPublicProperties)]
when: 'update data node leaves is called with the update request'
@@ -84,7 +82,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
def 'Update DMI Properties: #scenario'() {
given: 'the CPS service return a CM handle'
- mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> cmHandleDataNodeAsCollection
+ mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> cmHandleDataNodeAsCollection
and: 'an update cm handle request with DMI properties updates'
def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: updatedDmiProperties)]
when: 'update data node leaves is called with the update request'
@@ -108,7 +106,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
def 'Update CM Handle Properties, remove all properties: #scenario'() {
given: 'the CPS service return a CM handle'
def cmHandleDataNode = new DataNode(xpath: cmHandleXpath, childDataNodes: originalPropertyDataNodes)
- mockInventoryPersistence.getCmHandleDataNode(cmHandleId) >> [cmHandleDataNode]
+ mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [cmHandleDataNode]
and: 'an update cm handle request that removes all public properties(existing and non-existing)'
def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp3': null, 'publicProp4': null])]
when: 'update data node leaves is called with the update request'
@@ -131,7 +129,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
given: 'cm handles request'
def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: [:], dmiProperties: [:])]
and: 'data node cannot be found'
- mockInventoryPersistence.getCmHandleDataNode(*_) >> { throw exception }
+ mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(*_) >> { throw exception }
when: 'update data node leaves is called using correct parameters'
def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
then: 'one failed registration response'
@@ -156,7 +154,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:]),
new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:])]
and: 'data node can be found for 1st and 3rd cm-handle but not for 2nd cm-handle'
- mockInventoryPersistence.getCmHandleDataNode(*_) >> cmHandleDataNodeAsCollection >> {
+ mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(*_) >> cmHandleDataNodeAsCollection >> {
throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) } >> cmHandleDataNodeAsCollection
when: 'update data node leaves is called using correct parameters'
def cmHandleResponseList = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
@@ -194,7 +192,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
{ args ->
assert args[3].contains('alt-1')
}
- mockCmHandleIdMapper.addMapping(cmHandleId, 'alt-1') >> isNewMapping
+ mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping
where: 'following updates are attempted'
scenario | isNewMapping || callsToDataService
'new alternate id ' | true || 1
@@ -205,8 +203,8 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
given: 'an existing data node and an update request with an alternate id'
def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')
DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['alternate-id': null])
- and: 'a new mapping is added'
- mockCmHandleIdMapper.addMapping(cmHandleId, 'alt-1') >> true
+ and: 'an applicable alternate id for the cm handle'
+ mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> true
and: 'but an exception occurs while saving'
def originalException = new NullPointerException('some exception')
mockCpsDataService.updateNodeLeaves(*_) >> { throw originalException }
@@ -215,8 +213,6 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
then: 'the original exception is thrown up'
def thrownException = thrown(NullPointerException)
assert thrownException == originalException
- and: 'the mapping is removed from the cache'
- 1 * mockCmHandleIdMapper.removeMapping(cmHandleId)
}
def convertToProperties(expectedPropertiesAfterUpdateAsMap) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfigSpec.groovy
deleted file mode 100644
index 71c5293e27..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/AlternateIdCacheConfigSpec.groovy
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * ============LICENSE_START========================================================
- * Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config.embeddedcache
-
-import com.hazelcast.core.Hazelcast
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import spock.lang.Specification
-
-@SpringBootTest(classes = [AlternateIdCacheConfig])
-class AlternateIdCacheConfigSpec extends Specification {
-
- @Autowired
- private Map<String, String> cmHandleIdPerAlternateId
- @Autowired
- private Map<String, String> alternateIdPerCmHandleId
-
- def 'Embedded (hazelcast) cache for alternate id - cm handle id caches.'() {
- expect: 'system is able to create an instance of the Alternate ID Cache'
- assert null != cmHandleIdPerAlternateId
- assert null != alternateIdPerCmHandleId
- and: 'there are at least 2 instances'
- assert Hazelcast.allHazelcastInstances.size() > 1
- and: 'Alternate ID Caches are present'
- assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceAlternateIdPerCmHandleIdMap')
- && Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceCmHandleIdPerAlternateIdMap')
- }
-
- def 'Verify configs of the alternate id distributed objects.'(){
- when: 'retrieving the map config of module set tag'
- def alternateIdConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceAlternateIdPerCmHandleIdMap').config
- def alternateIdMapConfig = alternateIdConfig.mapConfigs.get('alternateIdPerCmHandleIdMapConfig')
- def cmHandleIdConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceCmHandleIdPerAlternateIdMap').config
- def cmHandleIdIdMapConfig = cmHandleIdConfig.mapConfigs.get('cmHandleIdPerAlternateIdMapConfig')
- then: 'the map configs have the correct number of backups'
- assert alternateIdMapConfig.backupCount == 3
- assert alternateIdMapConfig.asyncBackupCount == 3
- assert cmHandleIdIdMapConfig.backupCount == 3
- assert cmHandleIdIdMapConfig.asyncBackupCount == 3
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfigSpec.groovy
deleted file mode 100644
index 8a6a32bd8d..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/ModuleSetTagCacheConfigSpec.groovy
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.config.embeddedcache
-
-import com.hazelcast.config.Config
-import com.hazelcast.core.Hazelcast
-import org.onap.cps.spi.model.ModuleReference
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import spock.lang.Specification
-
-@SpringBootTest(classes = [ModuleSetTagCacheConfig])
-class ModuleSetTagCacheConfigSpec extends Specification {
-
- @Autowired
- private Map<String, Collection<ModuleReference>> moduleSetTagCache
-
- def 'Embedded (hazelcast) caches for module set tag.'() {
- expect: 'system is able to create an instance of a map to hold module set tags'
- assert null != moduleSetTagCache
- and: 'there is at least 1 instance'
- assert Hazelcast.allHazelcastInstances.size() > 0
- and: 'hazelcast instance name of module set tag is correct'
- assert Hazelcast.allHazelcastInstances.name.contains('moduleSetTags')
- }
-
- def 'Verify configs of module set tag distributed object.'(){
- when: 'retrieving the map config of module set tag'
- def cacheConfig = Hazelcast.getHazelcastInstanceByName('moduleSetTags').config
- def moduleSetTagMapConfig = cacheConfig.mapConfigs.get('moduleSetTagCacheMapConfig')
- then: 'the module set tag map config has correct backup counts'
- assert moduleSetTagMapConfig.backupCount == 3
- assert moduleSetTagMapConfig.asyncBackupCount == 3
- }
-
- def 'Verify deployment network configs of distributed cache of module set tag object.'() {
- given: 'network config of module set tag cache'
- def moduleSetTagNetworkConfig = Hazelcast.getHazelcastInstanceByName('moduleSetTags').config.networkConfig
- expect: 'module set tag cache has the correct settings'
- assert moduleSetTagNetworkConfig.join.autoDetectionConfig.enabled
- assert !moduleSetTagNetworkConfig.join.kubernetesConfig.enabled
- }
-
- def 'Verify network of module set tag cache'() {
- given: 'Synchronization config object and test configuration'
- def objectUnderTest = new ModuleSetTagCacheConfig()
- def testConfig = new Config()
- when: 'kubernetes properties are enabled'
- objectUnderTest.cacheKubernetesEnabled = true
- objectUnderTest.cacheKubernetesServiceName = 'test-service-name'
- and: 'method called to update the discovery mode'
- objectUnderTest.updateDiscoveryMode(testConfig)
- then: 'applied properties are reflected'
- assert testConfig.networkConfig.join.kubernetesConfig.enabled
- assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name'
-
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
index a3b923f939..83acb2238a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -22,32 +22,34 @@
package org.onap.cps.ncmp.api.impl.inventory
-import org.onap.cps.api.CpsAnchorService
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
-import org.onap.cps.utils.JsonObjectMapper
import org.onap.cps.spi.utils.CpsValidator
+import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
class InventoryPersistenceImplSpec extends Specification {
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
@@ -60,8 +62,10 @@ class InventoryPersistenceImplSpec extends Specification {
def mockCpsValidator = Mock(CpsValidator)
+ def mockCmHandleQueries = Mock(CmHandleQueries)
+
def objectUnderTest = new InventoryPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService,
- mockCpsValidator, mockCpsAnchorService)
+ mockCpsValidator, mockCpsAnchorService, mockCmHandleQueries)
def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
.format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
@@ -283,13 +287,32 @@ class InventoryPersistenceImplSpec extends Specification {
def 'Get cmHandle data node'() {
given: 'expected xPath to get cmHandle data node'
- def expectedXPath = '/dmi-registry/cm-handles[@id=\'sample cmHandleId\']';
+ def expectedXPath = '/dmi-registry/cm-handles[@id=\'sample cmHandleId\']'
when: 'the method to get data nodes is called'
- objectUnderTest.getCmHandleDataNode('sample cmHandleId')
+ objectUnderTest.getCmHandleDataNodeByCmHandleId('sample cmHandleId')
then: 'the data persistence service method to get cmHandle data node is invoked once with expected xPath'
1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, expectedXPath, INCLUDE_ALL_DESCENDANTS)
}
+ def 'Get cm handle data node'() {
+ given: 'expected xPath to get cmHandle data node'
+ def expectedXPath = '/dmi-registry/cm-handles[@alternate-id=\'alternate id\']'
+ and: 'query service is invoked with expected xpath'
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(expectedXPath, OMIT_DESCENDANTS) >> [new DataNode()]
+ expect: 'getting the cm handle data node'
+ assert objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id') == new DataNode()
+ }
+
+ def 'Attempt to get non existing cm handle data node by alternate id'() {
+ given: 'query service is invoked and returns empty collection of data nodes'
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
+ when: 'getting the cm handle data node'
+ objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id')
+ then: 'no data found exception thrown'
+ def thrownException = thrown(DataNodeNotFoundException)
+ assert thrownException.getMessage().contains('DataNode not found')
+ }
+
def 'Get CM handles that has given module names'() {
when: 'the method to get cm handles is called'
objectUnderTest.getCmHandleIdsWithGivenModules(['sample-module-name'])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
index 827a548ae4..44bc182000 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
@@ -125,7 +125,7 @@ class ModuleOperationsUtilsSpec extends Specification{
where:
scenario | moduleSetTag || expectedDetails
'a module set tag' | 'someModuleSetTag' || 'someModuleSetTag'
- 'empty module set tag' | '' || 'not-specified'
+ 'empty module set tag' | '' || ''
}
def 'Get all locked cm-Handles where lock reasons are model sync failed or upgrade'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy
index de783ed2ca..b0ff6d886a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy
@@ -50,10 +50,9 @@ class ModuleSyncServiceSpec extends Specification {
def mockCmHandleQueries = Mock(CmHandleQueries)
def mockCpsDataService = Mock(CpsDataService)
def mockJsonObjectMapper = Mock(JsonObjectMapper)
- def mockModuleSetTagCache = [:]
def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService,
- mockCmHandleQueries, mockCpsDataService, mockCpsAnchorService, mockJsonObjectMapper, mockModuleSetTagCache)
+ mockCmHandleQueries, mockCpsDataService, mockCpsAnchorService, mockJsonObjectMapper)
def expectedDataspaceName = NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
def static cmHandleWithModuleSetTag = new DataNodeBuilder().withXpath("//cm-handles[@module-set-tag='tag-1'][@id='otherId']").withAnchor('otherId').build()
@@ -96,11 +95,7 @@ class ModuleSyncServiceSpec extends Specification {
and: 'some module references'
def moduleReferences = [ new ModuleReference('module1','1') ]
and: 'cache or DMI operations returns some module references for upgraded cm handle'
- if (populateCache) {
- mockModuleSetTagCache.put('tag-1', moduleReferences)
- } else {
- mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences
- }
+ mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences
and: 'none of these module references are new (unknown to the system)'
mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> []
and: 'CPS-Core returns list of existing module resources for TBD'
@@ -118,10 +113,9 @@ class ModuleSyncServiceSpec extends Specification {
and: 'No anchor is created for the upgraded cm handle'
0 * mockCpsAnchorService.createAnchor(*_)
where: 'the following parameters are used'
- scenario | populateCache | existingCmHandlesWithSameTag || expectedCallsToUpgradeSchemaSet | expectedCallsToCeateSchemaSet
- 'new' | false | [] || 0 | 1
- 'in cache' | true | [] || 1 | 0
- 'in database' | false | [cmHandleWithModuleSetTag] || 1 | 0
+ scenario | existingCmHandlesWithSameTag || expectedCallsToUpgradeSchemaSet | expectedCallsToCeateSchemaSet
+ 'new' | [] || 1 | 0
+ 'in database' | [cmHandleWithModuleSetTag] || 1 | 0
}
def 'upgrade model for a existing cm handle'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy
new file mode 100644
index 0000000000..f41fd6cdf3
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy
@@ -0,0 +1,97 @@
+/*
+ * ============LICENSE_START========================================================
+ * Copyright (c) 2024 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.impl.utils
+
+
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.spi.model.DataNodeBuilder
+import spock.lang.Specification
+
+class AlternateIdCheckerSpec extends Specification {
+
+ def mockInventoryPersistenceService = Mock(InventoryPersistence)
+ def someDataNode = new DataNodeBuilder().build()
+ def dataNodeFoundException = new DataNodeNotFoundException('', '')
+
+ def objectUnderTest = new AlternateIdChecker(mockInventoryPersistenceService)
+
+ def 'Check new cm handle with new alternate id.'() {
+ given: 'inventory persistence can not find cm handle id'
+ mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException}
+ and: 'inventory persistence can not find alternate id'
+ mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> {throw dataNodeFoundException}
+ expect: 'mapping can be added'
+ assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id')
+ }
+
+ def 'Check new cm handle with used alternate id.'() {
+ given: 'inventory persistence can not find cm handle id'
+ mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException}
+ and: 'inventory persistence can find alternate id'
+ mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> { someDataNode }
+ expect: 'mapping can not be added'
+ assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id') == false
+ }
+
+ def 'Check for existing cm handle with #currentAlternateId.'() {
+ given: 'a cm handle with the #currentAlternateId'
+ def yangModelCmHandle = new YangModelCmHandle(alternateId: currentAlternateId)
+ and: 'inventory service finds the cm handle'
+ mockInventoryPersistenceService.getYangModelCmHandle('my cm handle') >> yangModelCmHandle
+ expect: 'add mapping returns expected result'
+ assert canAdd == objectUnderTest.canApplyAlternateId('my cm handle', 'same alternate id')
+ where: 'following alternate ids is used'
+ currentAlternateId || canAdd
+ 'same alternate id' || true
+ 'other alternate id' || false
+ }
+
+ def 'Check a batch of NEW cm handles with #scenario.'() {
+ given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2'
+ def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1),
+ new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)]
+ and: 'the database already contains cm handle(s) with these alternate ids: #alreadyinDb'
+ mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >>
+ { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() }
+ when: 'the batch of new cm handles is checked'
+ def result = objectUnderTest.getIdsOfCmHandlesWithAcceptableAlternateId(batch)
+ then: 'the result only contains the ids of the acceptable cm handles'
+ assert result.contains('ch-1') == acceptCh1
+ assert result.contains('ch-2') == acceptCh2
+ where: 'the following alternate ids are used'
+ scenario | alt1 | alt2 | altAlreadyInDb || acceptCh1 | acceptCh2
+ 'no alternate ids' | '' | '' | ['dont matter'] || true | true
+ 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || true | true
+ 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || false | true
+ 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || false | false
+ 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || true | false
+ }
+
+ def throwDataNodeNotFoundException() {
+ // cannot 'return' an exception in conditional stub behavior, so hence a method call that will always throw this exception
+ throw dataNodeFoundException
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy
deleted file mode 100644
index 55ccdf3be5..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapperSpec.groovy
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * ============LICENSE_START========================================================
- * Copyright (c) 2024 Nordix Foundation.
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.impl.utils
-
-import ch.qos.logback.classic.Level
-import ch.qos.logback.classic.Logger
-import ch.qos.logback.classic.spi.ILoggingEvent
-import ch.qos.logback.core.read.ListAppender
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.slf4j.LoggerFactory
-import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
-import spock.lang.Specification
-
-class CmHandleIdMapperSpec extends Specification {
-
- def alternateIdPerCmHandle = new HashMap<String, String>()
- def cmHandlePerAlternateId = new HashMap<String, String>()
- def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
-
- def objectUnderTest = new CmHandleIdMapper(alternateIdPerCmHandle, cmHandlePerAlternateId, mockCpsCmHandlerQueryService)
-
- def logger = Spy(ListAppender<ILoggingEvent>)
-
- def setup() {
- ((Logger) LoggerFactory.getLogger(CmHandleIdMapper.class)).addAppender(logger)
- logger.start()
- mockCpsCmHandlerQueryService.getAllCmHandles() >> []
- assert objectUnderTest.addMapping('my cmhandle id', 'my alternate id')
- }
-
- void cleanup() {
- ((Logger) LoggerFactory.getLogger(CmHandleIdMapper.class)).detachAndStopAllAppenders()
- }
-
- def 'Checking entries in the cache.'() {
- expect: 'the alternate id can be converted to cmhandle id'
- assert objectUnderTest.alternateIdToCmHandleId('my alternate id') == 'my cmhandle id'
- and: 'the cmhandle id can be converted to alternate id'
- assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id'
- }
-
- def 'Attempt adding #scenario alternate id.'() {
- expect: 'cmhandle id - alternate id mapping fails'
- assert objectUnderTest.addMapping('ch-1', alternateId) == false
- and: 'alternate id looked up by cmhandle id unsuccessfully'
- assert objectUnderTest.cmHandleIdToAlternateId('ch-1') == null
- where: 'alternate id has an invalid value'
- scenario | alternateId
- 'empty' | ''
- 'blank' | ' '
- 'null' | null
- }
-
- def 'Remove an entry from the cache.'() {
- when: 'removing an entry'
- objectUnderTest.removeMapping('my cmhandle id')
- then: 'converting alternate id returns null'
- assert objectUnderTest.alternateIdToCmHandleId('my alternate id') == null
- and: 'converting cmhandle id returns null'
- assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == null
- }
-
- def 'Attempt to remove a non-existing entry from the cache.'() {
- when: 'removing an entry that is not cached'
- objectUnderTest.removeMapping('non-cached cmhandle id')
- then: 'deleting from the cmhandle cache returns null'
- assert alternateIdPerCmHandle.remove('non-cached cmhandle id') == null
- and: 'removal from the alternate id cache is skipped'
- 0 * cmHandlePerAlternateId.remove(_)
- }
-
- def 'Cannot update existing alternate id.'() {
- given: 'attempt to update an existing alternate id'
- objectUnderTest.addMapping('my cmhandle id', 'other id')
- expect: 'still returns the original alternate id'
- assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id'
- and: 'converting other alternate id returns null'
- assert objectUnderTest.alternateIdToCmHandleId('other id') == null
- and: 'a warning is logged with the original alternate id'
- def lastLoggingEvent = logger.list[1]
- assert lastLoggingEvent.level == Level.WARN
- assert lastLoggingEvent.formattedMessage.contains('my alternate id')
- }
-
- def 'Update existing alternate id with the same value.'() {
- expect: 'update an existing alternate id with the same value returns false (no update)'
- assert objectUnderTest.addMapping('my cmhandle id', 'my alternate id') == false
- and: 'conversion still returns the original alternate id'
- assert objectUnderTest.cmHandleIdToAlternateId('my cmhandle id') == 'my alternate id'
- }
-
- def 'Initializing cache #scenario.'() {
- when: 'the cache is (re-)initialized'
- objectUnderTest.cacheIsInitialized = false
- objectUnderTest.initializeCache()
- then: 'the alternate id can be converted to cmhandle id'
- assert objectUnderTest.alternateIdToCmHandleId('alt-1') == convertedCmHandleId
- and: 'the cm handle id can be converted to alternate id'
- assert objectUnderTest.cmHandleIdToAlternateId('ch-1') == convertedAlternatId
- and: 'the query service is called to get the initial data'
- 1 * mockCpsCmHandlerQueryService.getAllCmHandles() >> persistedCmHandles
- where: 'the initial data has a cm handle #scenario'
- scenario | persistedCmHandles || convertedAlternatId | convertedCmHandleId
- 'with alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: 'alt-1')] || 'alt-1' | 'ch-1'
- 'without alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1')] || null | null
- 'with blank alternate id' | [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: ' ')] || null | null
- }
-} \ No newline at end of file
diff --git a/docs/deployment.rst b/docs/deployment.rst
index 3b5aad1bfc..c1ee1eb2ea 100644
--- a/docs/deployment.rst
+++ b/docs/deployment.rst
@@ -335,9 +335,5 @@ Below are the list of distributed datastructures that we have.
+--------------+------------------------------------+-----------------------------------------------------------+
| cps-ncmp | cmNotificationSubscriptionCache | Stores and tracks cm notification subscription requests. |
+--------------+------------------------------------+-----------------------------------------------------------+
-| cps-ncmp | alternateIdPerCmHandleId | Stores the alternate id for each cm handle id. |
-+--------------+------------------------------------+-----------------------------------------------------------+
-| cps-ncmp | cmHandleIdPerAlternateId | Stores the cm handle id for each alternate id. |
-+--------------+------------------------------------+-----------------------------------------------------------+
-Total number of caches : 10
+Total number of caches : 8
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index ecf7d67d2d..23504e49cd 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -30,6 +30,10 @@ import org.onap.cps.integration.DatabaseTestContainer
import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.repository.DataspaceRepository
@@ -40,10 +44,17 @@ import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.web.client.RestTemplate
import org.testcontainers.spock.Testcontainers
import spock.lang.Shared
import spock.lang.Specification
+import spock.util.concurrent.PollingConditions
+
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
@SpringBootTest(classes = [CpsDataspaceService])
@Testcontainers
@@ -75,9 +86,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
SessionManager sessionManager
@Autowired
- RestTemplate restTemplate
-
- @Autowired
NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
@Autowired
@@ -86,6 +94,16 @@ abstract class CpsIntegrationSpecBase extends Specification {
@Autowired
NetworkCmProxyQueryService networkCmProxyQueryService
+ @Autowired
+ RestTemplate restTemplate
+
+ @Autowired
+ ModuleSyncWatchdog moduleSyncWatchdog
+
+ MockRestServiceServer mockDmiServer = null
+
+ static final DMI_URL = 'http://mock-dmi-server'
+
def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
@@ -98,8 +116,19 @@ abstract class CpsIntegrationSpecBase extends Specification {
createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
initialized = true
}
+ mockDmiServer = MockRestServiceServer.createServer(restTemplate)
+ }
+
+ def cleanup() {
+ mockDmiServer.reset()
}
+ def static readResourceDataFile(filename) {
+ return new File('src/test/resources/data/' + filename).text
+ }
+
+ // *** CPS Integration Test Utilities ***
+
def static countDataNodesInTree(DataNode dataNode) {
return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
}
@@ -112,10 +141,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
return nodeCount
}
- def static readResourceDataFile(filename) {
- return new File('src/test/resources/data/' + filename).text
- }
-
def getBookstoreYangResourcesNameToContentMap() {
def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
@@ -158,4 +183,35 @@ abstract class CpsIntegrationSpecBase extends Specification {
return '"' + name + '":[' + innerJson + ']'
}
+ // *** NCMP Integration Test Utilities ***
+
+ def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
+ mockDmiResponsesForRegistration(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ new PollingConditions().within(3, () -> {
+ CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
+ })
+ mockDmiServer.reset()
+ }
+
+ def deregisterCmHandle(dmiPlugin, cmHandleId) {
+ deregisterCmHandles(dmiPlugin, [cmHandleId])
+ }
+
+ def deregisterCmHandles(dmiPlugin, cmHandleIds) {
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
+ }
+
+ def mockDmiResponsesForRegistration(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
+ if (dmiModuleReferencesResponse != null) {
+ mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
+ .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
+ }
+ if (dmiModuleResourcesResponse != null) {
+ mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
+ .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
+ }
+ }
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
new file mode 100644
index 0000000000..4369b799bd
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
@@ -0,0 +1,134 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.integration.functional
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.springframework.http.HttpStatus
+import spock.util.concurrent.PollingConditions
+
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
+
+class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
+
+ NetworkCmProxyDataService objectUnderTest
+
+ static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
+ static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
+ static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
+ static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
+
+ def setup() {
+ objectUnderTest = networkCmProxyDataService
+ }
+
+ def 'CM Handle registration is successful.'() {
+ given: 'DMI will return modules when requested'
+ mockDmiResponsesForRegistration(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+
+ when: 'a CM-handle is registered for creation'
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
+ def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse('ch-1')]
+
+ and: 'CM-handle is initially in ADVISED state'
+ assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
+ })
+
+ and: 'the CM-handle has expected modules'
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
+
+ and: 'DMI received expected requests'
+ mockDmiServer.verify()
+
+ cleanup: 'deregister CM handle'
+ deregisterCmHandle(DMI_URL, 'ch-1')
+ }
+
+ def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
+ given: 'DMI is not available to handle requests'
+ mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
+
+ when: 'a CM-handle is registered for creation'
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+
+ and: 'module sync runs'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED'
+ new PollingConditions().within(3, () -> {
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1')
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED
+ })
+
+ and: 'CM-handle has no modules'
+ assert objectUnderTest.getYangResourcesModuleReferences('ch-1').empty
+
+ cleanup: 'deregister CM handle'
+ deregisterCmHandle(DMI_URL, 'ch-1')
+ }
+
+ def 'Create a CM-handle with existing moduleSetTag.'() {
+ given: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
+ registerCmHandle(DMI_URL, 'ch-1', 'A', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+ registerCmHandle(DMI_URL, 'ch-2', 'B', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
+
+ when: 'a CM-handle is registered for creation with moduleSetTag "B"'
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B')
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate]))
+
+ then: 'the CM-handle goes to READY state after module sync'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState
+ })
+
+ and: 'the CM-handle has expected moduleSetTag'
+ assert objectUnderTest.getNcmpServiceCmHandle('ch-3').moduleSetTag == 'B'
+
+ and: 'the CM-handle has expected modules from module set "B": M1 and M3'
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-3').moduleName.sort()
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2', 'ch-3'])
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy
deleted file mode 100644
index 9cd4d7cbf9..0000000000
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.integration.functional
-
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.onap.cps.spi.exceptions.DataNodeNotFoundException
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.MockRestServiceServer
-import spock.util.concurrent.PollingConditions
-
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
-
-class NcmpCmHandleRegistrationSpec extends CpsIntegrationSpecBase {
-
- NetworkCmProxyDataService objectUnderTest
-
- @Autowired
- ModuleSyncWatchdog moduleSyncWatchdog
-
- static final DMI_URL = 'http://mock-dmi-server'
- def mockDmiServer
- def moduleReferencesResponse
- def moduleResourcesResponse
-
- def setup() {
- objectUnderTest = networkCmProxyDataService
- mockDmiServer = MockRestServiceServer.createServer(restTemplate)
- moduleReferencesResponse = readResourceDataFile('mock-dmi-responses/ietfYangModuleResponse.json')
- moduleResourcesResponse = readResourceDataFile('mock-dmi-responses/ietfYangModuleResourcesResponse.json')
- }
-
- def 'CM Handle is READY when Registration is successful.'() {
- given: 'a CM handle to create'
- def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'cm-1')]
-
- and: 'DMI registration params'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- and: 'DMI returns modules'
- mockDmiServer.expect(requestTo("${DMI_URL}/dmi/v1/ch/cm-1/modules"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(moduleReferencesResponse))
- mockDmiServer.expect(requestTo("${DMI_URL}/dmi/v1/ch/cm-1/moduleResources"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(moduleResourcesResponse))
-
- when: 'a CM-handle is registered'
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'registration gives expected response'
- assert dmiPluginRegistrationResponse.createdCmHandles.size() == 1
-
- and: 'CM-handle is initially in ADVISED state'
- assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('cm-1').cmHandleState
-
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
- assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('cm-1').cmHandleState
- })
-
- and: 'DMI received expected requests'
- mockDmiServer.verify()
- }
-
- def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
- given: 'a CM handle to create'
- def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'cm-2')]
-
- and: 'DMI registration params'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- and: 'DMI returns error code'
- mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
-
- when: 'a CM-handle is registered'
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'registration gives expected response'
- assert dmiPluginRegistrationResponse.createdCmHandles.size() == 1
-
- and: 'CM-handle is initially in ADVISED state'
- assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('cm-2').cmHandleState
-
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to LOCKED state'
- new PollingConditions().within(3, () -> {
- assert CmHandleState.LOCKED == objectUnderTest.getCmHandleCompositeState('cm-2').cmHandleState
- })
-
- and: 'DMI received expected requests'
- mockDmiServer.verify()
- }
-
- def 'Deregister CM-handles.'() {
- given: 'a list of CM handles to remove'
- def cmHandlesToRemove = ['cm-1', 'cm-2']
-
- and: 'DMI registration parameters are set'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, removedCmHandles: cmHandlesToRemove)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- when: 'the CM-handles are deregistered'
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'the CM-handles no longer exists'
- assert !objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier(DMI_URL).contains('cm-1')
- assert !objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier(DMI_URL).contains('cm-2')
- }
-}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
new file mode 100644
index 0000000000..ffa4382d49
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
@@ -0,0 +1,196 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation
+ * ================================================================================
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.integration.functional
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.models.UpgradedCmHandles
+import org.springframework.http.HttpStatus
+import spock.util.concurrent.PollingConditions
+
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
+
+class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
+
+ NetworkCmProxyDataService objectUnderTest
+
+ static final INITIAL_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
+ static final INITIAL_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
+ static final UPDATED_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
+ static final UPDATED_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
+ static final NO_MODULE_SET_TAG = ''
+ static final CM_HANDLE_ID = 'ch-1'
+ static final CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG = 'ch-2'
+
+ def setup() {
+ objectUnderTest = networkCmProxyDataService
+ }
+
+ def 'Upgrade CM-handle with new moduleSetTag or no moduleSetTag.'() {
+ given: 'an existing CM-handle with expected initial modules: M1 and M2'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ and: 'DMI returns different modules for upgrade'
+ mockDmiResponsesForRegistration(DMI_URL, CM_HANDLE_ID, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+
+ when: "CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
+ def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
+
+ and: 'CM-handle is in LOCKED state due to MODULE_UPGRADE'
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE
+ assert cmHandleCompositeState.lockReason.details == "Upgrade to ModuleSetTag: ${updatedModuleSetTag}"
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+ })
+
+ and: 'the CM-handle has expected moduleSetTag'
+ assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
+
+ and: 'CM-handle has expected updated modules: M1 and M3'
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ and: 'DMI received expected requests'
+ mockDmiServer.verify()
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+
+ where:
+ initialModuleSetTag | updatedModuleSetTag
+ NO_MODULE_SET_TAG | NO_MODULE_SET_TAG
+ NO_MODULE_SET_TAG | 'new'
+ 'initial' | NO_MODULE_SET_TAG
+ 'initial' | 'new'
+ }
+
+ def 'Upgrade CM-handle with existing moduleSetTag.'() {
+ given: "an existing CM-handle handle with moduleSetTag '${updatedModuleSetTag}'"
+ registerCmHandle(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG).moduleName.sort()
+ and: "a CM-handle with moduleSetTag '${initialModuleSetTag}' which will be upgraded"
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ when: "CM-handle is upgraded to moduleSetTag '${updatedModuleSetTag}'"
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
+ def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+ })
+
+ and: 'the CM-handle has expected moduleSetTag'
+ assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
+
+ and: 'CM-handle has expected updated modules: M1 and M3'
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandles(DMI_URL, [CM_HANDLE_ID, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG])
+
+ where:
+ initialModuleSetTag | updatedModuleSetTag
+ NO_MODULE_SET_TAG | 'moduleSet2'
+ 'moduleSet1' | 'moduleSet2'
+ }
+
+ def 'Skip upgrade of CM-handle with same moduleSetTag as before.'() {
+ given: 'an existing CM-handle with expected initial modules: M1 and M2'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, 'same', INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ when: 'CM-handle is upgraded with the same moduleSetTag'
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'same')
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ then: 'CM-handle remains in READY state'
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+
+ and: 'the CM-handle has same moduleSetTag as before'
+ assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == 'same'
+
+ then: 'CM-handle has same modules as before: M1 and M2'
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ }
+
+ def 'Upgrade of CM-handle fails due to DMI error.'() {
+ given: 'an existing CM-handle'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, 'oldTag', INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+
+ and: 'DMI returns error code'
+ mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
+
+ when: "CM-handle is upgraded"
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'newTag')
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ and: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED'
+ new PollingConditions().within(3, () -> {
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED
+ })
+
+ and: 'the CM-handle has same moduleSetTag as before'
+ assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == 'oldTag'
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ }
+
+}
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json
new file mode 100644
index 0000000000..5d713914d6
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json
@@ -0,0 +1,12 @@
+[
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01",
+ "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02",
+ "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ }
+] \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json
new file mode 100644
index 0000000000..9f20564f04
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json
@@ -0,0 +1,12 @@
+{
+ "schemas": [
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02"
+ }
+ ]
+} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json
new file mode 100644
index 0000000000..ef9b85f926
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json
@@ -0,0 +1,12 @@
+[
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01",
+ "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ },
+ {
+ "moduleName": "M3",
+ "revision": "2024-01-03",
+ "yangSource": "module M3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-03 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ }
+] \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json
new file mode 100644
index 0000000000..513c749a26
--- /dev/null
+++ b/integration-test/src/test/resources/data/mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json
@@ -0,0 +1,12 @@
+{
+ "schemas": [
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01"
+ },
+ {
+ "moduleName": "M3",
+ "revision": "2024-01-03"
+ }
+ ]
+} \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResourcesResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResourcesResponse.json
deleted file mode 100644
index 4326733f5e..0000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResourcesResponse.json
+++ /dev/null
@@ -1,52 +0,0 @@
-[
- {
- "moduleName": "ietf-yang-types-1",
- "revision": "2013-07-15",
- "yangSource": "module ietf-yang-types-1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-15 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-2",
- "revision": "2013-07-16",
- "yangSource": "module ietf-yang-types-2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-16 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-3",
- "revision": "2013-07-17",
- "yangSource": "module ietf-yang-types-3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-17 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-4",
- "revision": "2013-07-18",
- "yangSource": "module ietf-yang-types-4 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-4\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-18 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-5",
- "revision": "2013-07-19",
- "yangSource": "module ietf-yang-types-5 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-5\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-19 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-6",
- "revision": "2013-07-20",
- "yangSource": "module ietf-yang-types-6 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-6\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-20 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-7",
- "revision": "2013-07-21",
- "yangSource": "module ietf-yang-types-7 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-7\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-21 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-8",
- "revision": "2013-07-22",
- "yangSource": "module ietf-yang-types-8 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-8\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-22 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-9",
- "revision": "2013-07-23",
- "yangSource": "module ietf-yang-types-9 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-9\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-23 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-10",
- "revision": "2013-07-24",
- "yangSource": "module ietf-yang-types-10 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-10\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-24 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResponse.json b/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResponse.json
deleted file mode 100644
index 2cbd8d1313..0000000000
--- a/integration-test/src/test/resources/data/mock-dmi-responses/ietfYangModuleResponse.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "ietf-yang-types-1",
- "revision": "2013-07-15"
- },
- {
- "moduleName": "ietf-yang-types-2",
- "revision": "2013-07-16"
- },
- {
- "moduleName": "ietf-yang-types-3",
- "revision": "2013-07-17"
- },
- {
- "moduleName": "ietf-yang-types-4",
- "revision": "2013-07-18"
- },
- {
- "moduleName": "ietf-yang-types-5",
- "revision": "2013-07-19"
- },
- {
- "moduleName": "ietf-yang-types-6",
- "revision": "2013-07-20"
- },
- {
- "moduleName": "ietf-yang-types-7",
- "revision": "2013-07-21"
- },
- {
- "moduleName": "ietf-yang-types-8",
- "revision": "2013-07-22"
- },
- {
- "moduleName": "ietf-yang-types-9",
- "revision": "2013-07-23"
- },
- {
- "moduleName": "ietf-yang-types-10",
- "revision": "2013-07-24"
- }
- ]
-} \ No newline at end of file