Allow separate registration of DMIDataPlugin and DmiModelPugin
Moved relevant code from NetworkCmProxyDataServiceImp to DmiOperations
Split DmiOperations into DMiData... and DMIModelOperations
Merged update-operation changes
Added tests for error message validation in NetworkCmProxyDataServiceImplSpec
Removede @Service from DMIOperations and added @component to
DmiDataOperations & DmiModelOperations
Verify sync robot test is now hardened
Added exitonfailure so robot tests stop after first encountered failed
test
Issue-ID: CPS-736
Change-Id: I0b40931cc8cd4fc0452328a0a7e0f60e6fc38d0a
Signed-off-by: JosephKeenan <joseph.keenan@est.tech>
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
index 45d5bd9..ec816ed 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
@@ -22,8 +22,9 @@
package org.onap.cps.ncmp.api;
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
+
import java.util.Collection;
-import javax.validation.constraints.NotNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
import org.onap.cps.spi.FetchDescendantsOption;
@@ -118,8 +119,8 @@
* @param optionsParamInQuery options query
* @return {@code Object} resource data
*/
- Object getResourceDataOperationalForCmHandle(@NotNull String cmHandle,
- @NotNull String resourceIdentifier,
+ Object getResourceDataOperationalForCmHandle(String cmHandle,
+ String resourceIdentifier,
String acceptParamInHeader,
String optionsParamInQuery);
@@ -133,24 +134,25 @@
* @param optionsParamInQuery options query
* @return {@code Object} resource data
*/
- Object getResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle,
- @NotNull String resourceIdentifier,
+ Object getResourceDataPassThroughRunningForCmHandle(String cmHandle,
+ String resourceIdentifier,
String acceptParamInHeader,
String optionsParamInQuery);
/**
- * Create resource data for data store pass-through running
+ * Write resource data for data store pass-through running
* using dmi for given cm-handle.
- *
- * @param cmHandle cm handle
+ * @param cmHandle cm handle
* @param resourceIdentifier resource identifier
+ * @param operation required operation
* @param requestBody request body to create resource
* @param contentType content type in body
*/
- void createResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle,
- @NotNull String resourceIdentifier,
- @NotNull String requestBody,
- String contentType);
+ void writeResourceDataPassThroughRunningForCmHandle(String cmHandle,
+ String resourceIdentifier,
+ OperationEnum operation,
+ String requestBody,
+ String contentType);
/**
* Retrieve module references for the given cm handle.
@@ -158,7 +160,7 @@
* @param cmHandle cm handle
* @return a collection of modules names and revisions
*/
- Collection<ModuleReference> getYangResourcesModuleReferences(@NotNull String cmHandle);
+ Collection<ModuleReference> getYangResourcesModuleReferences(String cmHandle);
/**
* Query cm handle identifiers for the given collection of module names.
@@ -169,14 +171,4 @@
*/
Collection<String> executeCmHandleHasAllModulesSearch(Collection<String> moduleNames);
- /**
- * Update resource data for data store pass-through running using dmi for the given cm-handle.
- *
- * @param cmHandle cm handle
- * @param resourceIdentifier resource identifier
- * @param requestBody request body to create resource
- * @param contentType content type in body
- */
- void updateResourceDataPassThroughRunningForCmHandle(String cmHandle, String resourceIdentifier,
- String requestBody, String contentType);
}
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 80cd297..fb929a2 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
@@ -23,6 +23,8 @@
package org.onap.cps.ncmp.api.impl;
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
+
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
@@ -32,12 +34,9 @@
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsAdminService;
import org.onap.cps.api.CpsDataService;
@@ -45,13 +44,12 @@
import org.onap.cps.api.CpsQueryService;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
import org.onap.cps.ncmp.api.impl.exception.NcmpException;
-import org.onap.cps.ncmp.api.impl.operation.DmiOperations;
+import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
+import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
+import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
import org.onap.cps.ncmp.api.models.CmHandle;
import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.ncmp.api.models.GenericRequestBody;
-import org.onap.cps.ncmp.api.models.GenericRequestBody.OperationEnum;
import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
-import org.onap.cps.ncmp.api.models.PersistenceCmHandle.AdditionalProperty;
import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
import org.onap.cps.ncmp.api.models.YangResource;
import org.onap.cps.spi.FetchDescendantsOption;
@@ -59,7 +57,6 @@
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
-import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -76,17 +73,15 @@
private static final OffsetDateTime NO_TIMESTAMP = null;
- private static final String NCMP_DMI_SERVICE_NAME = "dmi-service-name";
-
- private static final String REVISION = "revision";
-
private CpsDataService cpsDataService;
private ObjectMapper objectMapper;
private CpsQueryService cpsQueryService;
- private DmiOperations dmiOperations;
+ private DmiDataOperations dmiDataOperations;
+
+ private DmiModelOperations dmiModelOperations;
private CpsModuleService cpsModuleService;
@@ -94,18 +89,20 @@
/**
* Constructor Injection for Dependencies.
- * @param dmiOperations DMI operation
+ * @param dmiDataOperations DMI operation
* @param cpsDataService Data Service Interface
* @param cpsQueryService Query Service Interface
* @param objectMapper Object Mapper
*/
- public NetworkCmProxyDataServiceImpl(final DmiOperations dmiOperations,
- final CpsModuleService cpsModuleService,
- final CpsDataService cpsDataService,
- final CpsQueryService cpsQueryService,
- final CpsAdminService cpsAdminService,
- final ObjectMapper objectMapper) {
- this.dmiOperations = dmiOperations;
+ public NetworkCmProxyDataServiceImpl(final DmiDataOperations dmiDataOperations,
+ final DmiModelOperations dmiModelOperations,
+ final CpsModuleService cpsModuleService,
+ final CpsDataService cpsDataService,
+ final CpsQueryService cpsQueryService,
+ final CpsAdminService cpsAdminService,
+ final ObjectMapper objectMapper) {
+ this.dmiDataOperations = dmiDataOperations;
+ this.dmiModelOperations = dmiModelOperations;
this.cpsModuleService = cpsModuleService;
this.cpsDataService = cpsDataService;
this.cpsQueryService = cpsQueryService;
@@ -158,9 +155,10 @@
@Override
public void updateDmiRegistrationAndSyncModule(final DmiPluginRegistration dmiPluginRegistration) {
+ dmiPluginRegistration.validateDmiPluginRegistration();
try {
if (dmiPluginRegistration.getCreatedCmHandles() != null) {
- parseAndCreateCmHandlesInDmiRegistrationAndSyncModule(dmiPluginRegistration);
+ parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration);
}
if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
@@ -174,64 +172,44 @@
}
@Override
- public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle,
- final @NotNull String resourceIdentifier,
+ public Object getResourceDataOperationalForCmHandle(final String cmHandle,
+ final String resourceIdentifier,
final String acceptParamInHeader,
final String optionsParamInQuery) {
-
- final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
- final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
- final String dmiRequestBody = getGenericRequestBody(cmHandleDataNode);
- final ResponseEntity<Object> response = dmiOperations.getResourceDataOperationalFromDmi(dmiServiceName,
- cmHandle,
- resourceIdentifier,
- optionsParamInQuery,
- acceptParamInHeader,
- dmiRequestBody);
- return handleResponse(response);
+ return handleResponse(dmiDataOperations.getResourceDataFromDmi(
+ cmHandle,
+ resourceIdentifier,
+ optionsParamInQuery,
+ acceptParamInHeader,
+ DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL), "Not able to get resource data.");
}
@Override
- public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
- final @NotNull String resourceIdentifier,
+ public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandle,
+ final String resourceIdentifier,
final String acceptParamInHeader,
final String optionsParamInQuery) {
- final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
- final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
- final String dmiRequestBody = getGenericRequestBody(cmHandleDataNode);
- final ResponseEntity<Object> response = dmiOperations.getResourceDataPassThroughRunningFromDmi(dmiServiceName,
- cmHandle,
- resourceIdentifier,
- optionsParamInQuery,
- acceptParamInHeader,
- dmiRequestBody);
- return handleResponse(response);
+ return handleResponse(dmiDataOperations.getResourceDataFromDmi(
+ cmHandle,
+ resourceIdentifier,
+ optionsParamInQuery,
+ acceptParamInHeader,
+ DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING), "Not able to get resource data.");
}
@Override
- public void createResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
- final @NotNull String resourceIdentifier,
- final @NotNull String requestBody,
- final String contentType) {
- final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
- final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
- final Collection<DataNode> cmHandlePropertiesAsDataNodes = cmHandleDataNode.getChildDataNodes();
- final Map<String, String> cmHandlePropertiesAsMap = getCmHandlePropertiesAsMap(cmHandlePropertiesAsDataNodes);
- final GenericRequestBody dmiRequestBodyObject = GenericRequestBody.builder()
- .operation(GenericRequestBody.OperationEnum.CREATE)
- .dataType(contentType)
- .data(requestBody)
- .cmHandleProperties(cmHandlePropertiesAsMap)
- .build();
- final String dmiRequestBody = prepareOperationBody(dmiRequestBodyObject);
- final ResponseEntity<String> responseEntity = dmiOperations
- .createResourceDataPassThroughRunningFromDmi(dmiServiceName,
- cmHandle,
- resourceIdentifier,
- dmiRequestBody);
- handleResponseFromDmi(responseEntity, "Not able to create resource data.");
+ public void writeResourceDataPassThroughRunningForCmHandle(final String cmHandle,
+ final String resourceIdentifier,
+ final OperationEnum operation,
+ final String requestData,
+ final String dataType) {
+ handleResponse(
+ dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(
+ cmHandle, resourceIdentifier, operation, requestData, dataType),
+ "Not able to " + operation + " resource data.");
}
+
@Override
public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandle) {
return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle);
@@ -249,134 +227,46 @@
}
/**
- * Update resource data for data store pass-through running using dmi for given cm-handle.
+ * THis method registers a cm handle and intiates modules sync.
*
- * @param cmHandle cm handle
- * @param resourceIdentifier resource identifier
- * @param requestBody request body to create resource
- * @param contentType content type in body
+ * @param dmiPluginRegistration dmi plugin registration information.
+ * @throws JsonProcessingException thrown if json is malformed or missing.
*/
- @Override
- public void updateResourceDataPassThroughRunningForCmHandle(final String cmHandle, final String resourceIdentifier,
- final String requestBody, final String contentType) {
- final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
- final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
- final Collection<DataNode> cmHandlePropertiesAsDataNodes = cmHandleDataNode.getChildDataNodes();
- final Map<String, String> cmHandlePropertiesAsMap = getCmHandlePropertiesAsMap(cmHandlePropertiesAsDataNodes);
- final GenericRequestBody dmiRequestBodyObject = GenericRequestBody.builder()
- .operation(OperationEnum.UPDATE)
- .dataType(contentType)
- .data(requestBody)
- .cmHandleProperties(cmHandlePropertiesAsMap)
- .build();
- final String dmiRequestBody = prepareOperationBody(dmiRequestBodyObject);
- final ResponseEntity<String> responseEntity = dmiOperations
- .updateResourceDataPassThroughRunningFromDmi(dmiServiceName,
- cmHandle,
- resourceIdentifier,
- dmiRequestBody);
- handleResponseFromDmi(responseEntity, "Unable to replace resource data.");
+ public void parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
+ final DmiPluginRegistration dmiPluginRegistration) throws JsonProcessingException {
+ final PersistenceCmHandlesList createdPersistenceCmHandlesList =
+ getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getCreatedCmHandles());
+ registerAndSyncNewCmHandles(createdPersistenceCmHandlesList);
}
- private DataNode fetchDataNodeFromDmiRegistryForCmHandle(final String cmHandle) {
- final String xpathForDmiRegistryToFetchCmHandle = "/dmi-registry/cm-handles[@id='" + cmHandle + "']";
- return cpsDataService.getDataNode(NCMP_DATASPACE_NAME,
- NCMP_DMI_REGISTRY_ANCHOR,
- xpathForDmiRegistryToFetchCmHandle,
- FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
- }
-
- private String prepareOperationBody(final GenericRequestBody requestBodyObject) {
- try {
- return objectMapper.writeValueAsString(requestBodyObject);
- } catch (final JsonProcessingException e) {
- log.error("Parsing error occurred while converting Object to JSON.");
- throw new NcmpException("Parsing error occurred while converting given object to JSON.",
- e.getMessage());
- }
- }
-
- private static Map<String, String> getCmHandlePropertiesAsMap(
- final Collection<DataNode> cmHandlePropertiesAsDataNode) {
- if (cmHandlePropertiesAsDataNode.isEmpty()) {
- return Collections.emptyMap();
- }
- final Map<String, String> cmHandlePropertiesAsMap = new LinkedHashMap<>();
- for (final DataNode dataNode: cmHandlePropertiesAsDataNode) {
- cmHandlePropertiesAsMap.put(String.valueOf(dataNode.getLeaves().get("name")),
- String.valueOf(dataNode.getLeaves().get("value")));
- }
- return cmHandlePropertiesAsMap;
- }
-
- private static Map<String, String> getCmHandlePropertiesAsMap(
- final List<AdditionalProperty> cmHandlePropertiesAsList) {
- if (cmHandlePropertiesAsList == null || cmHandlePropertiesAsList.isEmpty()) {
- return Collections.emptyMap();
- }
- final Map<String, String> cmHandlePropertiesAsMap = new LinkedHashMap<>();
- for (final AdditionalProperty additionalProperty: cmHandlePropertiesAsList) {
- cmHandlePropertiesAsMap.put(additionalProperty.getName(),
- additionalProperty.getValue());
- }
- return cmHandlePropertiesAsMap;
- }
-
- private static Object handleResponse(final @NotNull ResponseEntity<Object> responseEntity) {
- if (responseEntity.getStatusCode() == HttpStatus.OK) {
+ private static Object handleResponse(final ResponseEntity<?> responseEntity,
+ final String exceptionMessage) {
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody();
} else {
- throw new NcmpException("Not able to get resource data.",
+ throw new NcmpException(exceptionMessage,
"DMI status code: " + responseEntity.getStatusCodeValue()
+ ", DMI response body: " + responseEntity.getBody());
}
}
- private static void handleResponseFromDmi(final @NotNull ResponseEntity<String> responseEntity,
- final String exceptionMessage) {
- if (!HttpStatus.valueOf(responseEntity.getStatusCodeValue()).is2xxSuccessful()) {
- throw new NcmpException(exceptionMessage,
- "DMI status code: " + responseEntity.getStatusCodeValue()
- + ", DMI response body: " + responseEntity.getBody());
- }
- }
-
- private String getGenericRequestBody(final DataNode cmHandleDataNode) {
- final Collection<DataNode> cmHandlePropertiesAsDataNodes = cmHandleDataNode.getChildDataNodes();
- final Map<String, String> cmHandlePropertiesAsMap = getCmHandlePropertiesAsMap(cmHandlePropertiesAsDataNodes);
- final GenericRequestBody requestBodyObject = GenericRequestBody.builder()
- .operation(GenericRequestBody.OperationEnum.READ)
- .cmHandleProperties(cmHandlePropertiesAsMap)
- .build();
- return prepareOperationBody(requestBodyObject);
- }
-
private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration)
throws JsonProcessingException {
- final PersistenceCmHandlesList updatedPersistenceCmHandlesList = toPersistenceCmHandlesList(
- dmiPluginRegistration.getDmiPlugin(),
- dmiPluginRegistration.getUpdatedCmHandles());
+ final PersistenceCmHandlesList updatedPersistenceCmHandlesList =
+ getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getUpdatedCmHandles());
final String cmHandlesAsJson = objectMapper.writeValueAsString(updatedPersistenceCmHandlesList);
cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
"/dmi-registry", cmHandlesAsJson, NO_TIMESTAMP);
}
- private void parseAndCreateCmHandlesInDmiRegistrationAndSyncModule(
- final DmiPluginRegistration dmiPluginRegistration) throws JsonProcessingException {
- final PersistenceCmHandlesList createdPersistenceCmHandlesList = toPersistenceCmHandlesList(
+ private PersistenceCmHandlesList getUpdatedPersistenceCmHandlesList(
+ final DmiPluginRegistration dmiPluginRegistration,
+ final List<CmHandle> updatedCmHandles) {
+ return PersistenceCmHandlesList.toPersistenceCmHandlesList(
dmiPluginRegistration.getDmiPlugin(),
- dmiPluginRegistration.getCreatedCmHandles());
- registerAndSyncNewCmHandles(createdPersistenceCmHandlesList);
- }
-
- private static PersistenceCmHandlesList toPersistenceCmHandlesList(final String dmiPlugin,
- final Collection<CmHandle> cmHandles) {
- final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
- for (final CmHandle cmHandle : cmHandles) {
- final PersistenceCmHandle persistenceCmHandle = toPersistenceCmHandle(dmiPlugin, cmHandle);
- persistenceCmHandlesList.add(persistenceCmHandle);
- }
- return persistenceCmHandlesList;
+ dmiPluginRegistration.getDmiDataPlugin(),
+ dmiPluginRegistration.getDmiModelPlugin(),
+ updatedCmHandles);
}
private static void handleJsonProcessingException(final DmiPluginRegistration dmiPluginRegistration,
@@ -403,19 +293,6 @@
createAnchor(persistenceCmHandle);
}
- private static PersistenceCmHandle toPersistenceCmHandle(final String dmiPluginService,
- final CmHandle cmHandle) {
- final PersistenceCmHandle persistenceCmHandle = new PersistenceCmHandle();
- persistenceCmHandle.setDmiServiceName(dmiPluginService);
- persistenceCmHandle.setId(cmHandle.getCmHandleID());
- if (cmHandle.getCmHandleProperties() == null) {
- persistenceCmHandle.setAdditionalProperties(Collections.emptyMap());
- } else {
- persistenceCmHandle.setAdditionalProperties(cmHandle.getCmHandleProperties());
- }
- return persistenceCmHandle;
- }
-
private void parseAndRemoveCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
for (final String cmHandle : dmiPluginRegistration.getRemovedCmHandles()) {
try {
@@ -428,11 +305,9 @@
}
private void fetchAndSyncModules(final PersistenceCmHandle persistenceCmHandle) {
- final Map<String, String> cmHandlePropertiesAsMap = getCmHandlePropertiesAsMap(
- persistenceCmHandle.getAdditionalProperties());
final List<ModuleReference> moduleReferencesFromCmHandle =
- fetchModuleReferencesFromDmi(persistenceCmHandle, cmHandlePropertiesAsMap);
+ toModuleReferences(dmiModelOperations.getModuleReferences(persistenceCmHandle));
final List<ModuleReference> existingModuleReferences = new ArrayList<>();
final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
@@ -442,7 +317,7 @@
newYangResourcesModuleNameToContentMap = new HashMap<>();
} else {
newYangResourcesModuleNameToContentMap = getNewYangResourcesFromDmi(persistenceCmHandle,
- unknownModuleReferences, cmHandlePropertiesAsMap);
+ unknownModuleReferences);
}
cpsModuleService
.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
@@ -465,60 +340,17 @@
}
}
- private List<ModuleReference> fetchModuleReferencesFromDmi(final PersistenceCmHandle persistenceCmHandle,
- final Map<String, String> cmHandlePropertiesAsMap) {
- final GenericRequestBody genericRequestBody = GenericRequestBody.builder()
- .cmHandleProperties(cmHandlePropertiesAsMap)
- .build();
- final String jsonBodyWithOnlyCmHandleProperties = prepareOperationBody(genericRequestBody);
- final ResponseEntity<String> dmiFetchModulesResponseEntity =
- dmiOperations.getResourceFromDmiWithJsonData(persistenceCmHandle.getDmiServiceName(),
- jsonBodyWithOnlyCmHandleProperties, persistenceCmHandle.getId(), "modules");
- return toModuleReferences(dmiFetchModulesResponseEntity);
- }
-
private void createAnchor(final PersistenceCmHandle persistenceCmHandle) {
cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
persistenceCmHandle.getId());
}
- private String getRequestBodyToFetchYangResourceFromDmi(final List<ModuleReference> unknownModuleReferences,
- final Map<String, String> cmHandlePropertiesAsMap) {
- final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(unknownModuleReferences);
- final JsonObject data = new JsonObject();
- data.add("modules", moduleReferencesAsJson);
- final JsonObject jsonRequestObject = new JsonObject();
- jsonRequestObject.add("data", data);
- final Gson gson = new Gson();
- jsonRequestObject.add("cmHandleProperties", gson.toJsonTree(cmHandlePropertiesAsMap));
- return jsonRequestObject.toString();
- }
-
- private static JsonArray getModuleReferencesAsJson(final List<ModuleReference> unknownModuleReferences) {
- final JsonArray moduleReferences = new JsonArray();
-
- for (final ModuleReference moduleReference : unknownModuleReferences) {
- final JsonObject moduleReferenceAsJson = new JsonObject();
- moduleReferenceAsJson.addProperty("name", moduleReference.getModuleName());
- moduleReferenceAsJson.addProperty(REVISION, moduleReference.getRevision());
- moduleReferences.add(moduleReferenceAsJson);
- }
- return moduleReferences;
- }
-
private Map<String, String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
- final List<ModuleReference> unknownModuleReferences,
- final Map<String, String> cmHandlePropertiesAsMap) {
- final String jsonDataWithDataAndCmHandleProperties = getRequestBodyToFetchYangResourceFromDmi(
- unknownModuleReferences, cmHandlePropertiesAsMap);
+ final List<ModuleReference> unknownModuleReferences) {
+ final ResponseEntity<String> responseEntity =
+ dmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences);
- final ResponseEntity<String> moduleResourcesAsJsonString = dmiOperations.getResourceFromDmiWithJsonData(
- persistenceCmHandle.getDmiServiceName(),
- jsonDataWithDataAndCmHandleProperties,
- persistenceCmHandle.getId(),
- "moduleResources");
-
- final JsonArray moduleResources = new Gson().fromJson(moduleResourcesAsJsonString.getBody(),
+ final JsonArray moduleResources = new Gson().fromJson(responseEntity.getBody(),
JsonArray.class);
final Map<String, String> newYangResourcesModuleNameToContentMap = new HashMap<>();
@@ -532,7 +364,7 @@
private static YangResource toYangResource(final JsonObject yangResourceAsJson) {
final YangResource yangResource = new YangResource();
yangResource.setModuleName(yangResourceAsJson.get("moduleName").getAsString());
- yangResource.setRevision(yangResourceAsJson.get(REVISION).getAsString());
+ yangResource.setRevision(yangResourceAsJson.get("revision").getAsString());
final String yangSourceJson = yangResourceAsJson.get("yangSource").getAsString();
String yangSource = JsonUtils.removeWrappingTokens(yangSourceJson);
@@ -558,7 +390,7 @@
private static ModuleReference toModuleReference(final JsonObject moduleReferenceAsJson) {
final ModuleReference moduleReference = new ModuleReference();
moduleReference.setModuleName(moduleReferenceAsJson.get("moduleName").getAsString());
- moduleReference.setRevision(moduleReferenceAsJson.get(REVISION).getAsString());
+ moduleReference.setRevision(moduleReferenceAsJson.get("revision").getAsString());
return moduleReference;
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
index fc70708..62eca94 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
@@ -35,13 +35,28 @@
private RestTemplate restTemplate;
private DmiProperties dmiProperties;
+ /**
+ * Constructor injection for DmiRestClient objects.
+ *
+ * @param restTemplate the rest template
+ * @param dmiProperties the DMI properties
+ */
public DmiRestClient(final RestTemplate restTemplate, final DmiProperties dmiProperties) {
this.restTemplate = restTemplate;
this.dmiProperties = dmiProperties;
}
+ /**
+ * Sends a PUT operation to DMI with JSON payload.
+ *
+ * @param dmiResourceUrl the DMI resource URL
+ * @param jsonData the JSON payload
+ * @param headers the HTTP headers
+ * @return response entity of type Object
+ */
public ResponseEntity<Object> putOperationWithJsonData(final String dmiResourceUrl,
final String jsonData, final HttpHeaders headers) {
+ //TODO Toine Siebelink, should we use POST operation below instead (and return a String-Entity!)
final var httpEntity = new HttpEntity<>(jsonData, configureHttpHeaders(headers));
return restTemplate.exchange(dmiResourceUrl, HttpMethod.PUT, httpEntity, Object.class);
}
@@ -76,4 +91,4 @@
final var httpEntity = new HttpEntity<>(configureHttpHeaders(httpHeaders));
return restTemplate.exchange(dmiResourceUrl, HttpMethod.POST, httpEntity, String.class);
}
-}
\ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
index c4e82d3..81c9dff 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
@@ -38,6 +38,8 @@
private String authUsername;
@Value("${dmi.auth.password}")
private String authPassword;
+ @Value("${dmi.api.base-path}")
+ private String dmiBasePath;
}
@Bean
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operation/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operation/DmiOperations.java
deleted file mode 100644
index 40a47ec..0000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operation/DmiOperations.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 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.operation;
-
-import com.fasterxml.jackson.annotation.JsonValue;
-import lombok.Getter;
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-
-@Component
-public class DmiOperations {
- @Getter
- public enum DataStoreEnum {
- PASSTHROUGH_OPERATIONAL("ncmp-datastore:passthrough-operational"),
- PASSTHROUGH_RUNNING("ncmp-datastore:passthrough-running");
- private String value;
-
- DataStoreEnum(final String value) {
- this.value = value;
- }
-
- @Override
- @JsonValue
- public String toString() {
- return value;
- }
- }
-
- private DmiRestClient dmiRestClient;
- private static final String DMI_API_PATH = "/dmi";
- private static final String DMI_CM_HANDLE_PATH = "/v1/ch/{cmHandle}";
- private static final String DMI_CM_HANDLE_DATASTORE_PATH = DMI_CM_HANDLE_PATH + "/data/ds";
- private static final String URL_SEPARATOR = "/";
- private static final String RESOURCE_IDENTIFIER = "resourceIdentifier";
- private static final String OPTIONS_QUERY_KEY = "options";
-
-
- /**
- * Constructor for {@code DmiOperations}. This method also manipulates url properties.
- *
- * @param dmiRestClient {@code DmiRestClient}
- */
- public DmiOperations(final DmiRestClient dmiRestClient) {
- this.dmiRestClient = dmiRestClient;
- }
-
- /**
- * Get resources from DMI.
- *
- * @param dmiServiceName dmi service name
- * @param cmHandle cmHandle
- * @param resourceName name of the resource(s)
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<String> getResourceFromDmi(final String dmiServiceName,
- final String cmHandle,
- final String resourceName) {
- final var dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName);
- final var httpHeaders = new HttpHeaders();
- return dmiRestClient.postOperation(dmiResourceDataUrl, httpHeaders);
- }
-
- /**
- * Get resources from DMI for modules.
- *
- * @param dmiServiceName dmi service name
- * @param jsonData module names and revisions as JSON
- * @param cmHandle cmHandle
- * @param resourceName name of the resource(s)
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<String> getResourceFromDmiWithJsonData(final String dmiServiceName,
- final String jsonData,
- final String cmHandle,
- final String resourceName) {
- final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName);
- return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonData, new HttpHeaders());
- }
-
- /**
- * This method fetches the resource data from operational data store for given cm handle
- * identifier on given resource using dmi client.
- *
- * @param dmiServiceName dmi service name
- * @param cmHandle network resource identifier
- * @param resourceId resource identifier
- * @param optionsParamInQuery options query
- * @param acceptParamInHeader accept parameter
- * @param jsonBody json body for put operation
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<Object> getResourceDataOperationalFromDmi(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final String optionsParamInQuery,
- final String acceptParamInHeader,
- final String jsonBody) {
- final var dmiResourceDataUrl = getDmiDatastoreUrl(dmiServiceName, cmHandle, resourceId,
- optionsParamInQuery, DataStoreEnum.PASSTHROUGH_OPERATIONAL);
- final var httpHeaders = prepareHeader(acceptParamInHeader);
- return dmiRestClient.putOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders);
- }
-
- /**
- * This method fetches the resource data from pass-through running data store for given cm handle
- * identifier on given resource using dmi client.
- *
- * @param dmiServiceName dmi service name
- * @param cmHandle network resource identifier
- * @param resourceId resource identifier
- * @param optionsParamInQuery fields query
- * @param acceptParamInHeader accept parameter
- * @param jsonBody json body for put operation
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<Object> getResourceDataPassThroughRunningFromDmi(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final String optionsParamInQuery,
- final String acceptParamInHeader,
- final String jsonBody) {
- final var dmiResourceDataUrl = getDmiDatastoreUrl(dmiServiceName, cmHandle, resourceId,
- optionsParamInQuery, DataStoreEnum.PASSTHROUGH_RUNNING);
- final var httpHeaders = prepareHeader(acceptParamInHeader);
- return dmiRestClient.putOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders);
- }
-
- /**
- * This method creates the resource data from pass-through running data store for given cm handle
- * identifier on given resource using dmi client.
- *
- * @param dmiServiceName dmi service name
- * @param cmHandle network resource identifier
- * @param resourceId resource identifier
- * @param jsonBody json body for put operation
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<String> createResourceDataPassThroughRunningFromDmi(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final String jsonBody) {
- final var stringBuilder = getStringBuilderForPassThroughUrl(dmiServiceName,
- cmHandle, resourceId, DataStoreEnum.PASSTHROUGH_RUNNING);
- return dmiRestClient.postOperationWithJsonData(stringBuilder.toString(), jsonBody, new HttpHeaders());
- }
-
- private String getDmiResourceUrl(final String dmiServiceName,
- final String cmHandle,
- final String resourceName) {
- final var stringBuilder = new StringBuilder(dmiServiceName);
- stringBuilder.append(DMI_API_PATH);
- stringBuilder.append(DMI_CM_HANDLE_PATH.replace("{cmHandle}", cmHandle));
- stringBuilder.append(URL_SEPARATOR + resourceName);
- return stringBuilder.toString();
- }
-
- /**
- * This method updates the resource data from pass-through running data store for the cm handle identifier on given
- * resource using dmi client.
- *
- * @param dmiServiceName dmi service name
- * @param cmHandle network resource identifier
- * @param resourceId resource identifier
- * @param jsonBody json body for put operation
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<String> updateResourceDataPassThroughRunningFromDmi(final String dmiServiceName,
- final String cmHandle, final String resourceId, final String jsonBody) {
- final StringBuilder stringBuilder =
- getStringBuilderForPassThroughUrl(dmiServiceName, cmHandle, resourceId, DataStoreEnum.PASSTHROUGH_RUNNING);
- return dmiRestClient.postOperationWithJsonData(stringBuilder.toString(), jsonBody, new HttpHeaders());
- }
-
- private String getDmiDatastoreUrl(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final String optionsParamInQuery,
- final DataStoreEnum dataStoreEnum) {
- final var stringBuilder = getStringBuilderForPassThroughUrl(dmiServiceName,
- cmHandle, resourceId, dataStoreEnum);
- appendOptionsQuery(stringBuilder, optionsParamInQuery);
- return stringBuilder.toString();
- }
-
- private StringBuilder getStringBuilderForPassThroughUrl(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final DataStoreEnum dataStoreEnum) {
- final var stringBuilder = new StringBuilder(dmiServiceName);
- stringBuilder.append(DMI_API_PATH);
- stringBuilder.append(DMI_CM_HANDLE_DATASTORE_PATH.replace("{cmHandle}", cmHandle));
- stringBuilder.append(URL_SEPARATOR + dataStoreEnum.getValue());
- stringBuilder.append("?" + RESOURCE_IDENTIFIER + "=" + resourceId);
- return stringBuilder;
- }
-
- private void appendOptionsQuery(final StringBuilder stringBuilder,
- final String optionsParamInQuery) {
- if (optionsParamInQuery != null) {
- stringBuilder.append("&").append(OPTIONS_QUERY_KEY).append("=").append(optionsParamInQuery);
- }
- }
-
- private HttpHeaders prepareHeader(final String acceptParam) {
- final var httpHeaders = new HttpHeaders();
- httpHeaders.set(HttpHeaders.ACCEPT, acceptParam);
- return httpHeaders;
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
new file mode 100644
index 0000000..b833645
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -0,0 +1,140 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING;
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ;
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+/**
+ * Operations class for DMI data.
+ */
+@Component
+public class DmiDataOperations extends DmiOperations {
+
+ /**
+ * Constructor for {@code DmiOperations}. This method also manipulates url properties.
+ *
+ * @param dmiRestClient {@code DmiRestClient}
+ */
+ public DmiDataOperations(final PersistenceCmHandleRetriever cmHandlePropertiesRetriever,
+ final ObjectMapper objectMapper,
+ final NcmpConfiguration.DmiProperties dmiProperties,
+ final DmiRestClient dmiRestClient) {
+ super(cmHandlePropertiesRetriever, objectMapper, dmiProperties, dmiRestClient);
+ }
+
+ /**
+ * This method fetches the resource data from operational data store for given cm handle
+ * identifier on given resource using dmi client.
+ *
+ * @param cmHandle network resource identifier
+ * @param resourceId resource identifier
+ * @param optionsParamInQuery options query
+ * @param acceptParamInHeader accept parameter
+ * @param dataStore data store enum
+ * @return {@code ResponseEntity} response entity
+ */
+ public ResponseEntity<Object> getResourceDataFromDmi(final String cmHandle,
+ final String resourceId,
+ final String optionsParamInQuery,
+ final String acceptParamInHeader,
+ final DataStoreEnum dataStore) {
+ final PersistenceCmHandle persistenceCmHandle =
+ cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandle);
+ final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
+ .operation(READ)
+ .build();
+ dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+ final String jsonBody = getDmiRequestBodyAsString(dmiRequestBody);
+
+ final var dmiResourceDataUrl = getDmiDatastoreUrlWithOptions(
+ persistenceCmHandle.resolveDmiServiceName(DATA), cmHandle, resourceId,
+ optionsParamInQuery, dataStore);
+ final var httpHeaders = prepareHeader(acceptParamInHeader);
+ return dmiRestClient.putOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders);
+ }
+
+ /**
+ * This method creates the resource data from pass-through running data store for given cm handle
+ * identifier on given resource using dmi client.
+ *
+ * @param cmHandle network resource identifier
+ * @param resourceId resource identifier
+ * @param operation operation enum
+ * @param requestData the request data
+ * @param dataType data type
+ * @return {@code ResponseEntity} response entity
+ */
+ public ResponseEntity<String> writeResourceDataPassThroughRunningFromDmi(final String cmHandle,
+ final String resourceId,
+ final OperationEnum operation,
+ final String requestData,
+ final String dataType) {
+ final PersistenceCmHandle persistenceCmHandle =
+ cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandle);
+ final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
+ .operation(operation)
+ .data(requestData)
+ .dataType(dataType)
+ .build();
+ dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+ final String jsonBody = getDmiRequestBodyAsString(dmiRequestBody);
+ final String dmiUrl =
+ getResourceInDataStoreUrl(persistenceCmHandle.resolveDmiServiceName(DATA),
+ cmHandle, resourceId, PASSTHROUGH_RUNNING);
+ return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonBody, new HttpHeaders());
+ }
+
+ private String getResourceInDataStoreUrl(final String dmiServiceName,
+ final String cmHandle,
+ final String resourceId,
+ final DataStoreEnum dataStoreEnum) {
+ return getCmHandleUrl(dmiServiceName, cmHandle)
+ + "data"
+ + URL_SEPARATOR
+ + "ds"
+ + URL_SEPARATOR
+ + dataStoreEnum.getValue()
+ + "?resourceIdentifier="
+ + resourceId;
+ }
+
+ private String getDmiDatastoreUrlWithOptions(final String dmiServiceName,
+ final String cmHandle,
+ final String resourceId,
+ final String optionsParamInQuery,
+ final DataStoreEnum dataStoreEnum) {
+ final String resourceInDataStoreUrl = getResourceInDataStoreUrl(dmiServiceName,
+ cmHandle, resourceId, dataStoreEnum);
+ return appendOptionsQuery(resourceInDataStoreUrl, optionsParamInQuery);
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
new file mode 100644
index 0000000..c582584
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
@@ -0,0 +1,133 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.List;
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
+import org.onap.cps.spi.model.ModuleReference;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DmiModelOperations extends DmiOperations {
+
+ /**
+ * Constructor for {@code DmiOperations}. This method also manipulates url properties.
+ *
+ * @param dmiRestClient {@code DmiRestClient}
+ */
+ public DmiModelOperations(final PersistenceCmHandleRetriever cmHandlePropertiesRetriever,
+ final ObjectMapper objectMapper,
+ final NcmpConfiguration.DmiProperties dmiProperties,
+ final DmiRestClient dmiRestClient) {
+ super(cmHandlePropertiesRetriever, objectMapper, dmiProperties, dmiRestClient);
+ }
+
+ /**
+ * Retrieves module references.
+ *
+ * @param persistenceCmHandle the persistence cm handle
+ * @return module references
+ */
+ public ResponseEntity<String> getModuleReferences(final PersistenceCmHandle persistenceCmHandle) {
+ final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
+ .build();
+ dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+ return getResourceFromDmiWithJsonData(persistenceCmHandle.resolveDmiServiceName(MODEL),
+ getDmiRequestBodyAsString(dmiRequestBody), persistenceCmHandle.getId(), "modules");
+ }
+
+ /**
+ * Retrieve yang resources from dmi for any modules that CPS-NCMP hasn't cached before.
+ *
+ * @param persistenceCmHandle the persistenceCmHandle
+ * @param unknownModuleReferences the unknown module references
+ * @return yang resources
+ */
+ public ResponseEntity<String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
+ final List<ModuleReference> unknownModuleReferences) {
+ final String jsonDataWithDataAndCmHandleProperties = getRequestBodyToFetchYangResources(
+ unknownModuleReferences, persistenceCmHandle.getAdditionalProperties());
+ return getResourceFromDmiWithJsonData(
+ persistenceCmHandle.resolveDmiServiceName(MODEL),
+ jsonDataWithDataAndCmHandleProperties,
+ persistenceCmHandle.getId(),
+ "moduleResources");
+ }
+
+ /**
+ * Get resources from DMI for modules.
+ *
+ * @param dmiServiceName dmi service name
+ * @param jsonData module names and revisions as JSON
+ * @param cmHandle cmHandle
+ * @param resourceName name of the resource(s)
+ * @return {@code ResponseEntity} response entity
+ */
+ private ResponseEntity<String> getResourceFromDmiWithJsonData(final String dmiServiceName,
+ final String jsonData,
+ final String cmHandle,
+ final String resourceName) {
+ final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName);
+ return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonData, new HttpHeaders());
+ }
+
+ private static String getRequestBodyToFetchYangResources(final List<ModuleReference> unknownModuleReferences,
+ final List<PersistenceCmHandle.AdditionalProperty> cmHandleProperties) {
+ final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(unknownModuleReferences);
+ final JsonObject data = new JsonObject();
+ data.add("modules", moduleReferencesAsJson);
+ final JsonObject jsonRequestObject = new JsonObject();
+ jsonRequestObject.add("data", data);
+ jsonRequestObject.add("cmHandleProperties", toJsonObject(cmHandleProperties));
+ return jsonRequestObject.toString();
+ }
+
+ private static JsonArray getModuleReferencesAsJson(final List<ModuleReference> unknownModuleReferences) {
+ final JsonArray moduleReferences = new JsonArray();
+
+ for (final ModuleReference moduleReference : unknownModuleReferences) {
+ final JsonObject moduleReferenceAsJson = new JsonObject();
+ moduleReferenceAsJson.addProperty("name", moduleReference.getModuleName());
+ moduleReferenceAsJson.addProperty("revision", moduleReference.getRevision());
+ moduleReferences.add(moduleReferenceAsJson);
+ }
+ return moduleReferences;
+ }
+
+ private static JsonObject toJsonObject(final List<PersistenceCmHandle.AdditionalProperty> cmHandleProperties) {
+ //TODO Toine/Joe Double check format with existing test data
+ final JsonObject asJsonObject = new JsonObject();
+ for (final PersistenceCmHandle.AdditionalProperty additionalProperty : cmHandleProperties) {
+ asJsonObject.addProperty(additionalProperty.getName(), additionalProperty.getValue());
+ }
+ return asJsonObject;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
new file mode 100644
index 0000000..5097280
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
@@ -0,0 +1,114 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
+import org.onap.cps.ncmp.api.impl.exception.NcmpException;
+import org.springframework.http.HttpHeaders;
+
+@Slf4j
+public class DmiOperations {
+
+ @Getter
+ public enum DataStoreEnum {
+ PASSTHROUGH_OPERATIONAL("ncmp-datastore:passthrough-operational"),
+ PASSTHROUGH_RUNNING("ncmp-datastore:passthrough-running");
+ private String value;
+
+ DataStoreEnum(final String value) {
+ this.value = value;
+ }
+ }
+
+ protected ObjectMapper objectMapper;
+ protected PersistenceCmHandleRetriever cmHandlePropertiesRetriever;
+ protected DmiRestClient dmiRestClient;
+ protected NcmpConfiguration.DmiProperties dmiProperties;
+
+ static final String URL_SEPARATOR = "/";
+
+ /**
+ * Constructor for {@code DmiOperations}. This method also manipulates url properties.
+ *
+ * @param dmiRestClient {@code DmiRestClient}
+ */
+ public DmiOperations(final PersistenceCmHandleRetriever cmHandlePropertiesRetriever,
+ final ObjectMapper objectMapper,
+ final NcmpConfiguration.DmiProperties dmiProperties,
+ final DmiRestClient dmiRestClient) {
+ this.cmHandlePropertiesRetriever = cmHandlePropertiesRetriever;
+ this.objectMapper = objectMapper;
+ this.dmiRestClient = dmiRestClient;
+ this.dmiProperties = dmiProperties;
+ }
+
+ String getCmHandleUrl(final String dmiServiceName, final String cmHandle) {
+ return dmiServiceName
+ + dmiProperties.getDmiBasePath()
+ + URL_SEPARATOR
+ + "v1"
+ + URL_SEPARATOR
+ + "ch"
+ + URL_SEPARATOR
+ + cmHandle
+ + URL_SEPARATOR;
+ }
+
+ String getDmiResourceUrl(final String dmiServiceName, final String cmHandle, final String resourceName) {
+ return getCmHandleUrl(dmiServiceName, cmHandle) + resourceName;
+ }
+
+ static String appendOptionsQuery(final String url, final String optionsParamInQuery) {
+ if (Strings.isNullOrEmpty(optionsParamInQuery)) {
+ return url;
+ }
+ return url + "&options=" + optionsParamInQuery;
+ }
+
+ static HttpHeaders prepareHeader(final String acceptParam) {
+ final var httpHeaders = new HttpHeaders();
+ httpHeaders.set(HttpHeaders.ACCEPT, acceptParam);
+ return httpHeaders;
+ }
+
+ /**
+ * Convert DmiRequestBody to JSON.
+ *
+ * @param dmiRequestBody the dmi request body
+ * @return DmiRequestBody as JSON
+ */
+ String getDmiRequestBodyAsString(final DmiRequestBody dmiRequestBody) {
+ try {
+ return objectMapper.writeValueAsString(dmiRequestBody);
+ } catch (final JsonProcessingException e) {
+ log.error("Parsing error occurred while converting Object to JSON.");
+ throw new NcmpException("Parsing error occurred while converting given object to JSON.",
+ e.getMessage());
+ }
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java
new file mode 100644
index 0000000..13cfdce
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java
@@ -0,0 +1,79 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.Builder;
+import lombok.Getter;
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Getter
+@Builder
+public class DmiRequestBody {
+ public enum OperationEnum {
+ READ("read"),
+ CREATE("create"),
+ UPDATE("update");
+ private String value;
+
+ OperationEnum(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ private OperationEnum operation;
+ private String dataType;
+ private String data;
+ private Map<String, String> cmHandleProperties;
+
+ /**
+ * Set CmHandleProperties by converting a list of PersistenceCmHandle.AdditionalProperty objects.
+ *
+ * @param cmHandlePropertiesAsList the cm handle additional properties
+ */
+ public void asCmHandleProperties(
+ final List<PersistenceCmHandle.AdditionalProperty> cmHandlePropertiesAsList) {
+ final boolean isCmHandlePropertiesNullOrEmpty =
+ cmHandlePropertiesAsList == null || cmHandlePropertiesAsList.isEmpty();
+ if (isCmHandlePropertiesNullOrEmpty) {
+ cmHandleProperties = Collections.emptyMap();
+ } else {
+ cmHandleProperties = new LinkedHashMap<>();
+ for (final PersistenceCmHandle.AdditionalProperty additionalProperty : cmHandlePropertiesAsList) {
+ cmHandleProperties.put(additionalProperty.getName(),
+ additionalProperty.getValue());
+ }
+ }
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java
new file mode 100644
index 0000000..78b5c31
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java
@@ -0,0 +1,89 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.onap.cps.api.CpsDataService;
+import org.onap.cps.ncmp.api.models.CmHandle;
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Component;
+
+/**
+ * Retrieves PersistenceCmHandles & properties.
+ */
+@Component
+public class PersistenceCmHandleRetriever {
+
+ private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
+ private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
+
+ private CpsDataService cpsDataService;
+
+ /**
+ * Constructor for PersistenceCmHandleRetriever.
+ *
+ * @param cpsDataService the cps data service.
+ */
+ public PersistenceCmHandleRetriever(final CpsDataService cpsDataService) {
+ this.cpsDataService = cpsDataService;
+ }
+
+ /**
+ * This method retieves dmi service name and properties for a given cm handle.
+ * @param cmHandleId the id of the cm handle
+ * @return persistence cm handle
+ */
+ public PersistenceCmHandle retrieveCmHandleDmiServiceNameAndProperties(final String cmHandleId) {
+ final DataNode cmHandleDataNode = getCmHandleDataNode(cmHandleId);
+ final CmHandle cmHandle = new CmHandle(cmHandleId, getCmHandleProperties(cmHandleDataNode));
+ return PersistenceCmHandle.toPersistenceCmHandle(
+ String.valueOf(cmHandleDataNode.getLeaves().get("dmi-service-name")),
+ String.valueOf(cmHandleDataNode.getLeaves().get("dmi-data-service-name")),
+ String.valueOf(cmHandleDataNode.getLeaves().get("dmi-model-service-name")),
+ cmHandle
+ );
+ }
+
+ private DataNode getCmHandleDataNode(final String cmHandle) {
+ final String xpathForDmiRegistryToFetchCmHandle = "/dmi-registry/cm-handles[@id='" + cmHandle + "']";
+ return cpsDataService.getDataNode(NCMP_DATASPACE_NAME,
+ NCMP_DMI_REGISTRY_ANCHOR,
+ xpathForDmiRegistryToFetchCmHandle,
+ FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+ }
+
+ private static Map<String, String> getCmHandleProperties(final DataNode cmHandleDataNode) {
+ if (cmHandleDataNode.getChildDataNodes().isEmpty()) {
+ return Collections.emptyMap();
+ }
+ final Map<String, String> cmHandlePropertiesAsMap = new LinkedHashMap<>();
+ for (final DataNode childDataNode: cmHandleDataNode.getChildDataNodes()) {
+ cmHandlePropertiesAsMap.put(String.valueOf(childDataNode.getLeaves().get("name")),
+ String.valueOf(childDataNode.getLeaves().get("value")));
+ }
+ return cmHandlePropertiesAsMap;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java
new file mode 100644
index 0000000..7e39766
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations;
+
+/**
+ * Enmm to determine if the required service is for a data or model operation.
+ */
+public enum RequiredDmiService {
+ DATA, MODEL
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
index 84227ed..a38442b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
@@ -22,7 +22,9 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
+import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.validation.annotation.Validated;
@@ -32,6 +34,8 @@
@Validated
@Getter
@Setter
+@AllArgsConstructor
+@NoArgsConstructor
public class CmHandle {
@JsonProperty("cmHandle")
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java
index f5a0d79..a604f34 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java
@@ -18,14 +18,17 @@
* ============LICENSE_END=========================================================
*/
-
package org.onap.cps.ncmp.api.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.annotation.Nulls;
+import com.google.common.base.Strings;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
+import org.onap.cps.ncmp.api.impl.exception.NcmpException;
/**
* Dmi Registry request object.
@@ -35,12 +38,53 @@
@JsonInclude(Include.NON_NULL)
public class DmiPluginRegistration {
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
private String dmiPlugin;
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
+ private String dmiDataPlugin;
+
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
+ private String dmiModelPlugin;
+
private List<CmHandle> createdCmHandles;
private List<CmHandle> updatedCmHandles;
private List<String> removedCmHandles;
+ public static final String PLEASE_SUPPLY_CORRECT_PLUGIN_INFORMATION = "Please supply correct plugin information.";
+
+ /**
+ * Validates plugin service names.
+ *
+ * @throws NcmpException if validation fails.
+ */
+ public void validateDmiPluginRegistration() throws NcmpException {
+ final String combinedServiceName = dmiPlugin;
+ final String dataServiceName = dmiDataPlugin;
+ final String modelsServiceName = dmiModelPlugin;
+
+ String errorMessage = null;
+
+ if (isNullEmptyOrBlank(combinedServiceName)
+ && isNullEmptyOrBlank(dataServiceName)
+ && isNullEmptyOrBlank(modelsServiceName)) {
+ errorMessage = "No DMI plugin service names";
+ }
+
+ if (!isNullEmptyOrBlank(combinedServiceName)
+ && (!isNullEmptyOrBlank(dataServiceName) || !isNullEmptyOrBlank(modelsServiceName))) {
+ errorMessage = "Invalid combination of plugin service names";
+ }
+
+ if (errorMessage != null) {
+ throw new NcmpException(errorMessage, PLEASE_SUPPLY_CORRECT_PLUGIN_INFORMATION);
+ }
+ }
+
+ private static boolean isNullEmptyOrBlank(final String serviceName) {
+ return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
+ }
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/GenericRequestBody.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/GenericRequestBody.java
deleted file mode 100644
index 3e1ba4a..0000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/GenericRequestBody.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 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.models;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.annotation.JsonValue;
-import java.util.Map;
-import lombok.Builder;
-import lombok.Getter;
-
-@JsonInclude(Include.NON_NULL)
-@Getter
-@Builder
-public class GenericRequestBody {
- public enum OperationEnum {
- READ("read"),
- CREATE("create"),
- UPDATE("update");
- private String value;
-
- OperationEnum(final String value) {
- this.value = value;
- }
-
- @Override
- @JsonValue
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- private OperationEnum operation;
- private String dataType;
- private String data;
- private Map<String, String> cmHandleProperties;
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
index 88d97d2..8b959e3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
@@ -22,13 +22,17 @@
package org.onap.cps.ncmp.api.models;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Strings;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
+import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
/**
* DmiRegistry.
@@ -43,22 +47,72 @@
@JsonProperty("dmi-service-name")
private String dmiServiceName;
+ @JsonProperty("dmi-data-service-name")
+ private String dmiDataServiceName;
+
+ @JsonProperty("dmi-model-service-name")
+ private String dmiModelServiceName;
+
@JsonProperty("additional-properties")
private List<AdditionalProperty> additionalProperties;
/**
+ * Create a persistenceCmHandle.
+ * @param dmiServiceName dmi service name
+ * @param dmiDataServiceName dmi data service name
+ * @param dmiModelServiceName dmi model service name
+ * @param cmHandle the cm handle
+ * @return instance of persistenceCmHandle
+ */
+ public static PersistenceCmHandle toPersistenceCmHandle(final String dmiServiceName,
+ final String dmiDataServiceName,
+ final String dmiModelServiceName,
+ final CmHandle cmHandle) {
+ final PersistenceCmHandle persistenceCmHandle = new PersistenceCmHandle();
+ persistenceCmHandle.setId(cmHandle.getCmHandleID());
+ persistenceCmHandle.setDmiServiceName(dmiServiceName);
+ persistenceCmHandle.setDmiDataServiceName(dmiDataServiceName);
+ persistenceCmHandle.setDmiModelServiceName(dmiModelServiceName);
+ if (cmHandle.getCmHandleProperties() == null) {
+ persistenceCmHandle.asAdditionalProperties(Collections.emptyMap());
+ } else {
+ persistenceCmHandle.asAdditionalProperties(cmHandle.getCmHandleProperties());
+ }
+ return persistenceCmHandle;
+ }
+
+ /**
* Set Additional Properties map, key and value pair.
* @param additionalPropertiesAsMap Map of Additional Properties
*/
- public void setAdditionalProperties(final Map<String, String> additionalPropertiesAsMap) {
+ public void asAdditionalProperties(final Map<String, String> additionalPropertiesAsMap) {
additionalProperties = new ArrayList<>(additionalPropertiesAsMap.size());
for (final Map.Entry<String, String> entry : additionalPropertiesAsMap.entrySet()) {
additionalProperties.add(new AdditionalProperty(entry.getKey(), entry.getValue()));
}
}
+ /**
+ * Resolve a dmi service name.
+ * @param requiredService indicates what typo of service is required
+ * @return dmi service name
+ */
+ public String resolveDmiServiceName(final RequiredDmiService requiredService) {
+ if (isNullEmptyOrBlank(dmiServiceName)) {
+ if (RequiredDmiService.DATA.equals(requiredService)) {
+ return dmiDataServiceName;
+ }
+ return dmiModelServiceName;
+ }
+ return dmiServiceName;
+ }
+
+ private static boolean isNullEmptyOrBlank(final String serviceName) {
+ return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
+ }
+
@AllArgsConstructor
- @Getter
+ @Data
public static class AdditionalProperty {
@JsonProperty()
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandlesList.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandlesList.java
index f35abf6..d4f6e95 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandlesList.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandlesList.java
@@ -22,6 +22,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import lombok.Getter;
@@ -32,6 +33,31 @@
private List<PersistenceCmHandle> persistenceCmHandles = new ArrayList<>();
/**
+ * Create a PersistenceCmHandleList given all service names and a collection of cmHandles.
+ * @param dmiServiceName the dmi service name
+ * @param dmiDataServiceName the dmi data service name
+ * @param dmiModelServiceName the dmi model service name
+ * @param cmHandles cm handles
+ * @return instance of PersistenceCmHandleList
+ */
+ public static PersistenceCmHandlesList toPersistenceCmHandlesList(final String dmiServiceName,
+ final String dmiDataServiceName,
+ final String dmiModelServiceName,
+ final Collection<CmHandle> cmHandles) {
+ final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
+ for (final CmHandle cmHandle : cmHandles) {
+ final PersistenceCmHandle persistenceCmHandle =
+ PersistenceCmHandle.toPersistenceCmHandle(
+ dmiServiceName,
+ dmiDataServiceName,
+ dmiModelServiceName,
+ cmHandle);
+ persistenceCmHandlesList.add(persistenceCmHandle);
+ }
+ return persistenceCmHandlesList;
+ }
+
+ /**
* Add a persistenceCmHandle.
*
* @param persistenceCmHandle the persistenceCmHandle to add
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
new file mode 100644
index 0000000..2a85a4a
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
@@ -0,0 +1,74 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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
+
+
+import org.onap.cps.api.CpsAdminService
+import org.onap.cps.api.CpsModuleService
+import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.spi.model.ModuleReference
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import spock.lang.Specification
+
+class NetworkCmProxyDataServiceImplModelSyncSpec extends Specification {
+
+ def mockCpsModuleService = Mock(CpsModuleService)
+ def mockCpsAdminService = Mock(CpsAdminService)
+ def mockDmiModelOperations = Mock(DmiModelOperations)
+
+ def objectUnderTest = new NetworkCmProxyDataServiceImpl(null, mockDmiModelOperations,
+ mockCpsModuleService, null, null, mockCpsAdminService, null)
+
+ def expectedDataspaceName = 'NFP-Operational'
+
+ def 'Sync model for a (new) cm handle with #scenario'() {
+ given: 'persistence cm handle is given'
+ def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
+ and: 'additional properties are set as required'
+ if (additionalProperties!=null) {
+ cmHandleForModelSync.asAdditionalProperties(additionalProperties)
+ }
+ and: 'dmi operations returns some module references'
+ def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
+ def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
+ mockDmiModelOperations.getModuleReferences(cmHandleForModelSync) >> moduleReferencesFromCmHandleAsJson
+ and: 'CPS-Core returns list of existing module resources'
+ mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> existingModuleResourcesInCps
+ and: 'DMI-Plugin returns resource(s) for "new" module(s)'
+ def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
+ mockDmiModelOperations.getNewYangResourcesFromDmi(cmHandleForModelSync, [new ModuleReference('module1', '1')]) >> moduleResources
+ when: 'module sync is triggered'
+ objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
+ then: 'the CPS module service is called once with the correct parameters'
+ 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, expectedKnownModules)
+ and: 'admin service create anchor method has been called with correct parameters'
+ 1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
+ where: 'the following parameters are used'
+ scenario | additionalProperties | existingModuleResourcesInCps | sdncReponseBody || expectedYangResourceToContentMap | expectedKnownModules | expectedJsonForAdditionalProperties
+ 'one unknown module' | ['name1': 'value1'] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{"name1":"value1"}'
+ 'no add. properties' | [:] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{}'
+ 'additional properties is null' | null | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] | '{}'
+ 'no unknown module' | [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '[]' || [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '{}'
+ }
+}
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
new file mode 100644
index 0000000..86c01b4
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -0,0 +1,167 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.ncmp.api.impl.exception.NcmpException
+import org.onap.cps.ncmp.api.models.CmHandle
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.exceptions.DataValidationException
+import spock.lang.Shared
+import spock.lang.Specification
+
+class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
+
+ @Shared
+ def persistenceCmHandle = new CmHandle()
+
+ @Shared
+ def cmHandlesArray = ['cmHandle001']
+
+ def mockCpsDataService = Mock(CpsDataService)
+ def spyObjectMapper = Spy(ObjectMapper)
+
+ def noTimestamp = null
+
+ def 'Register or re-register a DMI Plugin for the given cm-handle(s) with #scenario process.'() {
+ given: 'a registration'
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
+ persistenceCmHandle.cmHandleID = '123'
+ persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
+ dmiPluginRegistration.createdCmHandles = createdCmHandles
+ dmiPluginRegistration.updatedCmHandles = updatedCmHandles
+ dmiPluginRegistration.removedCmHandles = removedCmHandles
+ def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'save list elements is invoked with the expected parameters'
+ expectedCallsToSaveNode * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
+ '/dmi-registry', expectedJsonData, noTimestamp)
+ and: 'update node and child data nodes is invoked with correct parameters'
+ expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin',
+ 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp)
+ and : 'delete list or list element is invoked with the correct parameters'
+ expectedCallsToDeleteListElement * mockCpsDataService.deleteListOrListElement('NCMP-Admin',
+ 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
+ where:
+ scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode | expectedCallsToDeleteListElement
+ 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 0
+ 'update' | [] | [persistenceCmHandle] | [] || 0 | 1 | 0
+ 'delete' | [] | [] | cmHandlesArray || 0 | 0 | 1
+ 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1
+ 'no valid data' | null | null | null || 0 | 0 | 0
+ }
+
+ def 'Register a DMI Plugin for the given cm-handle(s) without additional properties.'() {
+ given: 'a registration without cm-handle properties'
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
+ persistenceCmHandle.cmHandleID = '123'
+ persistenceCmHandle.cmHandleProperties = null
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[]}]}'
+ when: 'registration is updated'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'save list elements is invoked with the expected parameters'
+ 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
+ '/dmi-registry', expectedJsonData, noTimestamp)
+ }
+
+ def 'Register a DMI Plugin for a given cm-handle(s) with JSON processing errors during #scenario process.'() {
+ given: 'a registration without cm-handle properties '
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'some-plugin')
+ dmiPluginRegistration.createdCmHandles = createdCmHandles
+ dmiPluginRegistration.updatedCmHandles = updatedCmHandles
+ and: 'an json processing exception occurs'
+ spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'a data validation exception is thrown'
+ thrown(DataValidationException)
+ where:
+ scenario | createdCmHandles | updatedCmHandles
+ 'create' | [persistenceCmHandle] | []
+ 'update' | [] | [persistenceCmHandle]
+ }
+
+ def 'Register a DMI Plugin for the given cm-handle(s) with no data found during delete process.'() {
+ given: 'a registration without cm-handle properties '
+ NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'some-plugin')
+ dmiPluginRegistration.removedCmHandles = ['some cm handle']
+ and: 'an json processing exception occurs during delete process'
+ mockCpsDataService.deleteListOrListElement(*_) >> { throw (new DataNodeNotFoundException('','')) }
+ when: 'registration is updated and modules are synced'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ }
+
+ def 'Dmi plugin registration with #scenario'() {
+ given: 'a registration '
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:dmiPlugin, dmiModelPlugin:dmiModelPlugin,
+ dmiDataPlugin:dmiDataPlugin)
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ 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.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ where:
+ scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin
+ 'combined DMI plugin' | 'service1' | '' | ''
+ 'data & model DMI plugins' | '' | 'service1' | 'service2'
+ 'data & model using same service' | '' | 'service1' | 'service1'
+ }
+
+ def 'Invalid dmi plugin registration with #scenario'() {
+ given: 'a registration '
+ def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:dmiPlugin, dmiModelPlugin:dmiModelPlugin,
+ dmiDataPlugin:dmiDataPlugin)
+ dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
+ when: 'registration is called with incorrect DMI plugin information'
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'an NcmpException is thrown with correct message details'
+ def exceptionThrown = thrown(NcmpException)
+ assert exceptionThrown.getMessage().contains(expectedMessageDetails)
+ and: 'registration is not called'
+ 0 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ where:
+ scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
+ 'no DMI plugin' | '' | '' | '' || 'No DMI plugin service names'
+ 'all DMI plugins' | 'service1' | 'service2' | 'service3' || 'Invalid combination of plugin service names'
+ 'no model DMI plugin' | 'service1' | '' | 'service2' || 'Invalid combination of plugin service names'
+ 'no data DMI plugin' | 'service1' | 'service2' | '' || 'Invalid combination of plugin service names'
+ }
+
+ def getObjectUnderTestWithModelSyncDisabled() {
+ def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(null, null, null,
+ mockCpsDataService, null, null, spyObjectMapper))
+ objectUnderTest.syncModulesAndCreateAnchor(*_) >> null
+ return objectUnderTest
+ }
+}
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 b0c447e..8bb0ee2 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
@@ -22,79 +22,54 @@
package org.onap.cps.ncmp.api.impl
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.impl.operations.DmiRequestBody
+import org.springframework.http.HttpHeaders
+
+import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
+
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsAdminService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.api.CpsQueryService
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
import org.onap.cps.ncmp.api.impl.exception.NcmpException
-import org.onap.cps.ncmp.api.impl.operation.DmiOperations
-import org.onap.cps.ncmp.api.models.CmHandle
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.PersistenceCmHandle
-import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
+import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
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.ModuleReference
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
-import spock.lang.Shared
import spock.lang.Specification
class NetworkCmProxyDataServiceImplSpec extends Specification {
- @Shared
- def persistenceCmHandle = new CmHandle()
- @Shared
- def cmHandlesArray = ['cmHandle001']
-
def mockCpsDataService = Mock(CpsDataService)
def mockCpsQueryService = Mock(CpsQueryService)
- def mockDmiOperations = Mock(DmiOperations)
def mockCpsModuleService = Mock(CpsModuleService)
def mockCpsAdminService = Mock(CpsAdminService)
- def mockDmiProperties = Mock(NcmpConfiguration.DmiProperties)
def spyObjectMapper = Spy(ObjectMapper)
+ def mockDmiDataOperations = Mock(DmiDataOperations)
- def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
- mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
+ def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiDataOperations, null,
+ mockCpsModuleService, mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
def cmHandle = 'some handle'
def noTimestamp = null
def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
def expectedDataspaceName = 'NFP-Operational'
-
- def 'Get data node.'() {
- when: 'queryDataNodes is invoked'
- objectUnderTest.getDataNode(cmHandle, 'some xpath', fetchDescendantsOption)
- then: 'the persistence data service is called once with the correct parameters'
- 1 * mockCpsDataService.getDataNode(expectedDataspaceName, cmHandle, 'some xpath', fetchDescendantsOption)
- where: 'all fetch descendants options are supported'
- fetchDescendantsOption << FetchDescendantsOption.values()
- }
-
- def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
- given: 'a cm Handle and a cps path'
- def cpsPath = '/cps-path'
- when: 'queryDataNodes is invoked'
- objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
- then: 'the persistence query service is called once with the correct parameters'
- 1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
- where: 'all fetch descendants options are supported'
- fetchDescendantsOption << FetchDescendantsOption.values()
- }
-
def 'Create full data node: #scenario.'() {
- given: 'a cm handle and root xpath'
+ given: 'json data'
def jsonData = 'some json'
when: 'createDataNode is invoked'
objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'save data is invoked once with the expected parameters'
1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData, noTimestamp)
where: 'following parameters were used'
scenario | xpath
@@ -103,274 +78,38 @@
}
def 'Create child data node.'() {
- given: 'a cm handle and parent node xpath'
+ given: 'json data and xpath'
def jsonData = 'some json'
def xpath = '/test-node'
- when: 'createDataNode is invoked'
+ when: 'create data node is invoked'
objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'save data is invoked once with the expected parameters'
1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
}
def 'Add list-node elements.'() {
- given: 'a cm handle and parent node xpath'
+ given: 'json data and xpath'
def jsonData = 'some json'
def xpath = '/test-node'
- when: 'addListNodeElements is invoked'
+ when: 'add list node element is invoked'
objectUnderTest.addListNodeElements(cmHandle, xpath, jsonData)
- then: 'the CPS service method is invoked once with the expected parameters'
+ then: 'the save list elements is invoked once with the expected parameters'
1 * mockCpsDataService.saveListElements(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
}
- def 'Update data node leaves.'() {
- given: 'a cm Handle and a cps path'
- def xpath = '/xpath'
- def jsonData = 'some json'
- when: 'updateNodeLeaves is invoked'
- objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
- then: 'the persistence service is called once with the correct parameters'
- 1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
- }
-
- def 'Replace data node tree.'() {
- given: 'a cm Handle and a cps path'
- def xpath = '/xpath'
- def jsonData = 'some json'
- when: 'replaceNodeTree is invoked'
- objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
- then: 'the persistence service is called once with the correct parameters'
- 1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
- }
-
- def 'Register or re-register a DMI Plugin with #scenario cm handles.'() {
- given: 'a registration '
- def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.dmiPlugin = 'my-server'
- persistenceCmHandle.cmHandleID = '123'
- persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
- dmiPluginRegistration.createdCmHandles = createdCmHandles
- dmiPluginRegistration.updatedCmHandles = updatedCmHandles
- dmiPluginRegistration.removedCmHandles = removedCmHandles
- def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'cps save list elements is invoked with the expected parameters'
- expectedCallsToSaveNode * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
- '/dmi-registry', expectedJsonData, noTimestamp)
- and: 'update node and child data nodes is invoked with correct parameters'
- expectedCallsToUpdateNode * mockCpsDataService.updateNodeLeavesAndExistingDescendantLeaves('NCMP-Admin',
- 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp)
- and : 'delete list or list element is invoked with the correct parameters'
- expectedCallsToDeleteListElement * mockCpsDataService.deleteListOrListElement('NCMP-Admin',
- 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
-
- where:
- scenario | createdCmHandles | updatedCmHandles | removedCmHandles || expectedCallsToSaveNode | expectedCallsToUpdateNode | expectedCallsToDeleteListElement
- 'create' | [persistenceCmHandle] | [] | [] || 1 | 0 | 0
- 'update' | [] | [persistenceCmHandle] | [] || 0 | 1 | 0
- 'delete' | [] | [] | cmHandlesArray || 0 | 0 | 1
- 'create, update and delete' | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray || 1 | 1 | 1
- 'no valid data' | null | null | null || 0 | 0 | 0
- }
-
- def 'Register a DMI Plugin for the given cmHandle without additional properties.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.dmiPlugin = 'my-server'
- persistenceCmHandle.cmHandleID = '123'
- persistenceCmHandle.cmHandleProperties = null
- dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
- def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[]}]}'
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'the cps save list element is invoked with the expected parameters'
- 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry',
- '/dmi-registry', expectedJsonData, noTimestamp)
- }
-
- def 'Register a DMI Plugin with JSON processing errors during #scenario.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.createdCmHandles = createdCmHandles
- dmiPluginRegistration.updatedCmHandles = updatedCmHandles
- and: 'an JSON processing exception occurs'
- spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'a data validation exception is thrown'
- thrown(DataValidationException)
- where:
- scenario | createdCmHandles | updatedCmHandles
- 'create' | [persistenceCmHandle] | []
- 'update' | [] | [persistenceCmHandle]
- }
-
- def 'Register a DMI Plugin with no data found during delete.'() {
- given: 'a registration without cmHandle properties '
- NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
- def dmiPluginRegistration = new DmiPluginRegistration()
- dmiPluginRegistration.removedCmHandles = ['some cm handle']
- and: 'an JSON processing exception occurs'
- mockCpsDataService.deleteListOrListElement(*_) >> { throw (new DataNodeNotFoundException('','')) }
- when: 'registration is updated'
- objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- then: 'no exception is thrown'
- noExceptionThrown()
- }
-
- def 'Get resource data for pass-through operational from dmi.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'data node is got from data service'
+ def 'Write resource data for passthrough running from dmi using POST #scenario cm handle properties.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(includeCmHandleProperties)
+ and: 'cpsDataService returns valid datanode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'resource data is got from DMI'
- mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'dmi returns ok response'
- response == 'result-json'
- }
-
- def 'Get resource data for pass-through operational from dmi threw parsing exception.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cps data service returns valid cmHandle data node'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'objectMapper not able to parse object'
- def mockObjectMapper = Mock(ObjectMapper)
- objectUnderTest.objectMapper = mockObjectMapper
- mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown with the expected details'
- def exceptionThrown = thrown(NcmpException.class)
- exceptionThrown.details == 'testException'
- }
-
- def 'Get resource data for pass-through operational from dmi return NOK response.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cps data service returns valid cmHandle data node'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns NOK response'
- mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
- >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown'
- def exceptionThrown = thrown(NcmpException.class)
- and: 'details contains the original response'
- exceptionThrown.details.contains('NOK-json')
- }
-
- def 'Get resource data for pass-through running from dmi.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns valid response and data'
- mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'get resource data returns expected response'
- response == '{result-json}'
- }
-
- def 'Get resource data for pass-through running from dmi threw parsing exception.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'objectMapper not able to parse object'
- def mockObjectMapper = Mock(ObjectMapper)
- objectUnderTest.objectMapper = mockObjectMapper
- mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown with the expected details'
- def exceptionThrown = thrown(NcmpException.class)
- exceptionThrown.details == 'testException'
- }
-
- def 'Get resource data for pass-through running from dmi return NOK response.'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
- and: 'cpsDataService returns valid dataNode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi returns NOK response'
- mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '(a=1,b=2)',
- 'testAcceptParam',
- '{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
- >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- 'testAcceptParam',
- '(a=1,b=2)')
- then: 'exception is thrown'
- def exceptionThrown = thrown(NcmpException.class)
- and: 'details contains the original response'
- exceptionThrown.details.contains('NOK-json')
- }
-
- def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
- given: 'data node representing cmHandle #scenario cm handle properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(includeCmHandleProperties)
- and: 'cpsDataService returns valid cm-handle datanode'
- mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- when: 'get resource data is called'
- objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
then: 'dmi called with correct data'
- 1 * mockDmiOperations.createResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '{"operation":"create","dataType":"application/json","data":"{some-json}","cmHandleProperties":'
- + expectedJsonForCmhandleProperties+ '}')
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
+ CREATE, '{some-json}', 'application/json')
>> { new ResponseEntity<>(HttpStatus.CREATED) }
where:
scenario | includeCmHandleProperties || expectedJsonForCmhandleProperties
@@ -378,57 +117,148 @@
'without' | false || '{}'
}
- def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
- given: 'data node representing cmHandle and its properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(true)
+ def 'Write resource data for passthrough running from dmi using POST "not found" response (from DMI).'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
and: 'cpsDataService returns valid dataNode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- and: 'dmi throws exception'
- mockDmiOperations.createResourceDataPassThroughRunningFromDmi(_ as String, _ as String, _ as String, _ as String)
- >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
- when: 'get resource data is called'
- objectUnderTest.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns a response with 404 status code'
+ mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
+ >> { new ResponseEntity<>(HttpStatus.NOT_FOUND) }
+ when: 'write resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json')
then: 'exception is thrown'
def exceptionThrown = thrown(NcmpException.class)
and: 'details contains (not found) error code: 404'
exceptionThrown.details.contains('404')
}
- def 'Sync model for a (new) cm handle with #scenario'() {
- given: 'persistence cm handle is given'
- def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
- and: 'additional properties are set as required'
- if (additionalProperties!=null) {
- cmHandleForModelSync.setAdditionalProperties(additionalProperties)
- }
- and: 'dmi operations returns some module references'
- def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
- def expectedJsonBody = '{"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
- mockDmiProperties.getAuthUsername() >> 'someUser'
- mockDmiProperties.getAuthPassword() >> 'somePassword'
- def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
- mockDmiOperations.getResourceFromDmiWithJsonData('some service name', expectedJsonBody, 'some cm handle', 'modules') >> moduleReferencesFromCmHandleAsJson
- and: 'CPS-Core returns list of known modules'
- mockCpsModuleService.getYangResourceModuleReferences(_) >> existingModuleResourcesInCps
- and: 'DMI-Plugin returns resource(s) for "new" module(s)'
- def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
- def jsonDataToFetchYangResource = '{"data":{"modules":[{"name":"module1","revision":"1"}]},"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
- mockDmiOperations.getResourceFromDmiWithJsonData('some service name', jsonDataToFetchYangResource, 'some cm handle', 'moduleResources') >> moduleResources
- when: 'module Sync is triggered'
- objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
- then: 'the CPS module service is called once with the correct parameters'
- 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, expectedKnownModules)
- and: 'admin service create anchor method has been called with correct parameters'
- 1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
- where: 'the following responses are received from SDNC'
- scenario | additionalProperties | existingModuleResourcesInCps | sdncReponseBody || expectedYangResourceToContentMap | expectedKnownModules | expectedJsonForAdditionalProperties
- 'one unknown module' | ['name1':'value1'] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{"name1":"value1"}'
- 'no add. properties' | [:] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
- 'additional properties is null' | null | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
- 'no unknown module' | [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '[]' || [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] |'{}'
+ def 'Get data node.'() {
+ when: 'get data node is invoked'
+ objectUnderTest.getDataNode(cmHandle, 'some xpath', fetchDescendantsOption)
+ then: 'the persistence data service is called once with the correct parameters'
+ 1 * mockCpsDataService.getDataNode(expectedDataspaceName, cmHandle, 'some xpath', fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
+ }
+
+ def 'Get resource data for passthrough operational from dmi.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'get data node is called'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'get resource data from dmi is called'
+ mockDmiDataOperations.getResourceDataFromDmi(
+ 'testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam' ,
+ PASSTHROUGH_OPERATIONAL) >> new ResponseEntity<>('result-json', HttpStatus.OK)
+ when: 'get resource data operational for cm-handle is called'
+ def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'dmi returns a json response'
+ response == 'result-json'
+ }
+
+ def 'Get resource data for passthrough operational from dmi with Json Processing Exception.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cps data service returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'objectMapper not able to parse object'
+ def mockObjectMapper = Mock(ObjectMapper)
+ objectUnderTest.objectMapper = mockObjectMapper
+ mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi(*_)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown with the expected details'
+ def exceptionThrown = thrown(NcmpException.class)
+ exceptionThrown.details == 'DMI status code: 404, DMI response body: NOK-json'
+ }
+
+ def 'Get resource data for passthrough operational from dmi return NOK response.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cps data service returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_OPERATIONAL)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown'
+ def exceptionThrown = thrown(NcmpException.class)
+ and: 'details contains the original response'
+ exceptionThrown.details.contains('NOK-json')
+ }
+
+ def 'Get resource data for passthrough running from dmi.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cpsDataService returns valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns valid response and data'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_RUNNING) >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
+ when: 'get resource data is called'
+ def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'get resource data returns expected response'
+ response == '{result-json}'
+ }
+
+ def 'Get resource data for passthrough running from dmi return NOK response.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(true)
+ and: 'cpsDataService returns valid dataNode'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ and: 'dmi returns NOK response'
+ mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
+ 'testResourceId',
+ '(a=1,b=2)',
+ 'testAcceptParam',
+ PASSTHROUGH_RUNNING)
+ >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId',
+ 'testAcceptParam',
+ '(a=1,b=2)')
+ then: 'exception is thrown'
+ def exceptionThrown = thrown(NcmpException.class)
+ and: 'details contains the original response'
+ exceptionThrown.details.contains('NOK-json')
}
def 'Getting Yang Resources.'() {
@@ -438,18 +268,6 @@
1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
}
- def 'Create the request body to get yang resources from DMI.'() {
- given: 'the expected json request'
- def expectedRequestBody = '{"data":{"modules":[{"name":"module1","revision":"1"},{"name":"module2","revision":"2"}]},"cmHandleProperties":{"name1":"value1"}}'
- and: 'module references and cm handle properties'
- def moduleReferences = [new ModuleReference('module1', '1'),new ModuleReference('module2', '2')]
- def cmHandleProperties = ['name1':'value1']
- when: 'get request body to fetch yang resources from DMI is called'
- def result = objectUnderTest.getRequestBodyToFetchYangResourceFromDmi(moduleReferences, cmHandleProperties)
- then: 'the result is the same as the expected request body'
- result == expectedRequestBody
- }
-
def 'Get cm handle identifiers for the given module names.'() {
when: 'execute a cm handle search for the given module names'
objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name'])
@@ -457,45 +275,86 @@
1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
}
- def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
- given: 'data node representing cmHandle #scenario cm handle properties'
- def cmHandleDataNode = getCmHandleDataNodeForTest(includeCmHandleProperties)
- and: 'cpsDataService returns valid cm-handle datanode'
+ def 'Update data node leaves.'() {
+ given: 'json data and xpath'
+ def jsonData = 'some json'
+ def xpath = '/xpath'
+ when: 'update node leaves is invoked'
+ objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
+ then: 'the persistence service is called once with the correct parameters'
+ 1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
+ }
+
+ def 'Replace data node tree.'() {
+ given: 'json data and xpath'
+ def jsonData = 'some json'
+ def xpath = '/xpath'
+ when: 'replace node tree is invoked'
+ objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
+ then: 'the persistence service is called once with the correct parameters'
+ 1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
+ }
+
+ def 'Update resource data for passthrough running from dmi using POST #scenario cm handle properties.'() {
+ given: 'a data node'
+ def dataNode = getDataNode(includeCmHandleProperties)
+ and: 'cpsDataService returns valid datanode'
mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
- cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> cmHandleDataNode
- when: 'update resource data is called'
- objectUnderTest.updateResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId',
- '{some-json}', 'application/json')
+ cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'get resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', UPDATE,
+ '{some-json}', 'application/json')
then: 'dmi called with correct data'
- 1 * mockDmiOperations.updateResourceDataPassThroughRunningFromDmi('testDmiService',
- 'testCmHandle',
- 'testResourceId',
- '{"operation":"update","dataType":"application/json","data":"{some-json}","cmHandleProperties":'
- + expectedJsonForCmhandleProperties + '}')
- >> new ResponseEntity<>(HttpStatus.OK)
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
+ UPDATE, '{some-json}', 'application/json')
+ >> { new ResponseEntity<>(HttpStatus.OK) }
where:
scenario | includeCmHandleProperties || expectedJsonForCmhandleProperties
'with' | true || '{"testName":"testValue"}'
'without' | false || '{}'
}
- def getObjectUnderTestWithModelSyncDisabled() {
- def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
- mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper))
- objectUnderTest.syncModulesAndCreateAnchor(_) >> null
- return objectUnderTest
+ def 'Verify error message from handleResponse is correct for #scenario operation.'() {
+ given: 'writeResourceDataPassThroughRunningFromDmi fails to return OK HttpStatus'
+ mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi(*_)
+ >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
+ when: 'get resource data is called'
+ def response = objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
+ 'testCmHandle',
+ 'testResourceId',
+ givenOperation,
+ '{some-json}',
+ 'application/json')
+ then: 'an exception is thrown with the expected error message detailsd with correct operation'
+ def exceptionThrown = thrown(NcmpException.class)
+ exceptionThrown.getMessage().contains(expectedResponseMessage)
+ where:
+ scenario | givenOperation || expectedResponseMessage
+ 'CREATE' | CREATE || 'Not able to create resource data.'
+ 'READ' | READ || 'Not able to read resource data.'
+ 'UPDATE' | UPDATE || 'Not able to update resource data.'
}
- def getCmHandleDataNodeForTest(boolean includeCmHandleProperties) {
- def cmHandleDataNode = new DataNode()
- cmHandleDataNode.leaves = ['dmi-service-name': 'testDmiService']
+ def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
+ given: 'a cps path'
+ def cpsPath = '/cps-path'
+ when: 'query data nodes is invoked'
+ objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
+ then: 'the persistence query service is called once with the correct parameters'
+ 1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
+ }
+
+ def getDataNode(boolean includeCmHandleProperties) {
+ def dataNode = new DataNode()
+ dataNode.leaves = ['dmi-service-name': 'testDmiService']
if (includeCmHandleProperties) {
def cmHandlePropertyDataNode = new DataNode()
cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
- cmHandleDataNode.childDataNodes = [cmHandlePropertyDataNode]
+ dataNode.childDataNodes = [cmHandlePropertyDataNode]
}
- return cmHandleDataNode
+ return dataNode
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy
deleted file mode 100644
index 44d4f0c..0000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operation/DmiOperationsSpec.groovy
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 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.operation
-
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
-import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.http.HttpHeaders
-import org.springframework.test.context.ContextConfiguration
-import spock.lang.Specification
-
-@SpringBootTest
-@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiOperations])
-class DmiOperationsSpec extends Specification {
-
- @SpringBean
- DmiRestClient mockDmiRestClient = Mock()
-
- @Autowired
- DmiOperations objectUnderTest = new DmiOperations(mockDmiRestClient)
-
- def 'call get resource data for pass-through:operational datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child&options=(a=1,b=2)'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- '(a=1,b=2)',
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call get resource data for pass-through:running datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child&options=(a=1,b=2)'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataPassThroughRunningFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- '(a=1,b=2)',
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call get resource data for pass-through:operational datastore from DMI when options is null.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child'
- when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- null,
- 'testAcceptJson',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
- def 'call create resource data for pass-through:running datastore from DMI.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child'
- when: 'get resource data is called to DMI'
- objectUnderTest.createResourceDataPassThroughRunningFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'parent/child',
- 'testJsonbody')
- then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
- }
-
- def 'Call get resource from dmi.'() {
- given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/modules'
- when: 'get resource data is called to dmi'
- objectUnderTest.getResourceFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'modules')
- then: 'the post operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperation(expectedUrl, _ as HttpHeaders)
- }
-
- def 'Call get resource from dmi with json data.'() {
- given: 'expected url & json data'
- def requestBody = 'some json'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmHandle/modules'
- def expectedHttpHeaders = new HttpHeaders()
- when: 'get resource data is called to dmi'
- objectUnderTest.getResourceFromDmiWithJsonData('testDmiBasePath',
- requestBody,
- 'testCmHandle',
- 'modules')
- then: 'the post operation is executed with the correct URL and json data'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, requestBody, expectedHttpHeaders)
- }
-
- def 'Update resource data for pass-through:running datastore from DMI.'() {
- given: 'the expected url'
- def cmHandle = 'some-cmhandle'
- def resourceIdentifier = 'parent/child'
- def expectedUrl = 'some-dmi-service-name/dmi/v1/ch/' + cmHandle + '/data/ds' +
- '/ncmp-datastore:passthrough-running?resourceIdentifier=' + resourceIdentifier
- when: 'replace resource data is called for DMI'
- objectUnderTest.updateResourceDataPassThroughRunningFromDmi('some-dmi-service-name',
- cmHandle,
- resourceIdentifier,
- 'some-json-body')
- then: 'the post operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'some-json-body', _ as HttpHeaders)
- }
-}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
new file mode 100644
index 0000000..674a442
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
@@ -0,0 +1,84 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations
+
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
+
+import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
+import org.springframework.http.HttpStatus
+
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiDataOperations])
+class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
+
+ @Autowired
+ DmiDataOperations objectUnderTest
+
+ def 'call get resource data for #expectedDatastoreInUrl from DMI #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalProperties)
+ and: 'a positive response from dmi service when it is called with the expected parameters'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ mockDmiRestClient.putOperationWithJsonData(
+ "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}",
+ expectedJson, [Accept:['sample accept header']]) >> responseFromDmi
+ when: 'get resource data is invoked'
+ def result = objectUnderTest.getResourceDataFromDmi(cmHandleId,resourceIdentifier, options,'sample accept header', dataStore)
+ then: 'the result is the response from the dmi service'
+ assert result == responseFromDmi
+ where: 'the following parameters are used'
+ scenario | additionalProperties | dataStore | options || expectedJson | expectedDatastoreInUrl | expectedOptionsInUrl
+ 'without properties' | [] | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'null properties' | null | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'with properties' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+ 'null options' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | null || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+ 'empty options' | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | '' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+ 'datastore running' | [] | PASSTHROUGH_RUNNING | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-running' | '&options=(a=1,b=2)'
+ }
+
+ def 'Write data for pass-through:running datastore in DMI.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval([sampleAdditionalProperty])
+ and: 'a positive response from dmi service when it is called with the expected parameters'
+ def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds" +
+ "/ncmp-datastore:passthrough-running?resourceIdentifier=${resourceIdentifier}"
+ def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, [:]) >> responseFromDmi
+ when: 'write resource method is invoked'
+ def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId,'parent/child', operation, 'requestData', 'some data type')
+ then: 'the result is the response from the dmi service'
+ assert result == responseFromDmi
+ where: 'the following operation is performed'
+ operation || expectedOperationInUrl
+ CREATE || 'create'
+ UPDATE || 'update'
+ }
+
+}
\ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
new file mode 100644
index 0000000..d9d1271
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.operations
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.onap.cps.ncmp.api.impl.exception.NcmpException
+import org.onap.cps.spi.model.ModuleReference
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Shared
+
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiModelOperations])
+class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
+
+ @Shared
+ def newModuleReferences = [new ModuleReference('mod1','A'), new ModuleReference('mod2','X')]
+
+ @Autowired
+ DmiModelOperations objectUnderTest
+
+ def 'Module references for a persistence cm handle #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
+ and: 'a positive response from dmi service when it is called with tha expected parameters'
+ def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
+ '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', [:]) >> responseFromDmi
+ when: 'a get module references is called'
+ def result = objectUnderTest.getModuleReferences(persistenceCmHandle)
+ then: 'the result is the response from dmi service'
+ assert result == responseFromDmi
+ where:
+ scenario | additionalPropertiesObject || expectedAdditionalPropertiesInRequest
+ 'with properties' | [sampleAdditionalProperty] || '{"prop1":"val1"}'
+ 'with null properties' | null || "{}"
+ 'without properties' | [] || "{}"
+ }
+
+ def 'New yang resources from dmi using persistence cm handle #scenario.'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
+ and: 'a positive response from dmi service when it is called with tha expected parameters'
+ def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
+ mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+ '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":'+expectedAdditionalPropertiesInRequest+'}',
+ [:]) >> responseFromDmi
+ when: 'get new yang resources from dmi service'
+ def result = objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences)
+ then: 'the result is the response from dmi service'
+ assert result == responseFromDmi
+ where:
+ scenario | additionalPropertiesObject | unknownModuleReferences || expectedAdditionalPropertiesInRequest | expectedModuleReferencesInRequest
+ 'with module references and properties' | [sampleAdditionalProperty] | newModuleReferences || '{"prop1":"val1"}' | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+ 'without module references' | [sampleAdditionalProperty] | [] || '{"prop1":"val1"}' | ''
+ 'without properties' | [] | newModuleReferences || '{}' | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+ }
+
+ def 'New yang resources from dmi with additional properties null'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval(null)
+ when: 'a get new yang resources from dmi is called'
+ objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, [])
+ then: 'a null pointer is thrown (we might need to address this later)'
+ thrown(NullPointerException)
+ }
+
+ def 'Json Processing Exception'() {
+ given: 'a persistence cm handle for #cmHandleId'
+ mockPersistenceCmHandleRetrieval([])
+ and: 'a Json processing exception occurs'
+ spyObjectMapper.writeValueAsString(_) >> {throw (new JsonProcessingException(''))}
+ when: 'a dmi operation is executed'
+ objectUnderTest.getModuleReferences(persistenceCmHandle)
+ then: 'an ncmp exception is thrown'
+ def exceptionThrown = thrown(NcmpException)
+ and: 'the message indicates a parsing error'
+ exceptionThrown.message.toLowerCase().contains("parsing error")
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
new file mode 100644
index 0000000..4bf7dad
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -0,0 +1,36 @@
+package org.onap.cps.ncmp.api.impl.operations
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.impl.client.DmiRestClient
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import org.spockframework.spring.SpringBean
+import spock.lang.Shared
+import spock.lang.Specification
+
+abstract class DmiOperationsBaseSpec extends Specification {
+
+ @Shared
+ def sampleAdditionalProperty = new PersistenceCmHandle.AdditionalProperty('prop1', 'val1')
+
+ @SpringBean
+ DmiRestClient mockDmiRestClient = Mock()
+
+ @SpringBean
+ PersistenceCmHandleRetriever mockCmHandlePropertiesRetriever = Mock()
+
+ @SpringBean
+ ObjectMapper spyObjectMapper = Spy()
+
+ def persistenceCmHandle = new PersistenceCmHandle()
+ def static dmiServiceName = 'some service name'
+ def static cmHandleId = 'some cm handle'
+ def static resourceIdentifier = 'parent/child'
+
+ def mockPersistenceCmHandleRetrieval(additionalProperties) {
+ persistenceCmHandle.dmiDataServiceName = dmiServiceName
+ persistenceCmHandle.dmiServiceName = dmiServiceName
+ persistenceCmHandle.additionalProperties = additionalProperties
+ persistenceCmHandle.id = cmHandleId
+ mockCmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId) >> persistenceCmHandle
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
new file mode 100644
index 0000000..3ab9266
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
@@ -0,0 +1,44 @@
+package org.onap.cps.ncmp.api.impl.operations
+
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.ncmp.api.models.PersistenceCmHandle
+import spock.lang.Shared
+
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import org.onap.cps.spi.model.DataNode
+import spock.lang.Specification
+
+class PersistenceCmHandleRetrieverSpec extends Specification {
+
+ def mockCpsDataService = Mock(CpsDataService)
+
+ def objectUnderTest = new PersistenceCmHandleRetriever(mockCpsDataService)
+
+ def cmHandleId = 'some cm handle'
+ def leaves = ["dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
+ def xpath = "/dmi-registry/cm-handles[@id='some cm handle']"
+
+ @Shared
+ def childDataNodesForCmHandleProperties = [new DataNode(leaves: ["name":"name1","value":"value1"]),
+ new DataNode(leaves: ["name":"name2","value":"value2"])]
+
+ def "Retrieve CmHandle using datanode #scenario."() {
+ given: 'the cps data service returns a data node from the dmi registry'
+ def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'retrieving the persisted cm handle'
+ def result = objectUnderTest.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId)
+ then: 'the result has the correct id and service names'
+ result.id == cmHandleId
+ result.dmiServiceName == 'common service name'
+ result.dmiDataServiceName == 'data service name'
+ result.dmiModelServiceName == 'model service name'
+ and: 'the expected additional properties'
+ result.additionalProperties == expectedCmHandleProperties
+ where: 'the following parameters are used'
+ scenario | childDataNodes || expectedCmHandleProperties
+ 'without additional properties' | [] || []
+ 'with additional properties' | childDataNodesForCmHandleProperties || [new PersistenceCmHandle.AdditionalProperty("name1", "value1"),
+ new PersistenceCmHandle.AdditionalProperty("name2", "value2")]
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
index bfed795..c66eaa9 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
@@ -21,13 +21,15 @@
import spock.lang.Specification
-class PersistenceCmHandleSpec extends Specification {
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL
- def objectUnderTest = new PersistenceCmHandle()
+class PersistenceCmHandleSpec extends Specification {
def 'Setting and getting additional properties.'() {
given: 'a map of one property is added'
- objectUnderTest.setAdditionalProperties([myProperty: 'some value'])
+ def objectUnderTest = new PersistenceCmHandle()
+ objectUnderTest.asAdditionalProperties([myProperty: 'some value'])
when: 'the additional properties are retrieved'
def result = objectUnderTest.getAdditionalProperties()
then: 'the result has the right size'
@@ -39,4 +41,23 @@
assert actualAdditionalProperty.value == expectedAdditionalProperty.value
}
+ def 'Resolve dmi service name: #scenario and #requiredService service require.'() {
+ given: 'a Persistence CM Handle'
+ def objectUnderTest = PersistenceCmHandle.toPersistenceCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new CmHandle('some id', null))
+ expect:
+ assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
+ where:
+ scenario | dmiServiceName | dmiDataServiceName | dmiModelServiceName | requiredService || expectedService
+ 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | DATA || 'common service'
+ 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | MODEL || 'common service'
+ 'common service empty' | '' | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service empty' | '' | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'common service blank' | ' ' | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service blank' | ' ' | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'common service null ' | null | 'data service' | 'does not matter' | DATA || 'data service'
+ 'common service null' | null | 'does not matter' | 'model service' | MODEL || 'model service'
+ 'only model service registered' | null | null | 'does not matter' | DATA || null
+ 'only data service registered' | null | 'does not matter' | null | MODEL || null
+ }
+
}
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
index 71ac2c9..d8fbb64 100644
--- a/cps-ncmp-service/src/test/resources/application.yml
+++ b/cps-ncmp-service/src/test/resources/application.yml
@@ -20,4 +20,6 @@
auth:
username: some-user
password: some-password
+ api:
+ base-path: /dmi