From: leventecsanyi Date: Tue, 27 May 2025 08:01:57 +0000 (+0200) Subject: Fetch Cm Handles with optional private properties X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F57%2F140957%2F10;p=cps.git Fetch Cm Handles with optional private properties - added output mapper - implemented endpoint to query cm handles on E-01 - added unit tests - re-generated relevant docs Issue-ID: CPS-1872 Change-Id: I18df1b151a6e818ee1c13b43a0c8e43ae9c22258 Signed-off-by: leventecsanyi --- 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 166488793d..309b4ed837 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 @@ -43,7 +43,7 @@ import org.onap.cps.ncmp.rest.model.RestModuleDefinition; import org.onap.cps.ncmp.rest.model.RestModuleReference; 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.model.RestOutputPublicCmHandleProperties; import org.onap.cps.ncmp.rest.stub.providers.ResourceProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -159,7 +159,7 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { } @Override - public ResponseEntity getCmHandlePublicPropertiesByCmHandleId( + public ResponseEntity getCmHandlePublicPropertiesByCmHandleId( final String cmHandle) { 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 e4283d9404..835cfc29e2 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-2024 Nordix Foundation +# Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved. # Modifications Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2022 Bell Canada # ================================================================================ @@ -130,9 +130,15 @@ components: type: string example: my-cm-handle cmHandleProperties: - $ref: '#/components/schemas/RestCmHandleProperties' + type: object + additionalProperties: + type: string + example: my-property publicCmHandleProperties: - $ref: '#/components/schemas/RestCmHandleProperties' + type: object + additionalProperties: + type: string + example: my-property moduleSetTag: type: string example: "my-module-set-tag" @@ -146,11 +152,6 @@ components: dataProducerIdentifier: type: string example: "my-data-producer-identifier" - RestCmHandleProperties: - type: object - additionalProperties: - type: string - example: my-property #Module upgrade schema UpgradedCmHandles: required: @@ -253,7 +254,17 @@ components: type: string example: my-cm-handle1 publicCmHandleProperties: - $ref: '#/components/schemas/CmHandlePublicProperties' + type: object + items: + type: object + additionalProperties: + type: string + example: '3gpp Type' + privateCmHandleProperties: + type: object + additionalProperties: + type: string + example: '3gpp Type' state: $ref: '#/components/schemas/CmHandleCompositeState' trustLevel: @@ -267,13 +278,6 @@ components: dataProducerIdentifier: type: string example: my-data-producer-identifier - CmHandlePublicProperties: - type: object - items: - type: object - additionalProperties: - type: string - example: '3gpp Type' CmHandleCompositeState: type: object properties: @@ -323,12 +327,16 @@ components: type: string example: 2022-12-31T20:30:40.000+0000 - RestOutputCmHandlePublicProperties: + RestOutputPublicCmHandleProperties: type: object properties: publicCmHandleProperties: - $ref: '#/components/schemas/CmHandlePublicProperties' - + type: object + items: + type: object + additionalProperties: + type: string + example: '3gpp Type' RestOutputCmHandleCompositeState: type: object properties: diff --git a/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml index 7b1c8d403e..4aa977e0cc 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml @@ -1,6 +1,6 @@ # ============LICENSE_START======================================================= # Copyright (C) 2021 Bell Canada -# Modifications Copyright (C) 2021-2024 Nordix Foundation +# Modifications Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -146,5 +146,41 @@ searchCmHandleIds: type: string 403: $ref: 'components.yaml#/components/responses/Forbidden' + 500: + $ref: 'components.yaml#/components/responses/InternalServerError' + +searchCmHandles: + post: + description: Execute cm handle query search and return a list of cm handle details. Any number of conditions can be applied. To be included in the result a cm-handle must fulfill ALL the conditions. An empty collection will be returned in the case that the cm handle does not match a condition. For more on cm handle query search please refer to cm handle query search Read the Docs.
By supplying a CPS Path it is possible to query on any data related to the cm handle. For more on CPS Path please refer to CPS Path Read the Docs. The cm handle ancestor is automatically returned for this query. + tags: + - network-cm-proxy-inventory + summary: Query Cm Handles for a requested DMI Service + operationId: searchCmHandles + parameters: + - name: includePrivatePropertiesInQuery + in: query + description: Whether to include private properties in the response. + required: false + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + $ref: 'components.yaml#/components/schemas/CmHandleQueryParameters' + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/components/schemas/RestOutputCmHandle' + 400: + $ref: 'components.yaml#/components/responses/BadRequest' + 403: + $ref: 'components.yaml#/components/responses/Forbidden' 500: $ref: 'components.yaml#/components/responses/InternalServerError' \ No newline at end of file diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index 6dd91136bb..bd26750a41 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-2024 OpenInfra Foundation Europe. All rights reserved. +# Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved. # Modifications Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2021-2022 Bell Canada # ================================================================================ @@ -392,7 +392,7 @@ getCmHandlePropertiesById: content: application/json: schema: - $ref: 'components.yaml#/components/schemas/RestOutputCmHandlePublicProperties' + $ref: 'components.yaml#/components/schemas/RestOutputPublicCmHandleProperties' 400: $ref: 'components.yaml#/components/responses/BadRequest' 404: diff --git a/cps-ncmp-rest/docs/openapi/openapi-inventory.yml b/cps-ncmp-rest/docs/openapi/openapi-inventory.yml index 7658075043..8f507c6a7c 100755 --- a/cps-ncmp-rest/docs/openapi/openapi-inventory.yml +++ b/cps-ncmp-rest/docs/openapi/openapi-inventory.yml @@ -33,3 +33,6 @@ paths: /v1/ch/searches: $ref: 'ncmp-inventory.yml#/searchCmHandleIds' + + /v1/ch/searchCmHandles: + $ref: 'ncmp-inventory.yml#/searchCmHandles' \ No newline at end of file diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml index 4084f9b21b..0715b42db4 100644 --- a/cps-ncmp-rest/pom.xml +++ b/cps-ncmp-rest/pom.xml @@ -130,7 +130,7 @@ org.openapitools openapi-generator-maven-plugin - 6.6.0 + 7.12.0 ncmp-code-gen @@ -168,6 +168,7 @@ org.onap.cps.ncmp.rest.api spring false + true src/gen/java java11 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 387f48acb5..2b0ea3171f 100644 --- 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 @@ -34,6 +34,7 @@ import io.micrometer.core.annotation.Timed; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -48,19 +49,19 @@ import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade; import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi; -import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties; import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; import org.onap.cps.ncmp.rest.model.DataOperationRequest; import org.onap.cps.ncmp.rest.model.RestModuleDefinition; import org.onap.cps.ncmp.rest.model.RestModuleReference; 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.model.RestOutputPublicCmHandleProperties; import org.onap.cps.ncmp.rest.util.CmHandleStateMapper; import org.onap.cps.ncmp.rest.util.CountCmHandleSearchExecution; import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper; import org.onap.cps.ncmp.rest.util.DeprecationHelper; import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper; +import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -82,6 +83,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { private final NcmpRestInputMapper ncmpRestInputMapper; private final CmHandleStateMapper cmHandleStateMapper; private final DataOperationRequestMapper dataOperationRequestMapper; + private final RestOutputCmHandleMapper restOutputCmHandleMapper; /** * Get resource data from datastore. @@ -265,7 +267,8 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters); final List restOutputCmHandles = networkCmProxyInventoryFacade.executeCmHandleSearch(cmHandleQueryApiParameters) - .map(this::toRestOutputCmHandle).collectList().block(); + .map(handle -> restOutputCmHandleMapper + .toRestOutputCmHandle(handle, false)).collectList().block(); return ResponseEntity.ok(restOutputCmHandles); } @@ -299,7 +302,8 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { public ResponseEntity retrieveCmHandleDetailsById(final String cmHandleReference) { final NcmpServiceCmHandle ncmpServiceCmHandle = networkCmProxyInventoryFacade.getNcmpServiceCmHandle(cmHandleReference); - final RestOutputCmHandle restOutputCmHandle = toRestOutputCmHandle(ncmpServiceCmHandle); + final RestOutputCmHandle restOutputCmHandle = restOutputCmHandleMapper + .toRestOutputCmHandle(ncmpServiceCmHandle, false); return ResponseEntity.ok(restOutputCmHandle); } @@ -310,14 +314,14 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @return cm handle properties */ @Override - public ResponseEntity getCmHandlePublicPropertiesByCmHandleId( + public ResponseEntity getCmHandlePublicPropertiesByCmHandleId( final String cmHandleReference) { - final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties(); + final List> cmHandlePublicProperties = new ArrayList<>(1); cmHandlePublicProperties.add(networkCmProxyInventoryFacade.getCmHandlePublicProperties(cmHandleReference)); - final RestOutputCmHandlePublicProperties restOutputCmHandlePublicProperties = - new RestOutputCmHandlePublicProperties(); - restOutputCmHandlePublicProperties.setPublicCmHandleProperties(cmHandlePublicProperties); - return ResponseEntity.ok(restOutputCmHandlePublicProperties); + final RestOutputPublicCmHandleProperties restOutputPublicCmHandleProperties = + new RestOutputPublicCmHandleProperties(); + restOutputPublicCmHandleProperties.setPublicCmHandleProperties(cmHandlePublicProperties); + return ResponseEntity.ok(restOutputPublicCmHandleProperties); } /** @@ -396,23 +400,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { return new ResponseEntity<>(HttpStatus.OK); } - private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) { - final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle(); - final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties(); - restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId()); - cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties()); - restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties); - restOutputCmHandle.setState(cmHandleStateMapper.toCmHandleCompositeStateExternalLockReason( - ncmpServiceCmHandle.getCompositeState())); - if (ncmpServiceCmHandle.getCurrentTrustLevel() != null) { - restOutputCmHandle.setTrustLevel(ncmpServiceCmHandle.getCurrentTrustLevel().toString()); - } - restOutputCmHandle.setModuleSetTag(ncmpServiceCmHandle.getModuleSetTag()); - restOutputCmHandle.setAlternateId(ncmpServiceCmHandle.getAlternateId()); - restOutputCmHandle.setDataProducerIdentifier(ncmpServiceCmHandle.getDataProducerIdentifier()); - return restOutputCmHandle; - } - private void validateDataStore(final DatastoreType acceptableDataStoreType, final String requestedDatastoreName) { final DatastoreType datastoreType = DatastoreType.fromDatastoreName(requestedDatastoreName); diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java index 5de8c12044..2af444132c 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade; +import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters; import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse.Status; @@ -37,8 +38,11 @@ import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse; import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse; import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration; +import org.onap.cps.ncmp.rest.model.RestOutputCmHandle; import org.onap.cps.ncmp.rest.util.CountCmHandleSearchExecution; +import org.onap.cps.ncmp.rest.util.DeprecationHelper; import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper; +import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -51,6 +55,8 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor private final NetworkCmProxyInventoryFacade networkCmProxyInventoryFacade; private final NcmpRestInputMapper ncmpRestInputMapper; + private final DeprecationHelper deprecationHelper; + private final RestOutputCmHandleMapper restOutputCmHandleMapper; /** * Get all cm handle references under a registered DMI plugin. @@ -73,6 +79,28 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor return ResponseEntity.ok(List.copyOf(cmHandleIds)); } + /** + * Execute cm handle query search and return a list of cm handle details. Any number of conditions can be applied. + * + * @param cmHandleQueryParameters the cm handle query parameters + * @param includePrivateProperties boolean value to determine the inclusion of private properties + * @return collection of cm handles + */ + @Override + public ResponseEntity> searchCmHandles( + final CmHandleQueryParameters cmHandleQueryParameters, + final Boolean includePrivateProperties) { + final CmHandleQueryApiParameters cmHandleQueryApiParameters = + deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters); + final boolean includePrivatePropertiesParameter = Boolean.TRUE.equals(includePrivateProperties); + final List restOutputCmHandles = + networkCmProxyInventoryFacade.executeCmHandleInventorySearch(cmHandleQueryApiParameters) + .map(handle -> restOutputCmHandleMapper + .toRestOutputCmHandle(handle, includePrivatePropertiesParameter)) + .collectList().block(); + return ResponseEntity.ok(restOutputCmHandles); + } + /** * Get all cm-handle IDs under a registered DMI plugin. * diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapper.java new file mode 100644 index 0000000000..095d0624a9 --- /dev/null +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapper.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.util; + +import java.util.Collections; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.rest.model.RestOutputCmHandle; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class RestOutputCmHandleMapper { + + private final CmHandleStateMapper cmHandleStateMapper; + + /** + * Map NcmpServiceCmHandle to a RestOutputCmHandle object. + * + * @param ncmpServiceCmHandle DMI plugin identifier + * @param includePrivateProperties Boolean for cm handle reference type either + * cm handle id (False) or alternate id (True) + * @return list of cm handles + */ + public RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle, + final boolean includePrivateProperties) { + final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle(); + restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId()); + restOutputCmHandle.setPublicCmHandleProperties( + Collections.singletonList(ncmpServiceCmHandle.getPublicProperties())); + if (includePrivateProperties) { + restOutputCmHandle.setPrivateCmHandleProperties(ncmpServiceCmHandle.getDmiProperties()); + } + restOutputCmHandle.setState( + cmHandleStateMapper.toCmHandleCompositeStateExternalLockReason( + ncmpServiceCmHandle.getCompositeState())); + if (ncmpServiceCmHandle.getCurrentTrustLevel() != null) { + restOutputCmHandle.setTrustLevel(ncmpServiceCmHandle.getCurrentTrustLevel().toString()); + } + restOutputCmHandle.setModuleSetTag(ncmpServiceCmHandle.getModuleSetTag()); + restOutputCmHandle.setAlternateId(ncmpServiceCmHandle.getAlternateId()); + restOutputCmHandle.setDataProducerIdentifier(ncmpServiceCmHandle.getDataProducerIdentifier()); + return restOutputCmHandle; + } +} \ No newline at end of file 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 8c7f5fbdf6..32fcd532f5 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 @@ -43,12 +43,14 @@ import org.onap.cps.ncmp.api.inventory.models.LockReasonCategory import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher import org.onap.cps.ncmp.rest.model.DataOperationDefinition import org.onap.cps.ncmp.rest.model.DataOperationRequest +import org.onap.cps.ncmp.rest.model.RestOutputCmHandle import org.onap.cps.ncmp.rest.util.CmHandleStateMapper import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper import org.onap.cps.api.model.ModuleDefinition import org.onap.cps.api.model.ModuleReference +import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory import org.spockframework.spring.SpringBean @@ -112,6 +114,9 @@ class NetworkCmProxyControllerSpec extends Specification { @SpringBean DataOperationRequestMapper dataOperationRequestMapper = Mappers.getMapper(DataOperationRequestMapper) + @SpringBean + RestOutputCmHandleMapper mockRestOutputCmHandleMapper = Mock() + @SpringBean DeprecationHelper stubbedDeprecationHelper = Stub() @@ -261,53 +266,44 @@ class NetworkCmProxyControllerSpec extends Specification { assert response.status == HttpStatus.OK.value() } - def 'Retrieve cm handles.'() { - given: 'an endpoint and json data' + def 'Execute cm handle search.'() { + given: 'search endpoint and JSON request' def searchesEndpoint = "$ncmpBasePathV1/ch/searches" String jsonString = TestUtils.getResourceFileContent('cmhandle-search.json') - and: 'the service method is invoked with module names and returns two cm handles' - def cmHandle1 = new NcmpServiceCmHandle() - cmHandle1.cmHandleId = 'ch-1' - cmHandle1.publicProperties = [color: 'yellow'] - cmHandle1.currentTrustLevel = TrustLevel.NONE - def cmHandle2 = new NcmpServiceCmHandle() - cmHandle2.cmHandleId = 'ch-2' - cmHandle2.publicProperties = [color: 'green'] - cmHandle2.alternateId = 'someAlternateId' - cmHandle2.moduleSetTag = 'someModuleSetTag' - cmHandle2.dataProducerIdentifier = 'someDataProducerIdentifier' - mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> Flux.fromIterable([cmHandle1, cmHandle2]) - when: 'the searches api is invoked' + and: 'the inventory facade returns two cm handles' + def ncmpServiceCmHandle1 = new NcmpServiceCmHandle(cmHandleId: 'ch-1') + def ncmpServiceCmHandle2 = new NcmpServiceCmHandle(cmHandleId: 'ch-2') + mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> Flux.fromIterable([ncmpServiceCmHandle1, ncmpServiceCmHandle2]) + and: 'mapper converts cm handles without private properties' + def restHandle1 = new RestOutputCmHandle(cmHandle: 'rest ch-1') + def restHandle2 = new RestOutputCmHandle(cmHandle: 'rest ch-2') + mockRestOutputCmHandleMapper.toRestOutputCmHandle(ncmpServiceCmHandle1, false) >> restHandle1 + mockRestOutputCmHandleMapper.toRestOutputCmHandle(ncmpServiceCmHandle2, false) >> restHandle2 + when: 'the search endpoint is invoked' def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response - then: 'response status returns OK' + then: 'response status is OK' assert response.status == HttpStatus.OK.value() - and: 'the expected response content is returned' - assert response.contentAsString == '[{"cmHandle":"ch-1","publicCmHandleProperties":[{"color":"yellow"}],"state":null,"trustLevel":"NONE","moduleSetTag":null,"alternateId":null,"dataProducerIdentifier":null},{"cmHandle":"ch-2","publicCmHandleProperties":[{"color":"green"}],"state":null,"trustLevel":null,"moduleSetTag":"someModuleSetTag","alternateId":"someAlternateId","dataProducerIdentifier":"someDataProducerIdentifier"}]' + and: 'the response contains the rest version of both cm handles' + assert response.contentAsString.contains('rest ch-1') + assert response.contentAsString.contains('rest ch-2') } + def 'Get complete Cm Handle details by Cm Handle Reference.'() { given: 'an endpoint and a cm handle reference' - def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle-reference" - and: 'an existing ncmp service cm handle' - def cmHandleId = 'some-cm-handle' - def alternateId = 'some-alternate-id' - def dmiProperties = [prop: 'some DMI property'] - def publicProperties = ["public prop": 'some public property'] - def compositeState = compositeStateTestObject() - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: alternateId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState, currentTrustLevel: TrustLevel.COMPLETE) - and: 'the service method is invoked with the cm handle reference' - 1 * mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('some-cm-handle-reference') >> ncmpServiceCmHandle + def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/cm handle id in request" + and: 'existing cm handle from inventory facade' + def cmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch-1') + mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('cm handle id in request') >> cmHandle + and: 'mapper converts cm handle without private properties' + def restOutputCmHandle = new RestOutputCmHandle(cmHandle: 'rest version of the cm handle') + mockRestOutputCmHandleMapper.toRestOutputCmHandle(cmHandle, false) >> restOutputCmHandle when: 'the cm handle details api is invoked' - def response = mvc.perform( - get(cmHandleDetailsEndpoint)).andReturn().response - then: 'the correct response is returned' + def response = mvc.perform(get(cmHandleDetailsEndpoint)).andReturn().response + then: 'response status is OK' response.status == HttpStatus.OK.value() - and: 'the response contains the public properties' - assertContainsPublicProperties(response) - and: 'the response contains the cm handle state' - assertContainsState(response) - and: 'the content does not contain dmi properties' - assert !response.contentAsString.contains("some DMI property") + and: 'the response contains the rest version of the cm handle' + assert response.contentAsString.contains('rest version of the cm handle') } def 'Get Cm Handle public properties by Cm Handle Reference.'() { @@ -341,23 +337,14 @@ class NetworkCmProxyControllerSpec extends Specification { } def 'Call execute cm handle searches with unrecognized condition name.'() { - given: 'an endpoint and json data' + given: 'the search endpoint and a request with an unrecognized condition name' def searchesEndpoint = "$ncmpBasePathV1/ch/searches" String jsonString = TestUtils.getResourceFileContent('invalid-cmhandle-search.json') - and: 'the service method is invoked with module names and returns two cm handles' - def cmHandle1 = new NcmpServiceCmHandle() - cmHandle1.cmHandleId = 'ch-1' - cmHandle1.publicProperties = [color: 'yellow'] - cmHandle1.currentTrustLevel = TrustLevel.COMPLETE - def cmHandle2 = new NcmpServiceCmHandle() - cmHandle2.cmHandleId = 'ch-2' - cmHandle2.publicProperties = [color: 'green'] - cmHandle2.currentTrustLevel = TrustLevel.NONE - mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> Flux.fromIterable([cmHandle1, cmHandle2]) when: 'the searches api is invoked' - def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response - then: 'an empty cm handle identifier is returned' - assert response.contentAsString == '[{"cmHandle":"ch-1","publicCmHandleProperties":[{"color":"yellow"}],"state":null,"trustLevel":"COMPLETE","moduleSetTag":null,"alternateId":null,"dataProducerIdentifier":null},{"cmHandle":"ch-2","publicCmHandleProperties":[{"color":"green"}],"state":null,"trustLevel":"NONE","moduleSetTag":null,"alternateId":null,"dataProducerIdentifier":null}]' + mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)) + then: 'the request was still accepted and forwarded to the correct services' + 1 * mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> Flux.fromIterable([new NcmpServiceCmHandle()]) + 1 * mockRestOutputCmHandleMapper.toRestOutputCmHandle(_, _) >> new RestOutputCmHandle(cmHandle: 'some cm handle') } def 'Query for cm handles matching query parameters'() { diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy index 9d79922478..7f1f4d6b46 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy @@ -23,6 +23,7 @@ package org.onap.cps.ncmp.rest.controller import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.TestUtils +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse @@ -32,7 +33,10 @@ import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration +import org.onap.cps.ncmp.rest.model.RestOutputCmHandle +import org.onap.cps.ncmp.rest.util.DeprecationHelper import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper +import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired @@ -42,6 +46,7 @@ import org.springframework.context.annotation.Import import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc +import reactor.core.publisher.Flux import spock.lang.Specification import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get @@ -60,6 +65,12 @@ class NetworkCmProxyInventoryControllerSpec extends Specification { @SpringBean NcmpRestInputMapper ncmpRestInputMapper = Mock() + @SpringBean + RestOutputCmHandleMapper mockRestOutputCmHandleMapper = Mock() + + @SpringBean + DeprecationHelper deprecationHelper = Mock() + DmiPluginRegistration mockDmiPluginRegistration = Mock() CmHandleQueryServiceParameters cmHandleQueryServiceParameters = Mock() @@ -252,11 +263,26 @@ class NetworkCmProxyInventoryControllerSpec extends Specification { assert response.contentAsString.contains(firstReference) assert response.contentAsString.contains(secondReference) where: - scenario | outputAlternateId || firstReference | secondReference + scenario | outputAlternateId || firstReference | secondReference 'output returns cm handle ids' | '' || 'cm-handle-id-1' | 'cm-handle-id-2' 'output returns alternate ids' | '&outputAlternateId=true' || 'alternate-id-1' | 'alternate-id-2' } + def 'Get a cm handle by DMI service name.'() { + given: 'an endpoint for returning cm handles by dmi service name' + def postUrl = "$ncmpBasePathV1/ch/searchCmHandles?includePrivatePropertiesInQuery=true" + String jsonString = TestUtils.getResourceFileContent('cm-handle-search-by-dmi-service.json') + and: 'a cm handle is returned' + def ncmpServiceCmHandle = new NcmpServiceCmHandle(dmiProperties: ['someName': 'my dmi']) + mockNetworkCmProxyInventoryFacade.executeCmHandleInventorySearch(_) >> Flux.fromIterable([ncmpServiceCmHandle]) + and: 'the mapper is requested to convert the object with private properties' + mockRestOutputCmHandleMapper.toRestOutputCmHandle(ncmpServiceCmHandle, true) >> new RestOutputCmHandle() + when: 'the endpoint is invoked' + def response = mvc.perform(post(postUrl).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response + then: 'a response status is OK' + assert response.status == 200 + } + def expectedUnknownErrorResponse(cmHandle) { return new CmHandlerRegistrationErrorResponse('cmHandle': cmHandle, 'errorCode': '108', 'errorText': 'Failed') } diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy index 3a9a0bb09c..7b16df52df 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy @@ -44,6 +44,7 @@ import org.onap.cps.api.exceptions.AlreadyDefinedException import org.onap.cps.api.exceptions.CpsException import org.onap.cps.api.exceptions.DataNodeNotFoundException import org.onap.cps.api.exceptions.DataValidationException +import org.onap.cps.ncmp.rest.util.RestOutputCmHandleMapper import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired @@ -105,6 +106,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { @SpringBean DataJobControllerForTest stubbedDataJobControllerForTest = Stub() + @SpringBean + RestOutputCmHandleMapper mockRestOutputCmHandleMapper = Mock() + @Value('${rest.api.ncmp-base-path}') def basePathNcmp diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapperSpec.groovy new file mode 100644 index 0000000000..d6eff59b20 --- /dev/null +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/RestOutputCmHandleMapperSpec.groovy @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.util + +import org.onap.cps.ncmp.api.inventory.models.CompositeState +import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.onap.cps.ncmp.rest.model.CmHandleCompositeState +import spock.lang.Specification + +class RestOutputCmHandleMapperSpec extends Specification { + + CmHandleStateMapper mockCmHandleStateMapper = Mock() + RestOutputCmHandleMapper objectUnderTest = new RestOutputCmHandleMapper(mockCmHandleStateMapper) + + def 'Map cm handles to rest output #scenario.'() { + given: 'a cm handle with different states' + def ncmpServiceCmHandle = createNcmpServiceCmHandle(trustLevel) + and: 'the state mapper returns a composite state' + mockCmHandleStateMapper.toCmHandleCompositeStateExternalLockReason(ncmpServiceCmHandle.getCompositeState()) >> new CmHandleCompositeState(cmHandleState: 'ADVISED') + when: 'the mapper function is called' + def result = objectUnderTest.toRestOutputCmHandle(ncmpServiceCmHandle, includePrivateProperties) + then: 'result has the expected properties' + assert result.privateCmHandleProperties.containsKey('private property key') == includePrivateProperties + if (trustLevel != null) { + assert result.trustLevel == trustLevel.toString() + } + assert result.publicCmHandleProperties[0].containsKey('public property key') + assert result.alternateId == 'alt-1' + assert result.cmHandle == 'ch-1' + where: + scenario | includePrivateProperties || trustLevel + 'without private properties' | false || null + 'with private properties' | true || TrustLevel.NONE + 'with trust level' | false || TrustLevel.COMPLETE + } + + def createNcmpServiceCmHandle(trustLevel) { + return new NcmpServiceCmHandle(cmHandleId: 'ch-1', dmiProperties: ['private property key': 'some value'], + currentTrustLevel: trustLevel, + publicProperties: ['public property key': 'public property value'], + alternateId: 'alt-1', compositeState: new CompositeState(cmHandleState: 'ADVISED')) + } +} diff --git a/cps-ncmp-rest/src/test/resources/cm-handle-search-by-dmi-service.json b/cps-ncmp-rest/src/test/resources/cm-handle-search-by-dmi-service.json new file mode 100644 index 0000000000..0048ecc7ee --- /dev/null +++ b/cps-ncmp-rest/src/test/resources/cm-handle-search-by-dmi-service.json @@ -0,0 +1,12 @@ +{ + "cmHandleQueryParameters": [ + { + "conditionName": "cmHandleWithDmiPlugin", + "conditionParameters": [ + { + "dmiPluginName": "my-dmi" + } + ] + } + ] +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java index 876a5e7c40..f6d9518b5a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java @@ -143,4 +143,13 @@ public interface NetworkCmProxyInventoryFacade { * @return cm handle state */ CompositeState getCmHandleCompositeState(final String cmHandleReference); + + /** + * Retrieve cm handles with details for the given query parameters. + * + * @param cmHandleQueryApiParameters cm handle query parameters + * @return cm handle objects as a reactive stream (flux) + */ + Flux executeCmHandleInventorySearch(final CmHandleQueryApiParameters + cmHandleQueryApiParameters); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java index 7130afdcfd..a6f50d22ec 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java @@ -127,6 +127,15 @@ public class NetworkCmProxyInventoryFacadeImpl implements NetworkCmProxyInventor return parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters); } + @Override + public Flux executeCmHandleInventorySearch( + final CmHandleQueryApiParameters cmHandleQueryApiParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = + jsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); + validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES); + return parameterizedCmHandleQueryService.queryInventoryForCmHandles(cmHandleQueryServiceParameters); + } + @Override public Collection executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters, final boolean outputAlternateId) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java index 64d4689d53..4d02e0328b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java @@ -71,4 +71,18 @@ public interface ParameterizedCmHandleQueryService { */ Flux queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters); + + /** + * Query and return cm handles that match the given query parameters. + * Supported query types: + * cps-path + * public properties + * private (additional) properties + * dmi-names + * + * @param cmHandleQueryServiceParameters the cm handle query parameters + * @return cm handle objects as a reactive stream (flux) + */ + Flux queryInventoryForCmHandles( + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java index 19b6199b99..be6ca8a249 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java @@ -86,6 +86,12 @@ public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHan return getNcmpServiceCmHandles(cmHandleIds); } + @Override + public Flux queryInventoryForCmHandles(final CmHandleQueryServiceParameters queryParameters) { + final Collection cmHandleIds = queryCmHandleIdsForInventory(queryParameters, false); + return getNcmpServiceCmHandles(cmHandleIds); + } + private Collection queryCmHandlesByDmiPlugin( final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) { final Map dmiPropertyQueryPairs = diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java index 6be5c8ba16..d96fdee75a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java @@ -30,7 +30,8 @@ public enum CmHandleQueryConditions { HAS_ALL_PROPERTIES("hasAllProperties"), HAS_ALL_MODULES("hasAllModules"), WITH_CPS_PATH("cmHandleWithCpsPath"), - WITH_TRUST_LEVEL("cmHandleWithTrustLevel"); + WITH_TRUST_LEVEL("cmHandleWithTrustLevel"), + WITH_DMI_SERVICE("cmHandleWithDmiPlugin"); public static final Collection ALL_CONDITION_NAMES = Arrays.stream(CmHandleQueryConditions.values()) .map(CmHandleQueryConditions::getConditionName).collect(Collectors.toList()); diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy index 29cd92db3f..bb4a6ff832 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy @@ -24,6 +24,7 @@ package org.onap.cps.ncmp.impl.inventory import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.api.exceptions.DataValidationException import org.onap.cps.api.model.ConditionProperties import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters @@ -263,6 +264,40 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { assert result[1].currentTrustLevel == TrustLevel.COMPLETE } + def 'Execute cm handle reference search with a valid condition name'() { + given: 'a valid API parameter with a supported condition' + def apiParams = new CmHandleQueryApiParameters( + cmHandleQueryParameters: [ + new ConditionApiProperties( + conditionName: 'hasAllProperties', + conditionParameters: [[ 'some key': 'some value' ]] + ) + ] + ) + and: 'the system returns a cm handle id' + mockParameterizedCmHandleQueryService.queryInventoryForCmHandles(_) + >> Flux.fromIterable([new NcmpServiceCmHandle(cmHandleId: 'cm handle from the query service')]) + when: 'executing the cm handle search' + def result = objectUnderTest.executeCmHandleInventorySearch(apiParams).collectList().block() + then: 'the result returns the cm handle from the query service' + assert result.size() == 1 + assert result[0].cmHandleId == 'cm handle from the query service' + } + + def 'Execute cm handle reference search with an invalid condition name'() { + given: 'an API parameter with an unsupported condition name' + def apiParams = new CmHandleQueryApiParameters( + cmHandleQueryParameters: [ + new ConditionApiProperties(conditionName: 'invalid condition name') + ] + ) + when: 'executing the search' + objectUnderTest.executeCmHandleInventorySearch(apiParams).collectList().block() + then: 'a data validation exception will be thrown' + def exception = thrown(DataValidationException) + assert exception.message == 'Invalid Query Parameter.' + } + def 'Set Cm Handle Data Sync flag.'() { when: 'setting data sync enabled flag' objectUnderTest.setDataSyncEnabled('ch-1',true) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy index 5d9a05c37a..82753efaaa 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy @@ -246,6 +246,31 @@ class ParameterizedCmHandleQueryServiceSpec extends Specification { 'both queries are null' | null | null || null } + def 'Query CM handle details by DMI service name.'() { + given: 'query parameters with the cmHandleWithDmiPlugin condition' + def queryParams = new CmHandleQueryServiceParameters( + cmHandleQueryParameters: [ + createConditionProperties('cmHandleWithDmiPlugin', [['some-key': 'some-value']]) + ] + ) + and: 'the query service returns a matching cm handle id' + def expectedCmHandleId = 'cm-handle from query service' + partiallyMockedCmHandleQueries.getCmHandleReferencesByDmiPluginIdentifier(_, false) >> [expectedCmHandleId] + and: 'the inventory persistence returns the matching cm handle object' + mockInventoryPersistence.getYangModelCmHandles([expectedCmHandleId]) >> [ + new YangModelCmHandle( + id: expectedCmHandleId, + dmiProperties: [new YangModelCmHandle.Property('name', 'value')], + publicProperties: [] + ) + ] + when: 'the query is executed' + def result = objectUnderTestWithPartiallyMockedQueries.queryInventoryForCmHandles(queryParams).collectList().block() + then: 'the result contains the correct cm handle id' + assert result.size() == 1 + assert result[0].cmHandleId == 'cm-handle from query service' + } + def createConditionProperties(String conditionName, List> conditionParameters) { return new ConditionProperties(conditionName : conditionName, conditionParameters : conditionParameters) } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy index 26541de64b..0ca665604e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy @@ -26,11 +26,12 @@ import spock.lang.Specification class CmHandleQueryConditionsSpec extends Specification { def 'CmHandle query condition names.'() { - expect: '3 conditions with the correct names' - assert CmHandleQueryConditions.ALL_CONDITION_NAMES.size() == 4 + expect: '5 conditions with the correct names' + assert CmHandleQueryConditions.ALL_CONDITION_NAMES.size() == 5 assert CmHandleQueryConditions.ALL_CONDITION_NAMES.containsAll('hasAllProperties', 'hasAllModules', 'cmHandleWithCpsPath', + 'cmHandleWithDmiPlugin', 'cmHandleWithTrustLevel') } diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml index 8c2e472240..2e4100f8ed 100644 --- a/cps-rest/pom.xml +++ b/cps-rest/pom.xml @@ -133,7 +133,7 @@ org.openapitools openapi-generator-maven-plugin - 6.6.0 + 7.12.0 code-gen diff --git a/docker-compose/cps-base.yml b/docker-compose/cps-base.yml index 2391fb2441..42bfe15909 100644 --- a/docker-compose/cps-base.yml +++ b/docker-compose/cps-base.yml @@ -56,7 +56,8 @@ services: cps-and-ncmp-template: image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/cps-and-ncmp:${CPS_VERSION:-latest} ### DEBUG: Uncomment next line to enable java debugging (ensure 'ports' aligns with 'deploy') - ### - ${CPS_CORE_DEBUG_PORT:-5005}:5005- + ### ports: + ### - ${CPS_CORE_DEBUG_PORT:-5005}:5005 environment: DB_HOST: ${DB_HOST:-dbpostgresql} DB_USERNAME: ${DB_USERNAME:-cps} diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index 62ac66abeb..7192ab6d16 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -1141,7 +1141,6 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: object description: OK @@ -1239,14 +1238,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: object application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -1345,14 +1342,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSampleForV3' - value: null schema: type: object application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXmlForV3' - value: null schema: type: object xml: @@ -1552,14 +1547,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: string application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -1680,14 +1673,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: string application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -1817,14 +1808,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: string application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -2020,14 +2009,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: string application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -2145,14 +2132,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: string application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -2256,7 +2241,6 @@ paths: examples: dataSample: $ref: '#/components/examples/deltaReportSample' - value: null schema: type: object description: OK @@ -2336,7 +2320,6 @@ paths: examples: dataSample: $ref: '#/components/examples/deltaReportSample' - value: null schema: type: object description: OK @@ -2430,7 +2413,6 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: object description: OK @@ -2526,14 +2508,12 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSample' - value: null schema: type: object application/xml: examples: dataSample: $ref: '#/components/examples/dataSampleXml' - value: null schema: type: object xml: @@ -2631,7 +2611,6 @@ paths: examples: dataSample: $ref: '#/components/examples/dataSampleAcrossAnchors' - value: null schema: type: object description: OK @@ -2821,7 +2800,6 @@ paths: examples: dataSample: $ref: '#/components/examples/NotificationSubscriptionsDataSample' - value: null schema: type: object required: true @@ -3260,6 +3238,10 @@ components: description: Unauthorized schemas: ErrorMessage: + example: + details: details + message: message + status: status properties: status: type: string diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml index c1ca0ae9ac..df474755f7 100644 --- a/docs/api/swagger/ncmp/openapi-inventory.yaml +++ b/docs/api/swagger/ncmp/openapi-inventory.yaml @@ -188,6 +188,74 @@ paths: summary: Query for CM Handle IDs tags: - network-cm-proxy-inventory + /v1/ch/searchCmHandles: + post: + description: Execute cm handle query search and return a list of cm handle details. + Any number of conditions can be applied. To be included in the result a cm-handle + must fulfill ALL the conditions. An empty collection will be returned in the + case that the cm handle does not match a condition. For more on cm handle + query search please refer to cm + handle query search Read the Docs.
By supplying a CPS Path it is possible + to query on any data related to the cm handle. For more on CPS Path please + refer to CPS + Path Read the Docs. The cm handle ancestor is automatically returned for + this query. + operationId: searchCmHandles + parameters: + - description: Whether to include private properties in the response. + in: query + name: includePrivatePropertiesInQuery + required: false + schema: + type: boolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CmHandleQueryParameters' + required: true + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/RestOutputCmHandle' + type: array + description: OK + "400": + content: + application/json: + example: + status: 400 + message: Bad request error message + details: Bad request error details + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Bad Request + "403": + content: + application/json: + example: + status: 403 + message: Forbidden error message + details: Forbidden error details + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Forbidden + "500": + content: + application/json: + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Internal Server Error + summary: Query Cm Handles for a requested DMI Service + tags: + - network-cm-proxy-inventory components: parameters: dmiPluginIdentifierInQuery: @@ -370,11 +438,6 @@ components: required: - cmHandle type: object - RestCmHandleProperties: - additionalProperties: - example: my-property - type: string - type: object UpgradedCmHandles: example: cmHandles: @@ -399,6 +462,10 @@ components: - cmHandles type: object ErrorMessage: + example: + details: details + message: message + status: status properties: status: type: string @@ -409,6 +476,35 @@ components: title: Error type: object DmiPluginRegistrationErrorResponse: + example: + failedCreatedCmHandles: + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + failedUpgradeCmHandles: + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + failedRemovedCmHandles: + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + failedUpdatedCmHandles: + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" + - cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" properties: failedCreatedCmHandles: items: @@ -428,6 +524,10 @@ components: type: array type: object CmHandlerRegistrationErrorResponse: + example: + cmHandle: my-cm-handle + errorText: Unknown error. + errorCode: "00" properties: cmHandle: example: my-cm-handle @@ -508,3 +608,134 @@ components: moduleName: example: my-module type: string + RestOutputCmHandle: + example: + cmHandle: my-cm-handle1 + alternateId: "Subnetwork=Europe,ManagedElement=X123" + dataProducerIdentifier: my-data-producer-identifier + publicCmHandleProperties: + - key: 3gpp Type + - key: 3gpp Type + state: + dataSyncEnabled: false + dataSyncState: + running: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + operational: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + cmHandleState: ADVISED + lockReason: + reason: LOCKED_MISBEHAVING + details: locked due to failure in module sync + lastUpdateTime: 2022-12-31T20:30:40.000+0000 + trustLevel: COMPLETE + moduleSetTag: my-module-set-tag + privateCmHandleProperties: + key: 3gpp Type + properties: + cmHandle: + example: my-cm-handle1 + type: string + publicCmHandleProperties: + items: + additionalProperties: + example: 3gpp Type + type: string + type: object + type: array + privateCmHandleProperties: + additionalProperties: + example: 3gpp Type + type: string + type: object + state: + $ref: '#/components/schemas/CmHandleCompositeState' + trustLevel: + description: Current trust level of the relevant CM handle ID. + example: COMPLETE + type: string + moduleSetTag: + example: my-module-set-tag + type: string + alternateId: + example: "Subnetwork=Europe,ManagedElement=X123" + type: string + dataProducerIdentifier: + example: my-data-producer-identifier + type: string + title: CM handle Details + type: object + CmHandleCompositeState: + example: + dataSyncEnabled: false + dataSyncState: + running: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + operational: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + cmHandleState: ADVISED + lockReason: + reason: LOCKED_MISBEHAVING + details: locked due to failure in module sync + lastUpdateTime: 2022-12-31T20:30:40.000+0000 + properties: + cmHandleState: + example: ADVISED + type: string + lockReason: + $ref: '#/components/schemas/lock-reason' + lastUpdateTime: + example: 2022-12-31T20:30:40.000+0000 + type: string + dataSyncEnabled: + example: false + type: boolean + dataSyncState: + $ref: '#/components/schemas/dataStores' + type: object + lock-reason: + example: + reason: LOCKED_MISBEHAVING + details: locked due to failure in module sync + properties: + reason: + example: LOCKED_MISBEHAVING + type: string + details: + example: locked due to failure in module sync + type: string + type: object + dataStores: + example: + running: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + operational: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + properties: + operational: + $ref: '#/components/schemas/sync-state' + running: + $ref: '#/components/schemas/sync-state' + type: object + sync-state: + example: + lastSyncTime: 2022-12-31T20:30:40.000+0000 + syncState: NONE_REQUESTED + properties: + syncState: + example: NONE_REQUESTED + type: string + lastSyncTime: + example: 2022-12-31T20:30:40.000+0000 + type: string + type: object + CmHandleTrustLevel: + description: Current trust level of the relevant CM handle ID. + example: COMPLETE + type: string diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml index aa72e4b420..4c62602c51 100644 --- a/docs/api/swagger/ncmp/openapi.yaml +++ b/docs/api/swagger/ncmp/openapi.yaml @@ -207,7 +207,6 @@ paths: examples: dataSampleResponse: $ref: '#/components/examples/dataSampleResponse' - value: null schema: type: object description: OK @@ -310,7 +309,6 @@ paths: examples: dataSampleRequest: $ref: '#/components/examples/dataSamplePatchRequest' - value: null schema: type: object required: true @@ -429,14 +427,12 @@ paths: examples: dataSampleRequest: $ref: '#/components/examples/dataSampleRequest' - value: null schema: type: object application/yang-data+json: examples: dataSampleRequest: $ref: '#/components/examples/dataSampleRequest' - value: null schema: type: object required: true @@ -553,14 +549,12 @@ paths: examples: dataSampleRequest: $ref: '#/components/examples/dataSampleRequest' - value: null schema: type: object application/yang-data+json: examples: dataSampleRequest: $ref: '#/components/examples/dataSampleRequest' - value: null schema: type: object required: true @@ -794,7 +788,6 @@ paths: examples: dataSampleResponse: $ref: '#/components/examples/dataSampleResponse' - value: null schema: type: object description: OK @@ -980,19 +973,14 @@ paths: examples: Cm handle properties query: $ref: '#/components/examples/pubPropCmHandleQueryParameters' - value: null Cm handle modules query: $ref: '#/components/examples/modulesCmHandleQueryParameters' - value: null All cm handle query parameters: $ref: '#/components/examples/allCmHandleQueryParameters' - value: null Cm handle with CPS path state query: $ref: '#/components/examples/cpsPathCmHandleStateQueryParameters' - value: null Cm handle with data sync flag query: $ref: '#/components/examples/cpsPathCmHandleDataSyncQueryParameters' - value: null schema: $ref: '#/components/schemas/CmHandleQueryParameters' required: true @@ -1111,7 +1099,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/RestOutputCmHandlePublicProperties' + $ref: '#/components/schemas/RestOutputPublicCmHandleProperties' description: OK "400": content: @@ -1174,19 +1162,14 @@ paths: examples: Cm handle properties query: $ref: '#/components/examples/pubPropCmHandleQueryParameters' - value: null Cm handle modules query: $ref: '#/components/examples/modulesCmHandleQueryParameters' - value: null All cm handle query parameters: $ref: '#/components/examples/allCmHandleQueryParameters' - value: null Cm handle with CPS path state query: $ref: '#/components/examples/cpsPathCmHandleStateQueryParameters' - value: null Cm handle with data sync flag query: $ref: '#/components/examples/cpsPathCmHandleDataSyncQueryParameters' - value: null schema: $ref: '#/components/schemas/CmHandleQueryParameters' required: true @@ -1737,6 +1720,10 @@ components: description: The request is larger than the server is willing or able to process schemas: ErrorMessage: + example: + details: details + message: message + status: status properties: status: type: string @@ -1747,6 +1734,11 @@ components: title: Error type: object DmiErrorMessage: + example: + message: Bad Gateway Error Message NCMP + dmi-response: + body: Bad Request + http-code: 400 properties: message: example: Bad Gateway Error Message NCMP @@ -1961,6 +1953,8 @@ components: lastUpdateTime: 2022-12-31T20:30:40.000+0000 trustLevel: COMPLETE moduleSetTag: my-module-set-tag + privateCmHandleProperties: + key: 3gpp Type properties: cmHandle: example: my-cm-handle1 @@ -1972,6 +1966,11 @@ components: type: string type: object type: array + privateCmHandleProperties: + additionalProperties: + example: 3gpp Type + type: string + type: object state: $ref: '#/components/schemas/CmHandleCompositeState' trustLevel: @@ -1989,13 +1988,6 @@ components: type: string title: CM handle Details type: object - CmHandlePublicProperties: - items: - additionalProperties: - example: 3gpp Type - type: string - type: object - type: array CmHandleCompositeState: example: dataSyncEnabled: false @@ -2068,7 +2060,7 @@ components: description: Current trust level of the relevant CM handle ID. example: COMPLETE type: string - RestOutputCmHandlePublicProperties: + RestOutputPublicCmHandleProperties: example: publicCmHandleProperties: - key: 3gpp Type @@ -2103,6 +2095,9 @@ components: $ref: '#/components/schemas/CmHandleCompositeState' type: object DmiErrorMessage_dmi_response: + example: + body: Bad Request + http-code: 400 properties: http-code: example: 400 diff --git a/policy-executor-stub/pom.xml b/policy-executor-stub/pom.xml index 40c684b4d8..af582f76ae 100644 --- a/policy-executor-stub/pom.xml +++ b/policy-executor-stub/pom.xml @@ -128,7 +128,7 @@ org.openapitools openapi-generator-maven-plugin - 6.6.0 + 7.12.0 code-gen