From 4cf4962b74765a5afe234aa258a9143ea6936f73 Mon Sep 17 00:00:00 2001 From: mpriyank Date: Fri, 20 May 2022 15:25:15 +0100 Subject: Enhanced response with Complex State in API - Introduced RestOutputCmHandleState in API specs of retrieveCmHandleDetailsById - Mapper to map CompositeState to RestOutputCmHandleState - Enhanced existing test cases and introduced new one to test the mapping result Issue-ID: CPS-1047 Change-Id: I34fa198287e5d920bc0cea312ee4e368f3be2b90 Signed-off-by: mpriyank --- .../rest/controller/NetworkCmProxyController.java | 4 ++ .../rest/mapper/RestOutputCmHandleStateMapper.java | 79 ++++++++++++++++++++++ .../controller/NetworkCmProxyControllerSpec.groovy | 46 +++++++++++-- .../NetworkCmProxyRestExceptionHandlerSpec.groovy | 4 ++ .../RestOutputCmHandleStateMapperTest.groovy | 75 ++++++++++++++++++++ 5 files changed, 203 insertions(+), 5 deletions(-) create mode 100644 cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java create mode 100644 cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy (limited to 'cps-ncmp-rest/src') 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 ca7e258bc4..cedc94672c 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 @@ -46,6 +46,7 @@ import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException; import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters; import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi; +import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper; import org.onap.cps.ncmp.rest.model.CmHandleProperties; import org.onap.cps.ncmp.rest.model.CmHandleProperty; import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties; @@ -79,6 +80,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { private final NetworkCmProxyDataService networkCmProxyDataService; private final JsonObjectMapper jsonObjectMapper; private final NcmpRestInputMapper ncmpRestInputMapper; + private final RestOutputCmHandleStateMapper restOutputCmHandleStateMapper; /** * Get resource data from operational datastore. @@ -312,6 +314,8 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId()); cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties()); restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties); + restOutputCmHandle.setState(restOutputCmHandleStateMapper.toRestOutputCmHandleState( + ncmpServiceCmHandle.getCompositeState())); return restOutputCmHandle; } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java new file mode 100644 index 0000000000..89015cca9d --- /dev/null +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.api.inventory.CmHandleState; +import org.onap.cps.ncmp.api.inventory.CompositeState; +import org.onap.cps.ncmp.rest.model.DataStores; +import org.onap.cps.ncmp.rest.model.RestOutputCmHandleState; +import org.onap.cps.ncmp.rest.model.SyncState; + +@Mapper(componentModel = "spring") +public interface RestOutputCmHandleStateMapper { + + @Mapping(target = "dataSyncState", source = "dataStores", qualifiedByName = "dataStoreToDataSyncState") + @Mapping(target = "cmHandleState", source = "cmhandleState", qualifiedByName = "cmHandleStateEnumToString") + RestOutputCmHandleState toRestOutputCmHandleState(CompositeState compositeState); + + /** + * Convert from CompositeState datastore to RestOutput Datastores. + * + * @param compositeStateDataStore Composite State data stores + * @return DataStores + */ + @Named("dataStoreToDataSyncState") + static DataStores toDataStores(CompositeState.DataStores compositeStateDataStore) { + + final DataStores dataStores = new DataStores(); + + if (compositeStateDataStore.getRunningDataStore() != null) { + final SyncState runningSyncState = new SyncState(); + runningSyncState.setState(compositeStateDataStore.getRunningDataStore().getSyncState()); + runningSyncState.setLastSyncTime(compositeStateDataStore.getRunningDataStore().getLastSyncTime()); + dataStores.setRunning(runningSyncState); + } + + if (compositeStateDataStore.getOperationalDataStore() != null) { + final SyncState operationalSyncState = new SyncState(); + operationalSyncState.setState(compositeStateDataStore.getOperationalDataStore().getSyncState()); + operationalSyncState.setLastSyncTime(compositeStateDataStore.getOperationalDataStore().getLastSyncTime()); + dataStores.setOperational(operationalSyncState); + } + + + return dataStores; + + } + + /** + * Converts cmHandleState enum value to equivalent string. + * @param cmHandleState cm handle state enum + * @return cm handle state as string + */ + @Named("cmHandleStateEnumToString") + static String toCmHandleState(final CmHandleState cmHandleState) { + return cmHandleState.name(); + } + +} 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 ba49321d85..6cf1506681 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 @@ -24,10 +24,21 @@ package org.onap.cps.ncmp.rest.controller import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeState import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper import spock.lang.Shared +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH +import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores +import static org.onap.cps.ncmp.api.inventory.CompositeState.LockReason +import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational +import static org.onap.cps.ncmp.api.inventory.CompositeState.Running 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 @@ -69,6 +80,12 @@ class NetworkCmProxyControllerSpec extends Specification { @SpringBean NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper) + @SpringBean + RestOutputCmHandleStateMapper restOutputCmHandleStateMapper = Mappers.getMapper(RestOutputCmHandleStateMapper) + + def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) + @Value('${rest.api.ncmp-base-path}/v1') def ncmpBasePathV1 @@ -225,24 +242,32 @@ class NetworkCmProxyControllerSpec extends Specification { response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id1"},{"cmHandleId":"some-cmhandle-id2"}]}' } - def 'Get Cm Handle details by Cm Handle id.' () { + def 'Get Cm Handle details by Cm Handle id.'() { given: 'an endpoint and a cm handle' def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle" and: 'an existing ncmp service cm handle' def cmHandleId = 'some-cm-handle' def dmiProperties = [ prop:'some DMI property' ] def publicProperties = [ "public prop":'some public property' ] - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties) + def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED, + lockReason: LockReason.builder().reason('LOCKED_OTHER').details("lock-misbehaving-details").build(), + lastUpdateTime: formattedDateAndTime.toString(), + dataSyncEnabled: false, + dataStores: dataStores()) + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState) and: 'the service method is invoked with the cm handle id' 1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('some-cm-handle') >> ncmpServiceCmHandle when: 'the cm handle details api is invoked' def response = mvc.perform(get(cmHandleDetailsEndpoint)).andReturn().response then: 'the correct response is returned' response.status == HttpStatus.OK.value() - and: 'the response returns public properties and the correct properties' + and: 'the response returns public properties and the correct cm handle states' response.contentAsString.contains('publicCmHandleProperties') - response.contentAsString.contains('public prop') - response.contentAsString.contains('some public property') + response.contentAsString.contains('LOCKED_OTHER') + response.contentAsString.contains('lock-misbehaving-details') + response.contentAsString.contains('ADVISED') + response.contentAsString.contains('NONE_REQUESTED') + response.contentAsString.contains('2022-12-31T20:30:40.000+0000') and: 'the content does not contain dmi properties' !response.contentAsString.contains("some DMI property") } @@ -348,5 +373,16 @@ class NetworkCmProxyControllerSpec extends Specification { ':passthrough-running' | 'passthrough-running' } + def dataStores() { + DataStores.builder() + .operationalDataStore(Operational.builder() + .syncState('NONE_REQUESTED') + .lastSyncTime(formattedDateAndTime.toString()).build()) + .runningDataStore(Running.builder() + .syncState('NONE_REQUESTED') + .lastSyncTime(formattedDateAndTime.toString()).build()) + .build() + } + } diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy index 751fdcd8b9..1258e6e1c4 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy @@ -29,6 +29,7 @@ import org.onap.cps.ncmp.api.impl.exception.DmiRequestException import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper +import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.exceptions.DataNodeNotFoundException import org.onap.cps.spi.exceptions.DataValidationException @@ -66,6 +67,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { @SpringBean NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper) + @SpringBean + RestOutputCmHandleStateMapper restOutputCmHandleStateMapper = Mappers.getMapper(RestOutputCmHandleStateMapper) + @Value('${rest.api.ncmp-base-path}') def basePathNcmp diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy new file mode 100644 index 0000000000..4560ae4818 --- /dev/null +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.mapper + +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeState +import org.onap.cps.ncmp.rest.model.RestOutputCmHandleState +import spock.lang.Specification + +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + +import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores +import static org.onap.cps.ncmp.api.inventory.CompositeState.LockReason +import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational + +class RestOutputCmHandleStateMapperTest extends Specification { + + def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) + def objectUnderTest = Mappers.getMapper(RestOutputCmHandleStateMapper) + + def 'Composite State to Rest Output CmHandleState'() { + given: 'a composite state model' + def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED, + lockReason: LockReason.builder().reason('LOCKED_OTHER').details('locked-other-details').build(), + lastUpdateTime: formattedDateAndTime.toString(), + dataSyncEnabled: false, + dataStores: dataStores()) + when: 'mapper is called' + def result = objectUnderTest.toRestOutputCmHandleState(compositeState) + then: 'result is of the correct type' + assert result.class == RestOutputCmHandleState.class + and: 'mapped result should have correct values' + assert !result.dataSyncEnabled + assert result.lastUpdateTime == formattedDateAndTime + assert result.lockReason.reason == 'LOCKED_OTHER' + assert result.lockReason.details == 'locked-other-details' + assert result.cmHandleState == CmHandleState.ADVISED.name() + assert result.dataSyncState.operational != null + assert result.dataSyncState.running != null + } + + def dataStores() { + + return DataStores.builder() + .operationalDataStore(Operational.builder() + .syncState('NONE_REQUESTED') + .lastSyncTime(formattedDateAndTime.toString()).build()) + .runningDataStore(CompositeState.Running.builder() + .syncState('NONE_REQUESTED') + .lastSyncTime(formattedDateAndTime.toString()).build()) + .build() + } +} -- cgit 1.2.3-korg