diff options
Diffstat (limited to 'cps-ncmp-service/src')
18 files changed, 246 insertions, 208 deletions
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 0c8474839b..4230140d26 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 @@ -59,6 +59,7 @@ public interface NetworkCmProxyDataService { * @param optionsParamInQuery options query * @param topicParamInQuery topic name for (triggering) async responses * @param requestId unique requestId for async request + * @param authorization contents of Authorization header, or null if not present * @return {@code Object} resource data */ Object getResourceDataForCmHandle(String datastoreName, @@ -66,7 +67,8 @@ public interface NetworkCmProxyDataService { String resourceIdentifier, String optionsParamInQuery, String topicParamInQuery, - String requestId); + String requestId, + String authorization); /** * Get resource data for operational. @@ -87,10 +89,13 @@ public interface NetworkCmProxyDataService { * * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest contains a list of operation definitions(multiple operations) + * @param requestId request ID + * @param authorization contents of Authorization header, or null if not present */ void executeDataOperationForCmHandles(String topicParamInQuery, DataOperationRequest dataOperationRequest, - String requestId); + String requestId, + String authorization); /** @@ -101,13 +106,15 @@ public interface NetworkCmProxyDataService { * @param operationType required operation type * @param requestBody request body to create resource * @param contentType content type in body + * @param authorization contents of Authorization header, or null if not present * @return {@code Object} return data */ Object writeResourceDataPassThroughRunningForCmHandle(String cmHandleId, String resourceIdentifier, OperationType operationType, String requestBody, - String contentType); + String contentType, + String authorization); /** * Retrieve module references for the given cm handle. 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 ab83486bd7..4c905bf90f 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 @@ -51,7 +51,6 @@ import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; @@ -85,7 +84,6 @@ import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -104,7 +102,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; private final CpsDataService cpsDataService; private final IMap<String, Object> moduleSyncStartedOnCmHandles; - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; private final TrustLevelManager trustLevelManager; private final AlternateIdChecker alternateIdChecker; @@ -135,12 +132,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final String requestId) { + final String requestId, + final String authorization) { final ResponseEntity<?> responseEntity = dmiDataOperations.getResourceDataFromDmi(datastoreName, cmHandleId, resourceIdentifier, optionsParamInQuery, topicParamInQuery, - requestId); + requestId, + authorization); return responseEntity.getBody(); } @@ -155,10 +154,11 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService @Override public void executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest, - final String requestId) { - dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId); + final DataOperationRequest dataOperationRequest, + final String requestId, + final String authorization) { + dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId, + authorization); } @Override @@ -166,9 +166,10 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final String resourceIdentifier, final OperationType operationType, final String requestData, - final String dataType) { + final String dataType, + final String authorization) { return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier, - operationType, requestData, dataType); + operationType, requestData, dataType, authorization); } @Override @@ -423,7 +424,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final List<NcmpServiceCmHandle> cmHandlesToBeCreated, final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) { final Collection<String> rejectedCmHandleIds = alternateIdChecker - .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated); + .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE); cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses( rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED)); return rejectedCmHandleIds; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java index f5d22af281..3d15291633 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID; import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.DMI_PROPERTY; @@ -46,8 +47,6 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; -import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; @@ -70,67 +69,76 @@ public class NetworkCmProxyDataServicePropertyHandler { private final AlternateIdChecker alternateIdChecker; /** - * Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes. + * Iterates over incoming updatedNcmpServiceCmHandles and update the dataNodes based on the updated attributes. * The attributes which are not passed will remain as is. * - * @param ncmpServiceCmHandles collection of ncmpServiceCmHandles + * @param updatedNcmpServiceCmHandles collection of CmHandles */ public List<CmHandleRegistrationResponse> updateCmHandleProperties( - final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) { - final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses - = new ArrayList<>(ncmpServiceCmHandles.size()); - for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) { - final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); - try { - final DataNode existingCmHandleDataNode = inventoryPersistence - .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); - updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle); - processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle); - cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); - } catch (final DataNodeNotFoundException e) { - log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); - } catch (final DataValidationException e) { - log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); - } catch (final Exception exception) { - log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + final Collection<NcmpServiceCmHandle> updatedNcmpServiceCmHandles) { + final Collection<String> rejectedCmHandleIds = alternateIdChecker + .getIdsOfCmHandlesWithRejectedAlternateId(updatedNcmpServiceCmHandles, AlternateIdChecker.Operation.UPDATE); + final List<CmHandleRegistrationResponse> failureResponses = + CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED); + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failureResponses); + for (final NcmpServiceCmHandle updatedNcmpServiceCmHandle : updatedNcmpServiceCmHandles) { + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + if (!rejectedCmHandleIds.contains(cmHandleId)) { + try { + final DataNode existingCmHandleDataNode = inventoryPersistence + .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); + processUpdates(existingCmHandleDataNode, updatedNcmpServiceCmHandle); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); + } catch (final DataNodeNotFoundException e) { + log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, + e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); + } catch (final DataValidationException e) { + log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); + } catch (final Exception exception) { + log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + } } } return cmHandleRegistrationResponses; } - private void updateAlternateId(final DataNode existingCmHandleDataNode, - final NcmpServiceCmHandle ncmpServiceCmHandle) { - final YangModelCmHandle yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode); - final String currentAlternateId = yangModelCmHandle.getAlternateId(); - final String newAlternateId = ncmpServiceCmHandle.getAlternateId(); - if (alternateIdChecker.canApplyAlternateId(ncmpServiceCmHandle.getCmHandleId(), - currentAlternateId, newAlternateId)) { - setAndUpdateAlternateId(yangModelCmHandle, newAlternateId); + private void processUpdates(final DataNode existingCmHandleDataNode, + final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + updateAlternateId(updatedNcmpServiceCmHandle); + if (!updatedNcmpServiceCmHandle.getPublicProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, + updatedNcmpServiceCmHandle.getPublicProperties()); + } + if (!updatedNcmpServiceCmHandle.getDmiProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, DMI_PROPERTY, updatedNcmpServiceCmHandle.getDmiProperties()); } } - private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) { - if (!incomingCmHandle.getPublicProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, incomingCmHandle.getPublicProperties()); - } - if (!incomingCmHandle.getDmiProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, DMI_PROPERTY, incomingCmHandle.getDmiProperties()); - } + private void updateAlternateId(final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + final String updatedAlternateId = updatedNcmpServiceCmHandle.getAlternateId(); + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + final Map<String, String> cmHandleProperties = new HashMap<>(2); + cmHandleProperties.put("id", cmHandleId); + cmHandleProperties.put("alternate-id", updatedAlternateId); + final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); + dmiRegistryProperties.put("cm-handles", cmHandleProperties); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, + jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); + log.debug("Updating alternateId for cmHandle {} with value : {})", cmHandleId, updatedAlternateId); } private void updateProperties(final DataNode existingCmHandleDataNode, final PropertyType propertyType, - final Map<String, String> incomingProperties) { + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = - getReplacementDataNodes(existingCmHandleDataNode, propertyType, incomingProperties); + getReplacementDataNodes(existingCmHandleDataNode, propertyType, updatedProperties); replacementPropertyDataNodes.addAll( - getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, incomingProperties)); + getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, updatedProperties)); if (replacementPropertyDataNodes.isEmpty()) { removeAllProperties(existingCmHandleDataNode, propertyType); } else { @@ -149,13 +157,14 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getUnchangedPropertyDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> unchangedPropertyDataNodes = new HashSet<>(); for (final DataNode existingPropertyDataNode : existingCmHandleDataNode.getChildDataNodes()) { final Matcher matcher = propertyType.propertyXpathPattern.matcher(existingPropertyDataNode.getXpath()); if (matcher.find()) { final String keyName = matcher.group(2); - if (!incomingProperties.containsKey(keyName)) { + if (!updatedProperties.containsKey(keyName)) { unchangedPropertyDataNodes.add(existingPropertyDataNode); } } @@ -164,9 +173,10 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getReplacementDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = new HashSet<>(); - incomingProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { + updatedProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { final String propertyXpath = getAttributeXpath(existingCmHandleDataNode, propertyType, updatedAttributeKey); if (updatedAttributeValue != null) { log.info("Creating a new DataNode with xpath {} , key : {} and value : {}", propertyXpath, @@ -179,7 +189,7 @@ public class NetworkCmProxyDataServicePropertyHandler { } private String getAttributeXpath(final DataNode cmHandle, final PropertyType propertyType, - final String attributeKey) { + final String attributeKey) { return cmHandle.getXpath() + "/" + propertyType.xpathPrefix + String.format("[@name='%s']", attributeKey); } @@ -192,17 +202,6 @@ public class NetworkCmProxyDataServicePropertyHandler { return new DataNodeBuilder().withXpath(xpath).withLeaves(ImmutableMap.copyOf(updatedLeaves)).build(); } - private void setAndUpdateAlternateId(final YangModelCmHandle upgradedCmHandle, final String alternateId) { - final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); - final Map<String, String> cmHandleProperties = new HashMap<>(2); - cmHandleProperties.put("id", upgradedCmHandle.getId()); - cmHandleProperties.put("alternate-id", alternateId); - dmiRegistryProperties.put("cm-handles", cmHandleProperties); - cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, - jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); - log.info("Updating alternateId for cmHandle {} with value : {})", upgradedCmHandle.getId(), alternateId); - } - enum PropertyType { DMI_PROPERTY("additional-properties"), PUBLIC_PROPERTY("public-properties"); 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 5b93eb4853..798a280c8a 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 @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl.client; import com.fasterxml.jackson.databind.JsonNode; +import java.util.Locale; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties; @@ -51,12 +52,15 @@ public class DmiRestClient { * @param dmiResourceUrl dmi resource url * @param requestBodyAsJsonString json data body * @param operationType the type of operation being executed (for error reporting only) + * @param authorization contents of Authorization header, or null if not present * @return response entity of type String */ public ResponseEntity<Object> postOperationWithJsonData(final String dmiResourceUrl, final String requestBodyAsJsonString, - final OperationType operationType) { - final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders())); + final OperationType operationType, + final String authorization) { + final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders(), + authorization)); try { return restTemplate.postForEntity(dmiResourceUrl, httpEntity, Object.class); } catch (final HttpStatusCodeException httpStatusCodeException) { @@ -73,7 +77,7 @@ public class DmiRestClient { * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception) */ public String getDmiHealthStatus(final String dmiPluginBaseUrl) { - final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders())); + final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders(), null)); try { final JsonNode responseHealthStatus = restTemplate.getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION, @@ -86,9 +90,11 @@ public class DmiRestClient { } } - private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders) { + private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) { if (dmiProperties.isDmiBasicAuthEnabled()) { httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword()); + } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) { + httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization); } httpHeaders.setContentType(MediaType.APPLICATION_JSON); return httpHeaders; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java index f12cc9c822..171db52998 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java @@ -30,10 +30,6 @@ import org.springframework.context.annotation.Configuration; @Configuration public class TrustLevelCacheConfig extends HazelcastCacheConfig { - public static final String TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME = "trustLevelPerDmiPlugin"; - - public static final String TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME = "trustLevelPerCmHandle"; - private static final MapConfig trustLevelPerCmHandleCacheConfig = createMapConfig("trustLevelPerCmHandleCacheConfig"); @@ -45,7 +41,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of cm handle name as keys to trust-level for values. */ - @Bean(TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) + @Bean public Map<String, TrustLevel> trustLevelPerCmHandle() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", trustLevelPerCmHandleCacheConfig).getMap("trustLevelPerCmHandle"); @@ -56,7 +52,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of dmi-plugin name as keys to trust-level for values. */ - @Bean(TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) + @Bean public Map<String, TrustLevel> trustLevelPerDmiPlugin() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", trustLevelPerDmiPluginCacheConfig).getMap("trustLevelPerDmiPlugin"); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java index a43da294c1..2d7ad698c5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java @@ -34,14 +34,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.utils.CpsValidator; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @RequiredArgsConstructor @@ -51,11 +49,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries { private static final String DESCENDANT_PATH = "//"; private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles"; private final CpsDataPersistenceService cpsDataPersistenceService; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; private final CpsValidator cpsValidator; 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 index fa18767dbe..a77e78a2e2 100644 --- 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 @@ -79,6 +79,7 @@ public class DmiDataOperations extends DmiOperations { * @param optionsParamInQuery options query * @param topicParamInQuery topic name for (triggering) async responses * @param requestId requestId for async responses + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ @Timed(value = "cps.ncmp.dmi.get", @@ -89,7 +90,8 @@ public class DmiDataOperations extends DmiOperations { final String resourceId, final String optionsParamInQuery, final String topicParamInQuery, - final String requestId) { + final String requestId, + final String authorization) { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); @@ -97,7 +99,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle); final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, resourceId, optionsParamInQuery, topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); - return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization); } /** @@ -120,7 +122,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); - return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null); } /** @@ -130,10 +132,12 @@ public class DmiDataOperations extends DmiOperations { * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest data operation request to execute operations * @param requestId requestId for as a response + * @param authorization contents of Authorization header, or null if not present */ public void requestResourceDataFromDmi(final String topicParamInQuery, final DataOperationRequest dataOperationRequest, - final String requestId) { + final String requestId, + final String authorization) { final Set<String> cmHandlesIds = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest); @@ -145,7 +149,8 @@ public class DmiDataOperations extends DmiOperations { = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery, requestId, dataOperationRequest, yangModelCmHandles); - buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName); + buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName, + authorization); } /** @@ -157,13 +162,15 @@ public class DmiDataOperations extends DmiOperations { * @param operationType operation enum * @param requestData the request data * @param dataType data type + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleId, final String resourceId, final OperationType operationType, final String requestData, - final String dataType) { + final String dataType, + final String authorization) { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType, yangModelCmHandle); @@ -172,7 +179,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); - return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType); + return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization); } private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { @@ -234,23 +241,26 @@ public class DmiDataOperations extends DmiOperations { private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery, final String requestId, final Map<String, List<DmiDataOperation>> - groupsOutPerDmiServiceName) { + groupsOutPerDmiServiceName, + final String authorization) { groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> { final String dmiDataOperationResourceUrl = getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId); - sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies); + sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies, + authorization); }); } private void sendDataOperationRequestToDmiService(final String dataOperationResourceUrl, - final List<DmiDataOperation> dmiDataOperationRequestBodies) { + final List<DmiDataOperation> dmiDataOperationRequestBodies, + final String authorization) { final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder() .operations(dmiDataOperationRequestBodies).build(); final String dmiDataOperationRequestAsJsonString = jsonObjectMapper.asJsonString(dmiDataOperationRequest); TaskExecutor.executeTask(() -> dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, - dmiDataOperationRequestAsJsonString, READ), + dmiDataOperationRequestAsJsonString, READ, authorization), DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS) .whenCompleteAsync((response, throwable) -> handleTaskCompletionException(throwable, dataOperationResourceUrl, dmiDataOperationRequestBodies)); 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 index dbe386d7ca..f99fe86f66 100644 --- 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 @@ -112,7 +112,7 @@ public class DmiModelOperations extends DmiOperations { final String resourceName) { final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName); return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, - OperationType.READ); + OperationType.READ, null); } private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java index 4c606a9c01..82c7204028 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java @@ -24,12 +24,10 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Slf4j @@ -37,12 +35,8 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class TrustLevelManager { - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; - private final InventoryPersistence inventoryPersistence; private final AvcEventPublisher avcEventPublisher; private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java index 78eaf3e6bf..72dc295bf3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java @@ -26,10 +26,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -40,10 +38,7 @@ public class DmiPluginWatchDog { private final DmiRestClient dmiRestClient; private final NetworkCmProxyDataService networkCmProxyDataService; - private final TrustLevelManager trustLevelManager; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java index 4ac6537494..f14439f690 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java @@ -38,6 +38,10 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class AlternateIdChecker { + public enum Operation { + CREATE, UPDATE + } + private final InventoryPersistence inventoryPersistence; private static final String NO_CURRENT_ALTERNATE_ID = ""; @@ -96,15 +100,16 @@ public class AlternateIdChecker { } /** - * Check all alternate ids of a batch of NEW cm handles. + * Check all alternate ids of a batch of cm handles. * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted. - * This method can only be used for NEW cm handle registrations NOT for updating existing ones * * @param newNcmpServiceCmHandles the proposed new cm handles + * @param operation type of operation being executed * @return collection of cm handles ids which are acceptable */ public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId( - final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) { + final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles, + final Operation operation) { final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size()); final Collection<String> rejectedCmHandleIds = new ArrayList<>(); for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) { @@ -119,7 +124,11 @@ public class AlternateIdChecker { log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already " + "assigned to a different cm handle (in this batch)", cmHandleId); } else { - isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + if (Operation.CREATE.equals(operation)) { + isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + } else { + isAcceptable = canApplyAlternateId(cmHandleId, proposedAlternateId); + } } } if (isAcceptable) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index cb7e1ef8a9..fbfbac59e0 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -78,7 +78,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def setup() { // always accept all cm handles - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] // always can find all cm handles in DB mockInventoryPersistence.getYangModelCmHandles(_) >> { args -> args[0].collect { new YangModelCmHandle(id:it) } } @@ -418,14 +418,4 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' } - def 'Adding data to alternate id caches.'() { - given: 'a registration with three CM Handles to be created' - def ncmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')] - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', createdCmHandles: ncmpServiceCmHandles) - when: 'the DMI plugin registration happens' - objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'the new alternate id is added to the cache' - 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] - } - } 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 9b4fe146b9..74016e4c0c 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 @@ -86,6 +86,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def NO_TOPIC = null def NO_REQUEST_ID = null + def NO_AUTH_HEADER = null def OPTIONS_PARAM = '(a=1,b=2)' def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id') @@ -113,10 +114,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'write resource data is called' objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', CREATE, - '{some-json}', 'application/json') + '{some-json}', 'application/json', null) then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - CREATE, '{some-json}', 'application/json') + CREATE, '{some-json}', 'application/json', null) >> { new ResponseEntity<>(HttpStatus.CREATED) } } @@ -124,10 +125,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' mockDataNode() and: 'get resource data from DMI is called' - mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> new ResponseEntity<>('dmi-response', HttpStatus.OK) when: 'get resource data operational for cm-handle is called' - def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'DMI returns a json response' assert response == 'dmi-response' } @@ -136,10 +137,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' mockDataNode() and: 'DMI returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) when: 'get resource data is called' - def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'get resource data returns expected response' assert response == '{dmi-response}' } @@ -157,9 +158,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' def dataOperationRequest = getDataOperationRequest(datastoreName) when: 'request resource data for data operation is called' - objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId') + objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'request resource data for data operation returns expected response' - 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId') + 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) where: 'the following data stores are used' datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName] } @@ -259,10 +260,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'get resource data is called' objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', UPDATE, - '{some-json}', 'application/json') + '{some-json}', 'application/json', NO_AUTH_HEADER) then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - UPDATE, '{some-json}', 'application/json') + UPDATE, '{some-json}', 'application/json', NO_AUTH_HEADER) >> { new ResponseEntity<>(HttpStatus.OK) } } @@ -273,7 +274,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle] mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle] and: 'no rejected cm handles because of alternate ids' - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] when: 'parse and create cm handle in dmi registration then sync module' mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id'] objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse()) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy index e00a42674b..cbed4177bd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy @@ -49,6 +49,12 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def mockAlternateIdChecker = Mock(AlternateIdChecker) def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker) + + def setup() { + // Always accept all alternate IDs + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] + } + def static cmHandleId = 'myHandle1' def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']" @@ -66,7 +72,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { when: 'update data node leaves is called with the update request' objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) then: 'the replace list method is called with correct params' - 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) >> { args -> + 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) >> { args -> { assert args[1].leaves.size() == expectedPropertiesAfterUpdate.size() assert args[1].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate)) @@ -142,10 +148,10 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == expectedErrorText } where: - scenario | cmHandleId | exception || expectedError | expectedErrorText - 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' - 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' - 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' + scenario | cmHandleId | exception || expectedError | expectedErrorText + 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' + 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' + 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' } def 'Multiple update operations in a single request'() { @@ -177,42 +183,44 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == 'cm handle id(s) not found' } then: 'the replace list method is called twice' - 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) + 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) } - def 'Update CM Handle Alternate ID with #scenario'() { - given: 'an existing cm handle' - DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId]) - and: 'an update request with an alternate id' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') - when: 'update alternate id method is called with the update request' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the update node leaves method is invoked as many times as expected' - callsToDataService * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> + def 'Update alternate id of existing CM Handle.'() { + given: 'cm handles request' + def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'cm handle properties is updated' + def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'the update is delegated to cps data service with correct parameters' + 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> { args -> assert args[3].contains('alt-1') } - mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping - where: 'following updates are attempted' - scenario | isNewMapping || callsToDataService - 'new alternate id ' | true || 1 - 'existing alternate id' | false || 0 + and: 'one successful registration response' + response.size() == 1 + and: 'the response shows success for the given cm handle id' + assert response[0].status == Status.SUCCESS + assert response[0].cmHandle == cmHandleId } - def 'Alternate ID removed from cache when persisting fails.'() { - given: 'an existing data node and an update request with an alternate id' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') - DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': null]) - and: 'an applicable alternate id for the cm handle' - mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> true - and: 'but an exception occurs while saving' - def originalException = new NullPointerException('some exception') - mockCpsDataService.updateNodeLeaves(*_) >> { throw originalException } - when: 'updating of alternate id called' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the original exception is thrown up' - def thrownException = thrown(NullPointerException) - assert thrownException == originalException + def 'Update with rejected alternate id.'() { + given: 'cm handles request' + def updatedNcmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'attempt to update the cm handle' + def response = objectUnderTest.updateCmHandleProperties(updatedNcmpServiceCmHandles) + then: 'the update is NOT delegated to cps data service' + 0 * mockCpsDataService.updateNodeLeaves(*_) + and: 'the alternate id checker rejects the given cm handle (override default setup behavior)' + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [cmHandleId] + and: 'the response shows a failure for the given cm handle id' + assert response[0].status == Status.FAILURE + assert response[0].cmHandle == cmHandleId } def convertToProperties(expectedPropertiesAfterUpdateAsMap) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy index 0176de7147..c8e34b1a5e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy @@ -48,6 +48,10 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE @ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper]) class DmiRestClientSpec extends Specification { + static final NO_AUTH_HEADER = null + static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ=' + static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token' + @SpringBean RestTemplate mockRestTemplate = Mock(RestTemplate) @@ -66,7 +70,7 @@ class DmiRestClientSpec extends Specification { given: 'the rest template returns a valid response entity for the expected parameters' mockRestTemplate.postForEntity('my url', _ as HttpEntity, Object.class) >> responseFromRestTemplate when: 'POST operation is invoked' - def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ) + def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ, null) then: 'the output of the method is equal to the output from the test template' result == responseFromRestTemplate } @@ -77,7 +81,7 @@ class DmiRestClientSpec extends Specification { def httpServerErrorException = new HttpServerErrorException(HttpStatus.FORBIDDEN, 'status text', serverResponse, null) mockRestTemplate.postForEntity(*_) >> { throw httpServerErrorException } when: 'POST operation is invoked' - def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation) + def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation, null) then: 'a Http Client Exception is thrown' def thrown = thrown(HttpClientRequestException) and: 'the exception has the relevant details from the error response' @@ -113,15 +117,20 @@ class DmiRestClientSpec extends Specification { 'exception' | {throw new Exception()} } - def 'Basic auth header #scenario'() { + def 'DMI auth header #scenario'() { when: 'Specific dmi properties are provided' dmiProperties.dmiBasicAuthEnabled = authEnabled then: 'http headers to conditionally have Authorization header' - assert (objectUnderTest.configureHttpHeaders(new HttpHeaders()).get('Authorization') != null) == isPresentInHttpHeader + def authHeaderValues = objectUnderTest.configureHttpHeaders(new HttpHeaders(), ncmpAuthHeader).getOrEmpty('Authorization') + def outputAuthHeader = (authHeaderValues == null ? null : authHeaderValues[0]) + assert outputAuthHeader == expectedAuthHeader where: 'the following configurations are used' - scenario | authEnabled || isPresentInHttpHeader - 'auth enabled' | true || true - 'auth disabled' | false || false + scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader + 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER + 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER + 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER } } 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 index 2229b32b0c..7d8ac7485b 100644 --- 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 @@ -59,6 +59,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def dmiServiceBaseUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:" def NO_TOPIC = null def NO_REQUEST_ID = null + def NO_AUTH_HEADER = null @Shared def OPTIONS_PARAM = '(a=1,b=2)' @@ -77,11 +78,11 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK) def expectedUrl = dmiServiceBaseUrl + "${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}" - mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' def result = objectUnderTest.getResourceDataFromDmi(dataStore.datastoreName, cmHandleId, resourceIdentifier, - options, NO_TOPIC, NO_REQUEST_ID) + options, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'the result is the response from the DMI service' assert result == responseFromDmi where: 'the following parameters are used' @@ -104,16 +105,16 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity<Object>(HttpStatus.ACCEPTED) def expectedDmiBatchResourceDataUrl = "ncmp/v1/data/topic=my-topic-name" def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","cmHandleProperties":{"prop1":"val1"}}]}]}' - mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName, NO_AUTH_HEADER) >> responseFromDmi dmiServiceUrlBuilder.getDataOperationRequestUrl(_, _) >> expectedDmiBatchResourceDataUrl and: ' a flag to track the post operation call' def postOperationWithJsonDataMethodCalled = false and: 'the (mocked) dmi rest client will use the flag to indicate it is called and capture the request body' - mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ) >> { + mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, null) >> { postOperationWithJsonDataMethodCalled = true } when: 'get resource data for group of cm handles are invoked' - objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId') + objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'validate the post operation was called and ncmp generated dmi request body json args' new PollingConditions().within(1) { assert postOperationWithJsonDataMethodCalled == true @@ -148,7 +149,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK) def expectedUrl = dmiServiceBaseUrl + "passthrough-operational?resourceIdentifier=/" - mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ, null) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' def result = objectUnderTest.getResourceDataFromDmi( PASSTHROUGH_OPERATIONAL.datastoreName, cmHandleId, NO_REQUEST_ID) @@ -164,9 +165,9 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}' def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK) dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl - mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi when: 'write resource method is invoked' - def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type') + def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER) then: 'the result is the response from the DMI service' assert result == responseFromDmi where: 'the following operation is performed' 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 index a105f84ebe..ae17c56ef3 100644 --- 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 @@ -51,6 +51,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { @SpringBean JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + def NO_AUTH_HEADER = null + def 'Retrieving module references.'() { given: 'a cm handle' mockYangModelCmHandleRetrieval([]) @@ -58,7 +60,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']] def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules" def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK) - mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{}}', READ) + mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) @@ -91,7 +93,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { 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 + '}', READ) >> responseFromDmi + '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'a get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) then: 'the result is the response from DMI service' @@ -110,7 +112,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK) def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}' mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ) >> responseFromDmi + '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)' @@ -142,7 +144,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi + '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', + READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) then: 'the result is the response from DMI service' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy index aaa034437c..0eabaa1d28 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy @@ -20,7 +20,6 @@ package org.onap.cps.ncmp.api.impl.utils - import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle @@ -68,25 +67,41 @@ class AlternateIdCheckerSpec extends Specification { 'other alternate id' || false } - def 'Check a batch of NEW cm handles with #scenario.'() { + def 'Check a batch of created cm handles with #scenario.'() { given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2' def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1), new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)] - and: 'the database already contains cm handle(s) with these alternate ids: #alreadyinDb' + and: 'the database already contains cm handle(s) with these alternate ids: #altAlreadyInDb' mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } when: 'the batch of new cm handles is checked' - def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch) - then: 'the result only contains the ids of the acceptable cm handles' - assert result.contains('ch-1') == rejectCh1 - assert result.contains('ch-2') == rejectCh2 + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.CREATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds where: 'the following alternate ids are used' - scenario | alt1 | alt2 | altAlreadyInDb || rejectCh1 | rejectCh2 - 'no alternate ids' | '' | '' | ['dont matter'] || false | false - 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || false | false - 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || true | false - 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || true | true - 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || false | true + scenario | alt1 | alt2 | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate ids' | '' | '' | ['dont matter'] || [] + 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || [] + 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || ['ch-1'] + 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2'] + } + + def 'Check a batch of updates to existing cm handles with #scenario.'() { + given: 'a batch of 1 existing cm handle update alternate id to #proposedAlt' + def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: proposedAlt)] + and: 'the database already contains a cm handle with alternate id: #altAlreadyInDb' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> + { args -> altAlreadyInDb.equals(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } + mockInventoryPersistenceService.getYangModelCmHandle(_) >> new YangModelCmHandle(alternateId: altAlreadyInDb) + when: 'the batch of cm handle updates is checked' + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds + where: 'the following parameters are used' + scenario | proposedAlt | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate id' | 'fdn1' | '' || [] + 'used the same alternate id' | 'fdn1' | 'fdn1' || [] + 'used different alternate id' | 'otherFdn' | 'fdn1' || ['ch-1'] } def throwDataNodeNotFoundException() { |