aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java6
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml18
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml12
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml4
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java35
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy102
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java14
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java7
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java12
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy13
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy18
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java32
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java9
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java11
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java14
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy18
-rw-r--r--docs/_static/cps-delta-mechanism.pngbin0 -> 69416 bytes
-rw-r--r--docs/cps-delta-endpoints.rst66
-rw-r--r--docs/cps-delta-feature.rst44
-rw-r--r--docs/modeling.rst8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy14
24 files changed, 416 insertions, 72 deletions
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
index e33af45f9b..0e4f7f987f 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2022 Bell Canada
- * Modifications Copyright (c) 2022-2023 Nordix Foundation
+ * Modifications Copyright (c) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -167,7 +167,9 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
}
@Override
- public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandle) {
+ public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+ final String moduleName,
+ final String revision) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 3bee633900..6b53292af7 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2022 Bell Canada
# ================================================================================
@@ -492,6 +492,22 @@ components:
schema:
type: string
example: my-cm-handle
+ moduleNameInQuery:
+ name: module-name
+ in: query
+ description: Filter for a module name.This is an optional parameter
+ required: false
+ schema:
+ type: string
+ example: my-module
+ revisionInQuery:
+ name: revision
+ in: query
+ description: Filter for a module revision.This is an optional parameter and ignored when no module name is supplied
+ required: false
+ schema:
+ type: string
+ example: 2024-01-22
dataSyncEnabled:
name: dataSyncEnabled
in: query
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index 95ca6ccdc7..2f90155cbd 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021-2022 Bell Canada
# ================================================================================
@@ -289,15 +289,17 @@ fetchModuleReferencesByCmHandle:
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
-fetchModuleDefinitionsByCmHandle:
+getModuleDefinitions:
get:
- description: Fetch all module definitions (name, revision, yang resource) for a given cm handle
tags:
- network-cm-proxy
- summary: Fetch all module definitions (name, revision, yang resource) for a given cm handle
- operationId: getModuleDefinitionsByCmHandleId
+ summary: Get module definitions
+ description: Get module definitions (module name, revision, yang resource) with options to filter on module name and revision
+ operationId: getModuleDefinitions
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/moduleNameInQuery'
+ - $ref: 'components.yaml#/components/parameters/revisionInQuery'
responses:
200:
description: OK
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index 7ceb4fe70a..dd6d7c8baa 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021 Bell Canada
# ================================================================================
@@ -44,7 +44,7 @@ paths:
$ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
/v1/ch/{cm-handle}/modules/definitions:
- $ref: 'ncmp.yml#/fetchModuleDefinitionsByCmHandle'
+ $ref: 'ncmp.yml#/getModuleDefinitions'
/v1/ch/searches:
$ref: 'ncmp.yml#/searchCmHandles'
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 be33c6a010..6ec24448d7 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
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021 highstreet technologies GmbH
* Modifications Copyright (C) 2021-2022 Bell Canada
* ================================================================================
@@ -31,6 +31,7 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH;
import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE;
import io.micrometer.core.annotation.Timed;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -59,9 +60,11 @@ import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
import org.onap.cps.ncmp.rest.util.DeprecationHelper;
+import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -317,18 +320,32 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
}
/**
- * Return module definitions for a cm handle.
+ * Return module definitions.
*
- * @param cmHandleId cm-handle identifier
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param revision the revision of the module
* @return list of module definitions (module name, revision, yang resource content)
*/
@Override
- public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandleId) {
- final List<RestModuleDefinition> restModuleDefinitions =
- networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId).stream()
- .map(ncmpRestInputMapper::toRestModuleDefinition)
- .collect(Collectors.toList());
- return new ResponseEntity<>(restModuleDefinitions, HttpStatus.OK);
+ public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+ final String moduleName,
+ final String revision) {
+ final Collection<ModuleDefinition> moduleDefinitions;
+ if (StringUtils.hasText(moduleName)) {
+ moduleDefinitions =
+ networkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, revision);
+ } else {
+ moduleDefinitions = networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId);
+ if (StringUtils.hasText(revision)) {
+ log.warn("Ignoring revision filter as no module name is provided");
+ }
+ }
+ final List<RestModuleDefinition> response = new ArrayList<>();
+ for (final ModuleDefinition moduleDefinition: moduleDefinitions) {
+ response.add(ncmpRestInputMapper.toRestModuleDefinition(moduleDefinition));
+ }
+ return new ResponseEntity<>(response, HttpStatus.OK);
}
/**
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 314a0b221d..983f2438c0 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021-2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,26 +23,14 @@
package org.onap.cps.ncmp.rest.controller
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.classic.spi.ILoggingEvent
+import ch.qos.logback.core.read.ListAppender
import com.fasterxml.jackson.databind.ObjectMapper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
+import org.onap.cps.events.EventsPublisher
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
@@ -50,19 +38,20 @@ import org.onap.cps.ncmp.api.impl.inventory.CompositeState
import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.rest.model.DataOperationRequest
-import org.onap.cps.ncmp.rest.model.DataOperationDefinition
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler
import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler
import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper
import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper
+import org.onap.cps.ncmp.rest.model.DataOperationDefinition
+import org.onap.cps.ncmp.rest.model.DataOperationRequest
import org.onap.cps.ncmp.rest.util.DeprecationHelper
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
+import org.slf4j.LoggerFactory
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
@@ -72,10 +61,28 @@ import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Shared
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
+
@WebMvcTest(NetworkCmProxyController)
class NetworkCmProxyControllerSpec extends Specification {
@@ -130,11 +137,18 @@ class NetworkCmProxyControllerSpec extends Specification {
def NO_REQUEST_ID = null
def TIMOUT_FOR_TEST = 1234
+ def logger = Spy(ListAppender<ILoggingEvent>)
+
def setup() {
ncmpCachedResourceRequestHandler.notificationFeatureEnabled = true
ncmpCachedResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = true
ncmpPassthroughResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
+ setupLogger()
+ }
+
+ def cleanup() {
+ ((Logger) LoggerFactory.getLogger(EventsPublisher.class)).detachAndStopAllAppenders()
}
def 'Get Resource Data from pass-through operational.'() {
@@ -516,21 +530,46 @@ class NetworkCmProxyControllerSpec extends Specification {
':passthrough-running' | 'passthrough-running'
}
- def 'Get module definitions based on cmHandleId.'() {
- when: 'get module definition request is performed'
+ def 'Getting module definitions for a module'() {
+ when: 'get module definition request is performed with module name'
def response = mvc.perform(
- get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions"))
- .andReturn().response
- then: 'ncmp service method to get module definitions is called'
- mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle')
- >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
- 'module sampleModuleName{ sample module content }')]
+ get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=sampleModuleName"))
+ .andReturn().response
+ then: 'ncmp service method is invoked with correct parameters'
+ mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', 'sampleModuleName', _)
+ >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
+ 'module sampleModuleName{ sample module content }')]
and: 'response contains an array with the module name, revision and content'
response.getContentAsString() == '[{"moduleName":"sampleModuleName","revision":"2021-10-03","content":"module sampleModuleName{ sample module content }"}]'
and: 'response returns an OK http code'
response.status == HttpStatus.OK.value()
}
+ def 'Getting module definitions filtering on #scenario'() {
+ when: 'get module definition request is performed'
+ def response = mvc.perform(
+ get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=" + moduleName + "&revision=" + revision))
+ .andReturn().response
+ then: 'ncmp service method to get definitions by cm handle is invoked when needed'
+ numberOfCallsToByCmHandleId * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle') >> []
+ and: 'ncmp service method to get definitions by module is invoked when needed'
+ numberOfCallsToByModule * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', moduleName, revision) >> []
+ and: 'response returns an OK http code'
+ response.status == HttpStatus.OK.value()
+ and: 'the correct message is logged when needed'
+ if (expectLogWarning) {
+ def lastLoggingEvent = logger.list[0]
+ assert lastLoggingEvent.level == Level.WARN
+ assert lastLoggingEvent.formattedMessage.contains('Ignoring revision')
+ }
+ where: 'following parameters are used'
+ scenario | moduleName | revision || numberOfCallsToByCmHandleId | numberOfCallsToByModule | expectLogWarning
+ 'module name' | 'some-module' | '' || 0 | 1 | false
+ 'module name and revision' | 'some-module' | 'some-revision' || 0 | 1 | false
+ 'no filtering' | '' | '' || 1 | 0 | false
+ 'only revision' | '' | 'some-revision' || 1 | 0 | true
+ }
+
def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario'() {
when: 'the set data sync enabled request is invoked'
def response = mvc.perform(
@@ -667,5 +706,12 @@ class NetworkCmProxyControllerSpec extends Specification {
return dataOperationDefinition
}
+ def setupLogger() {
+ def setupLogger = ((Logger) LoggerFactory.getLogger(NetworkCmProxyController.class))
+ setupLogger.setLevel(Level.DEBUG)
+ setupLogger.addAppender(logger)
+ logger.start()
+ }
+
}
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 0c12875538..0c8474839b 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
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
@@ -126,6 +126,18 @@ public interface NetworkCmProxyDataService {
Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
/**
+ * Get module definitions for the given parameters.
+ *
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return list of module definitions (module name, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+ String moduleName,
+ String moduleRevision);
+
+ /**
* Query cm handle details by cm handle's name.
*
* @param cmHandleId cm handle identifier
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 3fa0504549..4fc8409290 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
@@ -192,6 +192,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
}
+ @Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+ final String moduleName,
+ final String moduleRevision) {
+ return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
+ }
+
/**
* Retrieve cm handles with details for the given query parameters.
*
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
index 9024eac331..dcd0368700 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
@@ -80,6 +80,18 @@ public interface InventoryPersistence extends NcmpPersistence {
Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
/**
+ * Method to return module definitions for the given parameters.
+ *
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return list of module definitions (module name, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+ String moduleName,
+ String moduleRevision);
+
+ /**
* Method to return module references by cmHandleId.
*
* @param cmHandleId cm handle ID
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
index 33d6e9a9cc..3b70786038 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
@@ -128,6 +128,15 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
}
@Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+ final String moduleName,
+ final String moduleRevision) {
+ cpsValidator.validateNameCharacters(cmHandleId, moduleName);
+ return cpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ cmHandleId, moduleName, moduleRevision);
+ }
+
+ @Override
public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
cpsValidator.validateNameCharacters(cmHandleId);
return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
index 8175fb5e74..a88adbd110 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
@@ -73,7 +73,13 @@ public class CmHandleIdMapper {
public void removeMapping(final String cmHandleId) {
final String alternateId = alternateIdPerCmHandleId.remove(cmHandleId);
- cmHandleIdPerAlternateId.remove(alternateId);
+ removeAlternateIdWithValidation(alternateId);
+ }
+
+ private void removeAlternateIdWithValidation(final String alternateId) {
+ if (alternateId != null) {
+ cmHandleIdPerAlternateId.remove(alternateId);
+ }
}
private void initializeCache() {
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 c1af902a08..49583cec32 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
@@ -298,10 +298,17 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
assert result == ['cm-handle-id-1']
}
- def 'Getting module definitions.'() {
- when: 'get module definitions method is called with a valid cm handle ID'
+ def 'Getting module definitions by module'() {
+ when: 'get module definitions is performed with module name'
+ objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+ then: 'ncmp inventory persistence service is invoked once with correct parameters'
+ 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+ }
+
+ def 'Getting module definitions by cm handle id'() {
+ when: 'get module definitions is performed with cm handle id'
objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
- then: 'CPS module services is invoked once'
+ then: 'ncmp inventory persistence service is invoked once with correct parameter'
1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
index cb2f3fdddd..a3b923f939 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -184,11 +184,23 @@ class InventoryPersistenceImplSpec extends Specification {
'DELETING' | CmHandleState.DELETING || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
}
- def 'Get module definitions'() {
- given: 'cps module service returns a collection of module definitions'
+ def 'Getting module definitions by module'() {
+ given: 'cps module service returns module definition for module name'
+ def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
+ mockCpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id', 'some-module', '2024-01-25') >> moduleDefinitions
+ when: 'get module definitions is invoked with module name'
+ def result = objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cmHandle-Id', 'some-module', '2024-01-25')
+ then: 'returned result are the same module definitions as returned from module service'
+ assert result == moduleDefinitions
+ and: 'cm handle id and module name validated'
+ 1 * mockCpsValidator.validateNameCharacters('some-cmHandle-Id', 'some-module')
+ }
+
+ def 'Getting module definitions with cm handle id'() {
+ given: 'cps module service returns module definitions for cm handle id'
def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
mockCpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleDefinitions
- when: 'get module definitions by cmHandle is invoked'
+ when: 'get module definitions is invoked with cm handle id'
def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id')
then: 'the returned result are the same module definitions as returned from the module service'
assert result == moduleDefinitions
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index b115f9a3c7..1e42702ab5 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -79,6 +80,8 @@ import org.springframework.stereotype.Component;
public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceService {
private static final String YANG_RESOURCE_CHECKSUM_CONSTRAINT_NAME = "yang_resource_checksum_key";
+ private static final String NO_MODULE_NAME_FILTER = null;
+ private static final String NO_MODULE_REVISION = null;
private static final Pattern CHECKSUM_EXCEPTION_PATTERN = Pattern.compile(".*\\(checksum\\)=\\((\\w+)\\).*");
private static final Pattern RFC6020_RECOMMENDED_FILENAME_PATTERN = Pattern
.compile("([\\w-]+)@(\\d{4}-\\d{2}-\\d{2})(?:\\.yang)?", Pattern.CASE_INSENSITIVE);
@@ -122,10 +125,29 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
public Collection<ModuleDefinition> getYangResourceDefinitions(final String dataspaceName,
final String anchorName) {
final Set<YangResourceEntity> yangResourceEntities =
- yangResourceRepository
- .findAllModuleDefinitionsByDataspaceAndAnchor(dataspaceName, anchorName);
- return yangResourceEntities.stream().map(CpsModulePersistenceServiceImpl::toModuleDefinition)
- .collect(Collectors.toList());
+ yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+ NO_MODULE_NAME_FILTER, NO_MODULE_REVISION);
+ return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+ }
+
+ @Override
+ public Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(final String dataspaceName,
+ final String anchorName,
+ final String moduleName,
+ final String moduleRevision) {
+ final Set<YangResourceEntity> yangResourceEntities =
+ yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+ moduleName, moduleRevision);
+ return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+ }
+
+ private List<ModuleDefinition> convertYangResourceEntityToModuleDefinition(final Set<YangResourceEntity>
+ yangResourceEntities) {
+ final List<ModuleDefinition> resultModuleDefinitions = new ArrayList<>(yangResourceEntities.size());
+ for (final YangResourceEntity yangResourceEntity: yangResourceEntities) {
+ resultModuleDefinitions.add(toModuleDefinition(yangResourceEntity));
+ }
+ return resultModuleDefinitions;
}
@Override
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
index 3fec462b44..b37f6357c1 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -84,9 +84,12 @@ public interface YangResourceRepository extends JpaRepository<YangResourceEntity
WHERE
dataspace.name = :dataspaceName
AND anchor.name = :anchorName
+ AND (:moduleName IS NULL OR yang_resource.module_name = :moduleName)
+ AND (:revision IS NULL OR yang_resource.revision = :revision)
""", nativeQuery = true)
- Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchor(
- @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName);
+ Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchorAndModule(
+ @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName,
+ @Param("moduleName") String moduleName, @Param("revision") String revision);
@Query(value = """
SELECT DISTINCT
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
index 2928464461..bdd361458e 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
* ================================================================================
@@ -134,6 +134,18 @@ public interface CpsModuleService {
Collection<ModuleDefinition> getModuleDefinitionsByAnchorName(String dataspaceName, String anchorName);
/**
+ * Retrieve module definitions for the given parameters.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return a collection of module definitions (moduleName, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+ String moduleName, String moduleRevision);
+
+ /**
* Identify previously unknown Yang Resource module references.
* The system will ignore the namespace of all module references.
*
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 61a4e623af..0f9eb3c64f 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* Modifications Copyright (C) 2022 TechMahindra Ltd
@@ -156,6 +156,15 @@ public class CpsModuleServiceImpl implements CpsModuleService {
}
@Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(final String dataspaceName,
+ final String anchorName,
+ final String moduleName,
+ final String moduleRevision) {
+ return cpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule(dataspaceName, anchorName,
+ moduleName, moduleRevision);
+ }
+
+ @Override
public Collection<ModuleReference> identifyNewModuleReferences(
final Collection<ModuleReference> moduleReferencesToCheck) {
return cpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck);
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
index aaca2ee5b5..eeaaa47991 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2022 TechMahindra Ltd.
* ================================================================================
@@ -126,6 +126,18 @@ public interface CpsModulePersistenceService {
Collection<ModuleDefinition> getYangResourceDefinitions(String dataspaceName, String anchorName);
/**
+ * Get YANG resource definitions for the given parameters.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return a collection of module definitions (moduleName, revision and yang resource content)
+ */
+ Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+ String moduleName, String moduleRevision);
+
+ /**
* Remove unused Yang Resource Modules.
*/
void deleteUnusedYangResourceModules();
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index d909e27abf..0bad0de6ac 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -238,15 +238,25 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck)
}
- def 'Getting module definitions.'() {
- given: 'the module persistence service returns a collection of module definitions'
+ def 'Getting module definitions with module name'() {
+ given: 'module persistence service returns module definitions for module name'
+ def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
+ mockCpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01') >> moduleDefinitionsFromPersistenceService
+ when: 'get module definitions method is called with anchor and module name'
+ def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01')
+ then: 'the result is the same collection returned by the persistence service'
+ assert result == moduleDefinitionsFromPersistenceService
+ }
+
+ def 'Getting module definitions with anchor name'() {
+ given: 'the module persistence service returns module definitions for cm handle id'
def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
mockCpsModulePersistenceService.getYangResourceDefinitions('some-dataspace-name', 'some-anchor-name') >> moduleDefinitionsFromPersistenceService
when: 'get module definitions method is called with a valid dataspace and anchor name'
def result = objectUnderTest.getModuleDefinitionsByAnchorName('some-dataspace-name', 'some-anchor-name')
then: 'the result is the same collection returned by the persistence service'
assert result == moduleDefinitionsFromPersistenceService
- and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
+ and: 'cps validator is called on the dataspace and anchor name'
1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name')
}
diff --git a/docs/_static/cps-delta-mechanism.png b/docs/_static/cps-delta-mechanism.png
new file mode 100644
index 0000000000..ab78ad9a1b
--- /dev/null
+++ b/docs/_static/cps-delta-mechanism.png
Binary files differ
diff --git a/docs/cps-delta-endpoints.rst b/docs/cps-delta-endpoints.rst
new file mode 100644
index 0000000000..b2e4e6041b
--- /dev/null
+++ b/docs/cps-delta-endpoints.rst
@@ -0,0 +1,66 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2021 Pantheon.tech
+.. Copyright (C) 2024 TechMahindra Ltd.
+.. _cpsDeltaEndpoints:
+
+.. toctree::
+ :maxdepth: 1
+
+CPS Delta Endpoints
+###################
+
+The CPS Delta feature provides 1 endpoint:
+
+- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta
+
+Description
+-----------
+The following is a Get endpoint, which allows the user to find the delta between configurations stored under two anchors within the same dataspace.
+
+Path Parameters
+---------------
+The endpoint takes 2 path parameters as input:
+ - **dataspace-name:** name of dataspace where the 2 anchors to be used for delta generation are stored.
+ - **anchor-name:** the source anchor name, the data under this anchor will be the reference data for delta report generation
+
+Query Parameters
+----------------
+The endpoint takes 3 query parameters as input:
+ - **target-anchor-name:** the data retrieved from target anchor gets compared against the data retrieved from source anchor
+ - **xpath:** the xpath to a particular data node, Example: /bookstore/categories[@code='1']
+ - **descendants:** specifies the number of descendants to query.
+
+Sample Delta Report
+-------------------
+
+.. code-block:: json
+
+ [
+ {
+ "action": "ADD",
+ "xpath": "/bookstore/categories/[@code=3]",
+ "target-data": {
+ "code": "3,",
+ "name": "kidz"
+ }
+ },
+ {
+ "action": "REMOVE",
+ "xpath": "/bookstore/categories/[@code=1]",
+ "source-data": {
+ "code": "1,",
+ "name": "Fiction"
+ }
+ },
+ {
+ "action": "UPDATE",
+ "xpath": "/bookstore/categories/[@code=2]",
+ "source-data": {
+ "name": "Funny"
+ },
+ "target-data": {
+ "name": "Comic"
+ }
+ }
+ ] \ No newline at end of file
diff --git a/docs/cps-delta-feature.rst b/docs/cps-delta-feature.rst
new file mode 100644
index 0000000000..f3a2f947e4
--- /dev/null
+++ b/docs/cps-delta-feature.rst
@@ -0,0 +1,44 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2021 Pantheon.tech
+.. Copyright (C) 2024 TechMahindra Ltd.
+.. _cpsDelta:
+
+.. toctree::
+ :maxdepth: 1
+
+CPS Delta Feature
+#################
+
+- The concept of CPS Delta Feature is to have the ability to find the delta or difference between two configurations stored in CPS DB.
+
+- The Delta feature brings a new functionality:
+
+ - Ability to find the delta between the configurations stored in two anchors within the same dataspace.
+
+The calculated differences can then be used to generate a Delta Report which can be sent over the Kafka Notification Service to the user.
+
+Delta Report Format
+-------------------
+
+The Delta Report is based on the RFC 9144, which defines a set of parameters to be included in the Delta Report. In CPS only the relevant parameters defined in RFC 9144 are used. These include:
+ - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to ADD, DELETE or UPDATE respectively for each data node.
+ - **xpath:** This parameter will provide the xpath of each data node that has been either added, deleted or modified.
+ - **source-data:** this parameter is added to the delta report when a data node is deleted or updated, this represents the source/reference data against which the delta is being generated. In case of newly added data node this field is not included in the delta report.
+ - **target-data:** this parameter is added to the delta report when a data node is added or updated, this represents the data values that are being compared to the source data. In case of a data node being deleted this field is not included in the delta report.
+
+**Note.** In case of an existing data node being modified, both the source-data and target-data fields are present in the delta report.
+
+Mechanism for Delta generation
+------------------------------
+
+.. image:: _static/cps-delta-mechanism.png
+ :alt: Mechanism for Delta generation
+
+Endpoints provided as part of Delta Feature
+-------------------------------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ cps-delta-endpoints.rst \ No newline at end of file
diff --git a/docs/modeling.rst b/docs/modeling.rst
index ceaaefda5a..7ebf6fecd5 100644
--- a/docs/modeling.rst
+++ b/docs/modeling.rst
@@ -63,6 +63,14 @@ Querying
xpath.rst
cps-path.rst
+Additional information on CPS-Core Interfaces
+---------------------------------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ cps-delta-feature.rst
+
.. Below Label is used by documentation for other CPS components to link here, do not remove even if it gives a warning
.. _cps_ncmp_modelling:
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
index cf0e0b5944..8029ae0428 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * Copyright (C) 2023-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
package org.onap.cps.integration.functional
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.api.impl.CpsModuleServiceImpl
import org.onap.cps.integration.base.FunctionalSpecBase
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.AlreadyDefinedException
@@ -153,6 +152,17 @@ class CpsModuleServiceIntegrationSpec extends FunctionalSpecBase {
result == [new ModuleDefinition('stores','2020-09-15','')]
}
+ def 'Retrieving module definitions: #scenarios'() {
+ when: 'module definitions for module name are retrieved'
+ def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, moduleName, moduleRevision)
+ then: 'the correct module definitions are returned'
+ result == [new ModuleDefinition('stores','2020-09-15','')]
+ where: 'following parameters are used'
+ scenarios | moduleName | moduleRevision
+ 'both specified' | 'stores' | '2020-09-15'
+ 'module name specified' | 'stores' | null
+ }
+
def 'Retrieving yang resource module references by anchor.'() {
when: 'the yang resource module references for an anchor are retrieved'
def result = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1)