From 04280e2f93bbf30e8654c411bb1e107d275c22bb Mon Sep 17 00:00:00 2001 From: "halil.cakal" Date: Tue, 23 Jan 2024 10:05:36 +0000 Subject: [PATCH] Extend API: Get Module Definitions - add query parameters: module-name and revision to OpenAPI - extend the controller method to hande the new parameters - add the new method stack to the service layer - extend the SQL query to support the new parameters - add unit and integration testwares Issue-ID: CPS-1135 Change-Id: I089ad2ad71effb58ac0ba809e9f441d6cdb59c4f Signed-off-by: halil.cakal --- .../controller/NetworkCmProxyStubController.java | 6 +- cps-ncmp-rest/docs/openapi/components.yaml | 18 +++- cps-ncmp-rest/docs/openapi/ncmp.yml | 12 ++- cps-ncmp-rest/docs/openapi/openapi.yml | 4 +- .../rest/controller/NetworkCmProxyController.java | 35 +++++-- .../controller/NetworkCmProxyControllerSpec.groovy | 102 +++++++++++++++------ .../cps/ncmp/api/NetworkCmProxyDataService.java | 14 ++- .../api/impl/NetworkCmProxyDataServiceImpl.java | 9 +- .../api/impl/inventory/InventoryPersistence.java | 12 +++ .../impl/inventory/InventoryPersistenceImpl.java | 9 ++ .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 15 ++- .../inventory/InventoryPersistenceImplSpec.groovy | 18 +++- .../spi/impl/CpsModulePersistenceServiceImpl.java | 32 ++++++- .../cps/spi/repository/YangResourceRepository.java | 9 +- .../java/org/onap/cps/api/CpsModuleService.java | 14 ++- .../onap/cps/api/impl/CpsModuleServiceImpl.java | 11 ++- .../onap/cps/spi/CpsModulePersistenceService.java | 14 ++- .../cps/api/impl/CpsModuleServiceImplSpec.groovy | 18 +++- .../CpsModuleServiceIntegrationSpec.groovy | 14 ++- 19 files changed, 293 insertions(+), 73 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 e33af45f9..0e4f7f987 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> getModuleDefinitionsByCmHandleId(final String cmHandle) { + public ResponseEntity> 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 3bee63390..6b53292af 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 95ca6ccdc..2f90155cb 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 7ceb4fe70..dd6d7c8ba 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 be33c6a01..6ec24448d 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> getModuleDefinitionsByCmHandleId(final String cmHandleId) { - final List restModuleDefinitions = - networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId).stream() - .map(ncmpRestInputMapper::toRestModuleDefinition) - .collect(Collectors.toList()); - return new ResponseEntity<>(restModuleDefinitions, HttpStatus.OK); + public ResponseEntity> getModuleDefinitions(final String cmHandleId, + final String moduleName, + final String revision) { + final Collection 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 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 314a0b221..983f2438c 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) + 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 0c1287553..0c8474839 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 * ================================================================================ @@ -125,6 +125,18 @@ public interface NetworkCmProxyDataService { */ Collection 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 getModuleDefinitionsByCmHandleAndModule(String cmHandleId, + String moduleName, + String moduleRevision); + /** * Query cm handle details by cm handle's name. * 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 469d75ab9..1e7edd402 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 @@ -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) 2021-2022 Bell Canada * Modifications Copyright (C) 2023 TechMahindra Ltd. @@ -188,6 +188,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId); } + @Override + public Collection 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 9024eac33..dcd036870 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 @@ -79,6 +79,18 @@ public interface InventoryPersistence extends NcmpPersistence { */ Collection 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 getModuleDefinitionsByCmHandleAndModule(String cmHandleId, + String moduleName, + String moduleRevision); + /** * Method to return module references by cmHandleId. * 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 33d6e9a9c..3b7078603 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 @@ -127,6 +127,15 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv return cpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId); } + @Override + public Collection 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 getYangResourcesModuleReferences(final String cmHandleId) { cpsValidator.validateNameCharacters(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 4f7b72698..4c8b2bbe0 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 @@ -1,6 +1,6 @@ /* * ============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 * Modifications Copyright (C) 2023 TechMahindra Ltd. @@ -292,10 +292,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 cb2f3fddd..a3b923f93 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 b115f9a3c..1e42702ab 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 getYangResourceDefinitions(final String dataspaceName, final String anchorName) { final Set 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 getYangResourceDefinitionsByAnchorAndModule(final String dataspaceName, + final String anchorName, + final String moduleName, + final String moduleRevision) { + final Set yangResourceEntities = + yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName, + moduleName, moduleRevision); + return convertYangResourceEntityToModuleDefinition(yangResourceEntities); + } + + private List convertYangResourceEntityToModuleDefinition(final Set + yangResourceEntities) { + final List 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 3fec462b4..b37f6357c 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 findAllModuleDefinitionsByDataspaceAndAnchor( - @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName); + Set 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 292846446..bdd361458 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. * ================================================================================ @@ -133,6 +133,18 @@ public interface CpsModuleService { */ Collection 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 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 61a4e623a..0f9eb3c64 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 @@ -155,6 +155,15 @@ public class CpsModuleServiceImpl implements CpsModuleService { return cpsModulePersistenceService.getYangResourceDefinitions(dataspaceName, anchorName); } + @Override + public Collection getModuleDefinitionsByAnchorAndModule(final String dataspaceName, + final String anchorName, + final String moduleName, + final String moduleRevision) { + return cpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule(dataspaceName, anchorName, + moduleName, moduleRevision); + } + @Override public Collection identifyNewModuleReferences( final Collection 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 aaca2ee5b..eeaaa4799 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. * ================================================================================ @@ -125,6 +125,18 @@ public interface CpsModulePersistenceService { */ Collection 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 getYangResourceDefinitionsByAnchorAndModule(String dataspaceName, String anchorName, + String moduleName, String moduleRevision); + /** * Remove unused Yang Resource Modules. */ 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 d909e27ab..0bad0de6a 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 cf0e0b594..8029ae042 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) -- 2.16.6