diff options
25 files changed, 480 insertions, 84 deletions
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml index 3f005c9f78..2b4dc4b7c7 100644 --- a/cps-application/src/main/resources/application.yml +++ b/cps-application/src/main/resources/application.yml @@ -1,6 +1,6 @@ # ============LICENSE_START=======================================================
# Copyright (C) 2021 Pantheon.tech
-# Modifications Copyright (C) 2021 Bell Canada
+# Modifications Copyright (C) 2021-2022 Bell Canada
# Modifications Copyright (C) 2021-2022 Nordix Foundation
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -157,4 +157,7 @@ dmi: timers:
advised-modules-sync:
- sleep-time-ms: 30000
\ No newline at end of file + sleep-time-ms: 30000
+
+ locked-modules-sync:
+ sleep-time-ms: 300000
\ No newline at end of file diff --git a/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json b/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json index 84fc12edbd..4ddffea56a 100644 --- a/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json +++ b/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json @@ -26,8 +26,7 @@ }, "eventSource": { "description": "The source of the event.", - "type": "string", - "format": "uri" + "type": "string" }, "eventType": { "description": "The type of the event.", @@ -35,8 +34,7 @@ }, "eventSchema": { "description": "The schema, including its version, that this event adheres to.", - "type": "string", - "format": "uri" + "type": "string" }, "event": { "$ref": "#/definitions/Event" diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index ccb1e9bbb8..fb234ef71a 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -211,6 +211,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @return collection of cm handles */ @Override + @SuppressWarnings("deprecation") // mapOldConditionProperties method will be removed in Release 12 public ResponseEntity<List<RestOutputCmHandle>> searchCmHandles( final CmHandleQueryParameters cmHandleQueryParameters) { final CmHandleQueryApiParameters cmHandleQueryApiParameters = diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java index fc992da41a..573491ca3f 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java @@ -40,9 +40,11 @@ public class DeprecationHelper { * !!! remove it after the old condition removed !!! * it only works for module names * + * @deprecated this method will be removed in Release 12 (No Name know yet) + * * @param cmHandleQueryParameters the original input parameter */ - @Deprecated //this method wil be removed in Release 12 (No Name know yet) + @Deprecated public CmHandleQueryApiParameters mapOldConditionProperties( final CmHandleQueryParameters cmHandleQueryParameters) { final CmHandleQueryApiParameters cmHandleQueryApiParameters = diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml index 99a024e65d..502e9824d7 100644 --- a/cps-ncmp-service/pom.xml +++ b/cps-ncmp-service/pom.xml @@ -3,6 +3,7 @@ ============LICENSE_START======================================================= Copyright (C) 2021-2022 Nordix Foundation Modifications Copyright (C) 2021 Pantheon.tech + Modifications Copyright (C) 2022 Bell Canada ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,10 +32,10 @@ </parent> <artifactId>cps-ncmp-service</artifactId> + <properties> - <minimum-coverage>0.93</minimum-coverage> + <minimum-coverage>0.96</minimum-coverage> </properties> - <dependencies> <dependency> <groupId>${project.groupId}</groupId> diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java index f8d51feba8..92b1e82c3e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java @@ -21,15 +21,15 @@ package org.onap.cps.ncmp.api; import java.util.Collection; -import org.onap.cps.spi.model.CmHandleQueryParameters; +import org.onap.cps.spi.model.CmHandleQueryServiceParameters; import org.onap.cps.spi.model.DataNode; public interface NetworkCmProxyCmHandlerQueryService { /** * Query and return cm handles that match the given query parameters. * - * @param cmHandleQueryParameters the cm handle query parameters + * @param cmHandleQueryServiceParameters the cm handle query parameters * @return collection of cm handles */ - Collection<DataNode> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters); + Collection<DataNode> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java index ef6e953e2f..00cbe69f54 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java @@ -37,7 +37,7 @@ import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.model.Anchor; -import org.onap.cps.spi.model.CmHandleQueryParameters; +import org.onap.cps.spi.model.CmHandleQueryServiceParameters; import org.onap.cps.spi.model.ConditionProperties; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DataNodeIdentifier; @@ -58,23 +58,23 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm /** * Query and return cm handles that match the given query parameters. * - * @param cmHandleQueryParameters the cm handle query parameters + * @param cmHandleQueryServiceParameters the cm handle query parameters * @return collection of cm handles */ @Override - public Collection<DataNode> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) { + public Collection<DataNode> queryCmHandles(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { - if (cmHandleQueryParameters.getCmHandleQueryParameters().isEmpty()) { + if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) { return getAllCmHandles(); } final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers = new ArrayList<>(); final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults = new HashMap<>(); - final boolean firstQuery = moduleNameQuery(cmHandleQueryParameters, + final boolean firstQuery = moduleNameQuery(cmHandleQueryServiceParameters, amalgamatedQueryResultIdentifiers, amalgamatedQueryResults); - publicPropertyQuery(cmHandleQueryParameters, amalgamatedQueryResultIdentifiers, + publicPropertyQuery(cmHandleQueryServiceParameters, amalgamatedQueryResultIdentifiers, amalgamatedQueryResults, firstQuery); final Collection<DataNode> filteredDataNodes = new ArrayList<>(); @@ -85,12 +85,12 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm return filteredDataNodes; } - private void publicPropertyQuery(final CmHandleQueryParameters cmHandleQueryParameters, + private void publicPropertyQuery(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers, final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults, boolean firstQuery) { for (final Map.Entry<String, String> entry : - getPublicPropertyPairs(cmHandleQueryParameters.getCmHandleQueryParameters()).entrySet()) { + getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters()).entrySet()) { final String cmHandlePath = "//public-properties[@name='" + entry.getKey() + "' " + "and @value='" + entry.getValue() + "']" + "/ancestor::cm-handles"; @@ -121,13 +121,13 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } } - private boolean moduleNameQuery(final CmHandleQueryParameters cmHandleQueryParameters, + private boolean moduleNameQuery(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers, final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults) { boolean firstQuery = true; - if (!getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters()).isEmpty()) { + if (!getModuleNames(cmHandleQueryServiceParameters.getCmHandleQueryParameters()).isEmpty()) { final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors("NFP-Operational", - getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters())); + getModuleNames(cmHandleQueryServiceParameters.getCmHandleQueryParameters())); anchors.forEach(anchor -> { final List<DataNode> dataNodes = getDataNodes("//cm-handles[@id='" + anchor.getName() + "']"); dataNodes.parallelStream().forEach(dataNode -> { 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 d1f72a5ef4..f8cab4f1ca 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 @@ -63,7 +63,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.exceptions.SchemaSetNotFoundException; -import org.onap.cps.spi.model.CmHandleQueryParameters; +import org.onap.cps.spi.model.CmHandleQueryServiceParameters; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.CpsValidator; import org.onap.cps.utils.JsonObjectMapper; @@ -167,12 +167,12 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService @Override public Set<NcmpServiceCmHandle> executeCmHandleSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) { - final CmHandleQueryParameters cmHandleQueryParameters = jsonObjectMapper.convertToValueType( - cmHandleQueryApiParameters, CmHandleQueryParameters.class); + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType( + cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); - validateCmHandleQueryParameters(cmHandleQueryParameters); + validateCmHandleQueryParameters(cmHandleQueryServiceParameters); - return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters).stream() + return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryServiceParameters).stream() .map(dataNode -> YangDataConverter .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString())) .map(YangDataConverter::convertYangModelCmHandleToNcmpServiceCmHandle).collect(Collectors.toSet()); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java new file mode 100644 index 0000000000..609306f08e --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java @@ -0,0 +1,90 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.event; + +import static org.onap.ncmp.cmhandle.lcm.event.Event.CmhandleState.READY; +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.lcm.event.Event; +import org.onap.ncmp.cmhandle.lcm.event.Event.Operation; +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; +import org.springframework.stereotype.Component; + + +/** + * NcmpEventsCreator to create NcmpEvent based on relevant operation. + */ +@Slf4j +@Component +public class NcmpEventsCreator { + + + /** + * Populate NcmpEvent. + * + * @param cmHandleId Cm Handle Identifier + * @param operation Relevant Operation + * @param ncmpServiceCmHandle Ncmp CmHandle Data + * @return Populated NcmpEvent + */ + public NcmpEvent populateNcmpEvent(final String cmHandleId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + return createNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle); + } + + private NcmpEvent createNcmpEvent(final String cmHandleId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + final NcmpEvent ncmpEvent = ncmpEventHeader(cmHandleId); + ncmpEvent.setEvent(ncmpEventPayload(cmHandleId, operation, ncmpServiceCmHandle)); + return ncmpEvent; + } + + private Event ncmpEventPayload(final String eventCorrelationId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + final Event event = new Event(); + event.setOperation(operation); + event.setCmHandleId(eventCorrelationId); + + if (!DELETE.equals(operation)) { + event.setCmhandleState(READY); + event.setCmhandleProperties(List.of(ncmpServiceCmHandle.getPublicProperties())); + } + return event; + } + + private NcmpEvent ncmpEventHeader(final String eventCorrelationId) { + final NcmpEvent ncmpEvent = new NcmpEvent(); + ncmpEvent.setEventId(UUID.randomUUID().toString()); + ncmpEvent.setEventCorrelationId(eventCorrelationId); + ncmpEvent.setEventTime(ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"))); + ncmpEvent.setEventSource("org.onap.ncmp"); + ncmpEvent.setEventType("org.onap.ncmp.cmhandle-lcm-event"); + ncmpEvent.setEventSchema("org.onap.ncmp:cmhandle-lcm-event:v1"); + return ncmpEvent; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java new file mode 100644 index 0000000000..045a67a104 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.event; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.lcm.event.Event.Operation; +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * NcmpEventService to map the event correctly and publish to the public topic. + */ + +@Slf4j +@Service +@RequiredArgsConstructor +public class NcmpEventsService { + + private final InventoryPersistence inventoryPersistence; + + private final NcmpEventsPublisher ncmpEventsPublisher; + + private final NcmpEventsCreator ncmpEventsCreator; + + @Value("${app.ncmp.events.topic:ncmp-events}") + private String topicName; + + /** + * Publish the NcmpEvent to the public topic. + * + * @param cmHandleId Cm Handle Id + * @param operation Relevant operation(CREATE,UPDATE or DELETE) + */ + public void publishNcmpEvent(final String cmHandleId, final Operation operation) { + + final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle( + inventoryPersistence.getYangModelCmHandle(cmHandleId)); + final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle); + ncmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent); + + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java index 2fc2dc5c1a..ce34154b9b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,6 +93,17 @@ public class InventoryPersistence { } /** + * Method to return cm handles from the cps path. + * + * @param cpsPath cps path for which the cmHandle is requested + * @return a list of cm handles + */ + public List<DataNode> getCmHandlesByCpsPath(final String cpsPath) { + return cpsDataPersistenceService.queryDataNodes( + NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cpsPath, FetchDescendantsOption.OMIT_DESCENDANTS); + } + + /** * This method retrieves DMI service name, DMI properties and the state for a given cm handle. * @param cmHandleId the id of the cm handle * @return yang model cm handle diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java index bcc7daa39d..dbc7dd4f2c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java @@ -1,6 +1,7 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +21,13 @@ package org.onap.cps.ncmp.api.inventory.sync; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.inventory.CmHandleState; import org.onap.cps.ncmp.api.inventory.CompositeState; +import org.onap.cps.ncmp.api.inventory.CompositeState.LockReason; import org.onap.cps.ncmp.api.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.inventory.LockReasonCategory; import org.springframework.scheduling.annotation.Scheduled; @@ -44,7 +47,7 @@ public class ModuleSyncWatchdog { /** * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'. */ - @Scheduled(fixedDelayString = "${timers.advised-modules-sync.sleep-time-ms}") + @Scheduled(fixedDelayString = "${timers.advised-modules-sync.sleep-time-ms:30000}") public void executeAdvisedCmHandlePoll() { YangModelCmHandle advisedCmHandle = syncUtils.getAnAdvisedCmHandle(); while (advisedCmHandle != null) { @@ -68,4 +71,20 @@ public class ModuleSyncWatchdog { log.debug("No Cm-Handles currently found in an ADVISED state"); } + /** + * Execute Cm Handle poll which changes the cm handle state from 'LOCKED' to 'ADVISED'. + */ + @Scheduled(fixedDelayString = "${timers.locked-modules-sync.sleep-time-ms:300000}") + public void executeLockedMisbehavingCmHandlePoll() { + final List<YangModelCmHandle> lockedMisbehavingCmHandles = syncUtils.getLockedMisbehavingCmHandles(); + for (final YangModelCmHandle lockedMisbehavingModelCmHandle: lockedMisbehavingCmHandles) { + final CompositeState updatedCompositeState = lockedMisbehavingModelCmHandle.getCompositeState(); + updatedCompositeState.setCmHandleState(CmHandleState.ADVISED); + updatedCompositeState.setLastUpdateTimeNow(); + updatedCompositeState.setLockReason(LockReason.builder() + .details(updatedCompositeState.getLockReason().getDetails()).build()); + log.debug("Locked misbehaving cm handle {} is being recycled", lockedMisbehavingModelCmHandle.getId()); + inventoryPersistence.saveCmHandleState(lockedMisbehavingModelCmHandle.getId(), updatedCompositeState); + } + } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java index a4f29de3e8..22eeabb0df 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +25,10 @@ import java.security.SecureRandom; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.inventory.CmHandleState; import org.onap.cps.ncmp.api.inventory.CompositeState; @@ -41,7 +44,6 @@ public class SyncUtils { private static final SecureRandom secureRandom = new SecureRandom(); - private final InventoryPersistence inventoryPersistence; private static final Pattern retryAttemptPattern = Pattern.compile("^Attempt #(\\d+) failed:"); @@ -64,6 +66,19 @@ public class SyncUtils { /** + * Query data nodes for cm handles with an "LOCKED" cm handle state with reason LOCKED_MISBEHAVING". + * + * @return a random yang model cm handle with an ADVISED state, return null if not found + */ + public List<YangModelCmHandle> getLockedMisbehavingCmHandles() { + final List<DataNode> lockedCmHandleAsDataNodeList = inventoryPersistence.getCmHandlesByCpsPath( + "//lock-reason[@reason=\"LOCKED_MISBEHAVING\"]/ancestor::cm-handles"); + return lockedCmHandleAsDataNodeList.stream() + .map(cmHandle -> YangDataConverter.convertCmHandleToYangModel(cmHandle, + cmHandle.getLeaves().get("id").toString())).collect(Collectors.toList()); + } + + /** * Update Composite State attempts counter and set new lock reason and details. * * @param lockReasonCategory lock reason category @@ -84,5 +99,4 @@ public class SyncUtils { .lockReasonCategory(lockReasonCategory).build()); } - } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy index a1ad9af191..b689097cc4 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy @@ -25,7 +25,7 @@ import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.model.Anchor -import org.onap.cps.spi.model.CmHandleQueryParameters +import org.onap.cps.spi.model.CmHandleQueryServiceParameters import org.onap.cps.spi.model.ConditionProperties import org.onap.cps.spi.model.DataNode import org.onap.cps.utils.JsonObjectMapper @@ -44,7 +44,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { def 'Retrieve cm handles with public properties when #scenario.'() { given: 'a condition property' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def conditionProperties = new ConditionProperties() conditionProperties.conditionName = 'hasAllProperties' conditionProperties.conditionParameters = publicProperties @@ -65,7 +65,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { def 'Retrieve cm handles with module names when #scenario.'() { given: 'a condition property' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def conditionProperties = new ConditionProperties() conditionProperties.conditionName = 'hasAllModules' conditionProperties.conditionParameters = moduleNames @@ -86,7 +86,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { def 'Retrieve cm handles with combined queries when #scenario.'() { given: 'condition properties' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def conditionProperties1 = new ConditionProperties() conditionProperties1.conditionName = 'hasAllProperties' conditionProperties1.conditionParameters = publicProperties @@ -111,7 +111,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { given: 'mock services' mockResponses() when: 'the service is invoked' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) then: 'the correct expected cm handles are returned' returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] 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 6ba2a2c276..d58fe6a7cd 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 @@ -33,7 +33,7 @@ import org.onap.cps.ncmp.api.models.DmiPluginRegistration import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService -import org.onap.cps.spi.model.CmHandleQueryParameters +import org.onap.cps.spi.model.CmHandleQueryServiceParameters import org.onap.cps.spi.model.ConditionProperties import spock.lang.Shared @@ -252,7 +252,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']] cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties] and: 'valid CmHandleQueryParameters input' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def conditionProperties = new ConditionProperties() conditionProperties.conditionName = 'hasAllModules' conditionProperties.conditionParameters = [[moduleName: 'module-name-1']] diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy new file mode 100644 index 0000000000..04eb0bf2bb --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.event + +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle +import spock.lang.Specification + +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.CREATE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.UPDATE + +class NcmpEventsCreatorSpec extends Specification { + + def objectUnderTest = new NcmpEventsCreator() + def cmHandleId = 'test-cm-handle' + + def 'Map the NcmpEvent for operation #operation'() { + given: 'NCMP cm handle details' + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeStateBuilder().withCmHandleState(CmHandleState.READY).build(), + publicProperties: ['publicProperty1': 'value1', 'publicProperty2': 'value2']) + when: 'the event is populated' + def result = objectUnderTest.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + and: 'event payload is mapped correctly' + assert result.event.operation == operation + assert result.event.cmhandleProperties.size() == cmHandlePropertiesListSize + assert result.event.cmhandleProperties[0] == cmHandleProperties + where: 'the following operations are used' + operation | cmHandlePropertiesListSize | cmHandleProperties + CREATE | 1 | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] + UPDATE | 1 | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] + DELETE | 0 | null + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy new file mode 100644 index 0000000000..9774235561 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.event + +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent +import spock.lang.Specification + +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.CREATE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.UPDATE + +class NcmpEventsServiceSpec extends Specification { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockNcmpEventsPublisher = Mock(NcmpEventsPublisher) + def mockNcmpEventsMapper = Mock(NcmpEventsCreator) + + def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsMapper) + + def 'Create and Publish event for #operation'() { + given: 'a cm handle id and operation and responses are mocked' + mockResponses('test-cm-handle-id', operation, 'test-topic') + when: 'service is called to publish ncmp event' + objectUnderTest.publishNcmpEvent('test-cm-handle-id', operation) + then: 'no exception is thrown' + noExceptionThrown() + where: 'for following operations' + operation << [CREATE, UPDATE, DELETE] + } + + def mockResponses(cmHandleId, operation, topicName) { + + def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, publicProperties: [new YangModelCmHandle.Property('publicProperty1', 'value1')], dmiProperties: []) + def ncmpEvent = new NcmpEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) + def ncmpServiceCmhandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle) + + mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + mockNcmpEventsMapper.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmhandle) >> ncmpEvent + mockNcmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent) >> {} + } + + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy index a2ebcb5d81..e6346cb024 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +28,7 @@ import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.DataNode +import org.onap.cps.spi.model.DataNodeBuilder import org.onap.cps.utils.JsonObjectMapper import spock.lang.Shared import spock.lang.Specification @@ -50,7 +52,7 @@ class InventoryPersistenceSpec extends Specification { def objectUnderTest = new InventoryPersistence(spiedJsonObjectMapper, mockCpsDataService, mockCpsDataPersistenceService) def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) + .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) 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"] @@ -88,7 +90,7 @@ class InventoryPersistenceSpec extends Specification { where: 'the following parameters are used' scenario | childDataNodes || expectedDmiProperties || expectedPublicProperties || expectedCompositeState 'no properties' | [] || [] || [] || null - 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null + 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null 'just DMI properties' | childDataNodesForCmHandleWithDMIProperties || [new YangModelCmHandle.Property("name1", "value1")] || [] || null 'just public properties' | childDataNodesForCmHandleWithPublicProperties || [] || [new YangModelCmHandle.Property("name2", "value2")] || null 'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED @@ -105,7 +107,7 @@ class InventoryPersistenceSpec extends Specification { def "Handling missing service names as null CPS-1043."() { given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes' - def dataNode = new DataNode(childDataNodes:[], leaves: ["cm-handle-state":"ADVISED"]) + def dataNode = new DataNode(childDataNodes:[], leaves: [:]) mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode when: 'retrieving the yang modelled cm handle' def result = objectUnderTest.getYangModelCmHandle(cmHandleId) @@ -121,7 +123,7 @@ class InventoryPersistenceSpec extends Specification { def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED']) and: 'cps data service returns a valid data node' mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', - '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode when: 'get cm handle state is invoked' def result = objectUnderTest.getCmHandleState(cmHandleId) then: 'result has returned the correct cm handle state' @@ -137,7 +139,7 @@ class InventoryPersistenceSpec extends Specification { then: 'update node leaves is invoked with the correct params' 1 * mockCpsDataService.replaceNodeTree('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime) where: 'the following states are used' - scenario | cmHandleState || expectedJsonData + scenario | cmHandleState || expectedJsonData 'READY' | CmHandleState.READY || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}' 'LOCKED' | CmHandleState.LOCKED || '{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}' } @@ -148,11 +150,25 @@ class InventoryPersistenceSpec extends Specification { and: 'cps data service returns a list of data nodes' def dataNodes = [new DataNode()] mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry', - '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> dataNodes + '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> dataNodes when: 'get cm handles by state is invoked' def result = objectUnderTest.getCmHandlesByState(cmHandleState) then: 'the returned result is a list of data nodes returned by cps data service' assert result == dataNodes } + def 'Retrieve cm handle by cps path '() { + given: 'a cm handle state to query based on the cps path' + def cmHandleDataNode = new DataNode(xpath: 'xpath', leaves: ['cm-handle-state': 'LOCKED']) + def cpsPath = '//cps-path' + and: 'cps data service returns a valid data node' + mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry', + cpsPath, OMIT_DESCENDANTS) + >> Arrays.asList(cmHandleDataNode) + when: 'get cm handles by cps path is invoked' + def result = objectUnderTest.getCmHandlesByCpsPath(cpsPath) + then: 'the returned result is a list of data nodes returned by cps data service' + assert result.contains(cmHandleDataNode) + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy index 97bea096a3..544f739c06 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState import org.onap.cps.ncmp.api.inventory.InventoryPersistence import org.onap.cps.ncmp.api.inventory.LockReasonCategory +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder import spock.lang.Specification class ModuleSyncSpec extends Specification { @@ -88,4 +90,16 @@ class ModuleSyncSpec extends Specification { } + def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles '() { + given: 'cm handles in an locked state' + def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED) + .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').build() + def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState) + and: 'sync utilities return a cm handle twice' + mockSyncUtils.getLockedMisbehavingCmHandles() >> [yangModelCmHandle, yangModelCmHandle] + when: 'module sync poll is executed' + objectUnderTest.executeLockedMisbehavingCmHandlePoll() + then: 'the first cm handle is updated to state "ADVISED" from "READY"' + 2 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState) + } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy index 7d67acccc3..15d1efe068 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,15 +25,12 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState import org.onap.cps.ncmp.api.inventory.InventoryPersistence import org.onap.cps.ncmp.api.inventory.LockReasonCategory -import org.onap.cps.spi.CpsDataPersistenceService -import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.DataNode import spock.lang.Shared import spock.lang.Specification class SyncUtilsSpec extends Specification{ - def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) def mockInventoryPersistence = Mock(InventoryPersistence) def objectUnderTest = new SyncUtils(mockInventoryPersistence) @@ -40,8 +38,6 @@ class SyncUtilsSpec extends Specification{ @Shared def dataNode = new DataNode(leaves: ['id': 'cm-handle-123']) - - def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() { given: 'the inventory persistence service returns a collection of data nodes' mockInventoryPersistence.getCmHandlesByState(CmHandleState.ADVISED) >> dataNodeCollection @@ -71,5 +67,15 @@ class SyncUtilsSpec extends Specification{ 'does not exist' | null || 'Attempt #1 failed: new error message' 'exists' | CompositeState.LockReason.builder().details("Attempt #2 failed: some error message").build() || 'Attempt #3 failed: new error message' } - + def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MISBEHAVING cm handle #scenario'() { + given: 'the cps (persistence service) returns a collection of data nodes' + mockInventoryPersistence.getCmHandlesByCpsPath( + '//lock-reason[@reason="LOCKED_MISBEHAVING"]/ancestor::cm-handles') >> [dataNode ] + when: 'get locked Misbehaving cm handle is called' + def result = objectUnderTest.getLockedMisbehavingCmHandles() + then: 'the returned cm handle collection is the correct size' + result.size() == 1 + and: 'the correct cm handle is returned' + result[0].id == 'cm-handle-123' + } } diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryServiceParameters.java index cf364db3a8..8dcf88b0eb 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java +++ b/cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryServiceParameters.java @@ -34,7 +34,7 @@ import lombok.Setter; @Getter @EqualsAndHashCode @JsonInclude(Include.NON_EMPTY) -public class CmHandleQueryParameters { +public class CmHandleQueryServiceParameters { @JsonProperty("cmHandleQueryParameters") @Valid private List<ConditionProperties> cmHandleQueryParameters = Collections.emptyList(); diff --git a/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java index c510a73af2..c3811eb485 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java +++ b/cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java @@ -27,7 +27,7 @@ import java.util.Map; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.onap.cps.spi.exceptions.DataValidationException; -import org.onap.cps.spi.model.CmHandleQueryParameters; +import org.onap.cps.spi.model.CmHandleQueryServiceParameters; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class CmHandleQueryRestParametersValidator { @@ -36,10 +36,11 @@ public class CmHandleQueryRestParametersValidator { /** * Validate cm handle query parameters. - * @param cmHandleQueryParameters name of data to be validated + * @param cmHandleQueryServiceParameters name of data to be validated */ - public static void validateCmHandleQueryParameters(final CmHandleQueryParameters cmHandleQueryParameters) { - cmHandleQueryParameters.getCmHandleQueryParameters().forEach( + public static void validateCmHandleQueryParameters( + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { + cmHandleQueryServiceParameters.getCmHandleQueryParameters().forEach( conditionApiProperty -> { if (Strings.isNullOrEmpty(conditionApiProperty.getConditionName())) { throwDataValidationException("Missing 'conditionName' - please supply a valid name."); @@ -54,27 +55,29 @@ public class CmHandleQueryRestParametersValidator { "Empty 'conditionsParameters' - please supply a valid condition parameter."); } conditionApiProperty.getConditionParameters().forEach( - conditionParameter -> { - if (conditionParameter.isEmpty()) { - throwDataValidationException( - "Empty 'conditionsParameter' - please supply a valid condition parameter."); - } - if (conditionParameter.size() > 1) { - throwDataValidationException("Too many name in one 'conditionsParameter' -" - + " please supply one name in one condition parameter."); - } - conditionParameter.forEach((key, value) -> { - if (Strings.isNullOrEmpty(key)) { - throwDataValidationException( - "Missing 'conditionsParameterName' - please supply a valid name."); - } - }); - } + CmHandleQueryRestParametersValidator::validateConditionParameter ); } ); } + private static void validateConditionParameter(final Map<String, String> conditionParameter) { + if (conditionParameter.isEmpty()) { + throwDataValidationException( + "Empty 'conditionsParameter' - please supply a valid condition parameter."); + } + if (conditionParameter.size() > 1) { + throwDataValidationException("Too many name in one 'conditionsParameter' -" + + " please supply one name in one condition parameter."); + } + conditionParameter.forEach((key, value) -> { + if (Strings.isNullOrEmpty(key)) { + throwDataValidationException( + "Missing 'conditionsParameterName' - please supply a valid name."); + } + }); + } + /** * Validate module name condition properties. * @param conditionProperty name of data to be validated diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy index def99e21f4..41fcb29edd 100755 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy @@ -26,7 +26,6 @@ import org.onap.cps.api.CpsDataService import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.Anchor -import org.onap.cps.spi.model.CmHandleQueryParameters import spock.lang.Specification import java.time.OffsetDateTime diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy index 645829b2a2..a9b04c1ced 100644 --- a/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy @@ -21,14 +21,14 @@ package org.onap.cps.utils import org.onap.cps.spi.exceptions.DataValidationException -import org.onap.cps.spi.model.CmHandleQueryParameters +import org.onap.cps.spi.model.CmHandleQueryServiceParameters import org.onap.cps.spi.model.ConditionProperties import spock.lang.Specification class CmHandleQueryRestParametersValidatorSpec extends Specification { def 'CM Handle Query validation: empty query.'() { given: 'a cm handle query' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() when: 'validator is invoked' CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters) then: 'data validation exception is not thrown' @@ -37,7 +37,7 @@ class CmHandleQueryRestParametersValidatorSpec extends Specification { def 'CM Handle Query validation: normal query.'() { given: 'a cm handle query' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def condition = new ConditionProperties() condition.conditionName = 'hasAllProperties' condition.conditionParameters = [[key1:'value1'],[key2:'value2']] @@ -50,7 +50,7 @@ class CmHandleQueryRestParametersValidatorSpec extends Specification { def 'CM Handle Query validation: #scenario.'() { given: 'a cm handle query' - def cmHandleQueryParameters = new CmHandleQueryParameters() + def cmHandleQueryParameters = new CmHandleQueryServiceParameters() def condition = new ConditionProperties() condition.conditionName = conditionName condition.conditionParameters = conditionParameters diff --git a/docs/release-notes.rst b/docs/release-notes.rst index a584b580a1..58dc060bbd 100755 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -12,12 +12,16 @@ CPS Release Notes :depth: 2 .. -.. ======================== -.. * * * JAKARTA * * * -.. ======================== +.. ==================== +.. * * * KOHN * * * +.. ==================== + +Version: 3.1.0 (not released yet) +================================= + +Release Data +------------ -Version: 3.1.0 -============== +--------------------------------------+--------------------------------------------------------+ | **CPS Project** | | | | | @@ -25,10 +29,10 @@ Version: 3.1.0 | **Docker images** | onap/cps-and-ncmp:3.1.0 | | | | +--------------------------------------+--------------------------------------------------------+ -| **Release designation** | 3.1.0 Jakarta | +| **Release designation** | 3.1.0 Kohn | | | | +--------------------------------------+--------------------------------------------------------+ -| **Release date** | | +| **Release date** | N/A | | | | +--------------------------------------+--------------------------------------------------------+ @@ -36,6 +40,34 @@ Features -------- - `CPS-322 <https://jira.onap.org/browse/CPS-322>`_ Implement additional validation for names and identifiers +.. ======================== +.. * * * JAKARTA * * * +.. ======================== + +Version: 3.0.1 +============== + +Release Data +------------ + ++--------------------------------------+--------------------------------------------------------+ +| **CPS Project** | | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Docker images** | onap/cps-and-ncmp:3.0.1 | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release designation** | 3.0.1 Jakarta | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release date** | 2022 April 28 | +| | | ++--------------------------------------+--------------------------------------------------------+ + +Bug Fixes +--------- + - `CPS-961 <https://jira.onap.org/browse/CPS-961>`_ Updated ANTLR compiler version to 4.9.2 to be compatible with runtime version + Version: 3.0.0 ============== |