diff options
19 files changed, 291 insertions, 71 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/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/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) |