Get cm-handle state endpoint 76/129476/11
authorlukegleeson <luke.gleeson@est.tech>
Thu, 2 Jun 2022 09:56:43 +0000 (10:56 +0100)
committerlukegleeson <luke.gleeson@est.tech>
Wed, 29 Jun 2022 11:03:30 +0000 (12:03 +0100)
Added new get cm-handle state endpoint
Refactored RestOutputCmHandleState to CmHandleCompositeState
Created new RestOutputCmHandleCompositeState OpenApi object
^This is done so that we get '"state: {" at the start of JSON response
Refactored RestOutputCmHandleStateMapper to CmHandleStateMapper
Added more detailed composite state to get cmHandleDetails endpoint tests
Rebased code
Code rebased on top of 129658: Unable to change state from LOCKED to ADVISED | https://gerrit.onap.org/r/c/cps/+/129658 which fixes output error

Issue-ID: CPS-1019
Signed-off-by: mpriyank <priyank.maheshwari@est.tech>
Signed-off-by: lukegleeson <luke.gleeson@est.tech>
Change-Id: I361117c98c256a4aa578c13d21926bc6d7876a15

12 files changed:
cps-ncmp-rest/docs/openapi/components.yaml
cps-ncmp-rest/docs/openapi/ncmp.yml
cps-ncmp-rest/docs/openapi/openapi.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java [moved from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java with 92% similarity]
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperTest.groovy [moved from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy with 88% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy

index 248b1da..cf254e5 100644 (file)
@@ -209,7 +209,7 @@ components:
         publicCmHandleProperties:
           $ref: '#/components/schemas/CmHandlePublicProperties'
         state:
-          $ref: '#/components/schemas/RestOutputCmHandleState'
+          $ref: '#/components/schemas/CmHandleCompositeState'
     CmHandlePublicProperties:
       type: array
       items:
@@ -217,7 +217,7 @@ components:
         additionalProperties:
           type: string
           example: Book Type
-    RestOutputCmHandleState:
+    CmHandleCompositeState:
       type: object
       properties:
         cmHandleState:
@@ -268,6 +268,12 @@ components:
         publicCmHandleProperties:
           $ref: '#/components/schemas/CmHandlePublicProperties'
 
+    RestOutputCmHandleCompositeState:
+      type: object
+      properties:
+        state:
+          $ref: '#/components/schemas/CmHandleCompositeState'
+
   examples:
     dataSampleRequest:
         summary: Sample request
index 3259032..8bdaa82 100755 (executable)
@@ -293,6 +293,10 @@ retrieveCmHandleDetailsById:
           application/json:
             schema:
               $ref: 'components.yaml#/components/schemas/RestOutputCmHandle'
+      400:
+        $ref: 'components.yaml#/components/responses/BadRequest'
+      401:
+        $ref: 'components.yaml#/components/responses/Unauthorized'
       404:
         $ref: 'components.yaml#/components/responses/NotFound'
       500:
@@ -314,6 +318,35 @@ getCmHandlePropertiesById:
           application/json:
             schema:
               $ref: 'components.yaml#/components/schemas/RestOutputCmHandlePublicProperties'
+      400:
+        $ref: 'components.yaml#/components/responses/BadRequest'
+      401:
+        $ref: 'components.yaml#/components/responses/Unauthorized'
+      404:
+        $ref: 'components.yaml#/components/responses/NotFound'
+      500:
+        $ref: 'components.yaml#/components/responses/InternalServerError'
+
+getCmHandleStateById:
+  get:
+    description: Get CM handle state by cm handle id
+    tags:
+      - network-cm-proxy
+    summary: Get CM handle state
+    operationId: getCmHandleStateByCmHandleId
+    parameters:
+      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+    responses:
+      200:
+        description: OK
+        content:
+          application/json:
+            schema:
+              $ref: 'components.yaml#/components/schemas/RestOutputCmHandleCompositeState'
+      400:
+        $ref: 'components.yaml#/components/responses/BadRequest'
+      401:
+        $ref: 'components.yaml#/components/responses/Unauthorized'
       404:
         $ref: 'components.yaml#/components/responses/NotFound'
       500:
index 81ebf05..ad7dd1d 100755 (executable)
@@ -46,3 +46,6 @@ paths:
 
   /v1/ch/id-searches:
     $ref: 'ncmp.yml#/searchCmHandleIds'
+
+  /v1/ch/{cm-handle}/state:
+    $ref: 'ncmp.yml#/getCmHandleStateById'
index fb234ef..7abefe6 100755 (executable)
@@ -40,15 +40,17 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
 import org.onap.cps.ncmp.api.impl.exception.InvalidTopicException;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
 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.executor.CpsNcmpTaskExecutor;
-import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper;
+import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper;
 import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
 import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
 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.util.DeprecationHelper;
 import org.onap.cps.utils.CpsValidator;
@@ -73,7 +75,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
 
     private final DeprecationHelper deprecationHelper;
     private final NcmpRestInputMapper ncmpRestInputMapper;
-    private final RestOutputCmHandleStateMapper restOutputCmHandleStateMapper;
+    private final CmHandleStateMapper cmHandleStateMapper;
     private final CpsNcmpTaskExecutor cpsNcmpTaskExecutor;
 
     @Value("${notification.async.executor.time-out-value-in-ms:2000}")
@@ -253,7 +255,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
     /**
      * Get Cm Handle Properties by Cm Handle Id.
      * @param cmHandleId cm-handle identifier
-     * @return cm handle and its properties
+     * @return cm handle properties
      */
     @Override
     public ResponseEntity<RestOutputCmHandlePublicProperties> getCmHandlePublicPropertiesByCmHandleId(
@@ -266,6 +268,21 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         return ResponseEntity.ok(restOutputCmHandlePublicProperties);
     }
 
+    /**
+     * Get Cm Handle State by Cm Handle Id.
+     * @param cmHandleId cm-handle identifier
+     * @return cm handle state
+     */
+    @Override
+    public ResponseEntity<RestOutputCmHandleCompositeState> getCmHandleStateByCmHandleId(
+        final String cmHandleId) {
+        final CompositeState cmHandleState = networkCmProxyDataService.getCmHandleCompositeState(cmHandleId);
+        final RestOutputCmHandleCompositeState restOutputCmHandleCompositeState =
+            new RestOutputCmHandleCompositeState();
+        restOutputCmHandleCompositeState.setState(cmHandleStateMapper.toCmHandleCompositeState(cmHandleState));
+        return ResponseEntity.ok(restOutputCmHandleCompositeState);
+    }
+
     /**
      * Return module references for a cm handle.
      *
@@ -286,7 +303,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId());
         cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties());
         restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties);
-        restOutputCmHandle.setState(restOutputCmHandleStateMapper.toRestOutputCmHandleState(
+        restOutputCmHandle.setState(cmHandleStateMapper.toCmHandleCompositeState(
                 ncmpServiceCmHandle.getCompositeState()));
         return restOutputCmHandle;
     }
@@ -26,17 +26,17 @@ import org.mapstruct.Named;
 import org.mapstruct.NullValueCheckStrategy;
 import org.mapstruct.NullValuePropertyMappingStrategy;
 import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.rest.model.CmHandleCompositeState;
 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", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
         nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
-public interface RestOutputCmHandleStateMapper {
+public interface CmHandleStateMapper {
 
     @Mapping(target = "dataSyncState", source = "dataStores", qualifiedByName = "dataStoreToDataSyncState")
     @Mapping(target = "lockReason.reason", source = "lockReason.lockReasonCategory")
-    RestOutputCmHandleState toRestOutputCmHandleState(CompositeState compositeState);
+    CmHandleCompositeState toCmHandleCompositeState(CompositeState compositeState);
 
     /**
      * Convert from CompositeState datastore to RestOutput Datastores.
index 7125810..93d8358 100644 (file)
@@ -27,8 +27,9 @@ 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.inventory.SyncState
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.onap.cps.ncmp.rest.mapper.RestOutputCmHandleStateMapper
+import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper
 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
 import org.onap.cps.ncmp.rest.util.DeprecationHelper
 import spock.lang.Shared
@@ -40,7 +41,6 @@ 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.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
@@ -83,7 +83,7 @@ class NetworkCmProxyControllerSpec extends Specification {
     NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper)
 
     @SpringBean
-    RestOutputCmHandleStateMapper restOutputCmHandleStateMapper = Mappers.getMapper(RestOutputCmHandleStateMapper)
+    CmHandleStateMapper cmHandleStateMapper = Mappers.getMapper(CmHandleStateMapper)
 
     @SpringBean
     CpsNcmpTaskExecutor spiedCpsTaskExecutor = Spy()
@@ -262,24 +262,27 @@ class NetworkCmProxyControllerSpec extends Specification {
             response.contentAsString == '[{"cmHandle":"some-cmhandle-id1","publicCmHandleProperties":[{"color":"yellow"}],"state":null},{"cmHandle":"some-cmhandle-id2","publicCmHandleProperties":[{"color":"green"}],"state":null}]'
     }
 
-    def 'Get Cm Handle details by Cm Handle id.'() {
+    def 'Get complete 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 compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
-                lastUpdateTime: formattedDateAndTime.toString(),
-                dataStores: dataStores())
-            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle', compositeState: compositeState)
+            def cmHandleId = 'some-cm-handle'
+            def dmiProperties = [ prop:'some DMI property' ]
+            def publicProperties = [ "public prop":'some public property' ]
+            def compositeState = compositeStateTestObject()
+            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 the correct state and timestamp'
-            response.contentAsString.contains('some-cm-handle')
-            response.contentAsString.contains('ADVISED')
-            response.contentAsString.contains('2022-12-31T20:30:40.000+0000')
+        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'
+            !response.contentAsString.contains("some DMI property")
     }
 
     def 'Get Cm Handle public properties by Cm Handle id.' () {
@@ -293,8 +296,23 @@ class NetworkCmProxyControllerSpec extends Specification {
             def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response
         then: 'the correct response is returned'
             response.status == HttpStatus.OK.value()
-        and: 'the response returns public properties and the correct properties'
-            response.contentAsString.equals('{"publicCmHandleProperties":[{"public prop":"some public property"}]}')
+        and: 'the response contains the public properties'
+            assertContainsPublicProperties(response)
+    }
+
+    def 'Get Cm Handle composite state by Cm Handle id.' () {
+        given: 'a cm handle state endpoint'
+            def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/state"
+        and: 'some cm handle composite state'
+            def compositeState = compositeStateTestObject()
+        and: 'the service method is invoked with the cm handle id returning the cm handle composite state'
+            1 * mockNetworkCmProxyDataService.getCmHandleCompositeState('some-cm-handle') >> compositeState
+        when: 'the cm handle state api is invoked'
+            def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response
+        then: 'the correct response is returned'
+            response.status == HttpStatus.OK.value()
+        and: 'the response contains the cm handle state'
+            assertContainsState(response)
     }
 
     def 'Call execute cm handle searches with unrecognized condition name.'() {
@@ -397,5 +415,44 @@ class NetworkCmProxyControllerSpec extends Specification {
                 .lastSyncTime(formattedDateAndTime.toString()).build()).build()
     }
 
+    def compositeStateTestObject() {
+        new CompositeState(cmHandleState: CmHandleState.ADVISED,
+            lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(),
+            lastUpdateTime: formattedDateAndTime.toString(),
+            dataSyncEnabled: false,
+            dataStores: dataStores())
+    }
+
+    def assertContainsAll(response, assertContent) {
+        assertContent.forEach( string -> { assert(response.contentAsString.contains(string)) })
+        return void
+    }
+
+    def assertContainsState(response) {
+        def expectedContent = [
+            '"state":',
+            '"cmHandleState":"ADVISED"',
+            '"reason":"LOCKED_MISBEHAVING"',
+            '"details":"lock misbehaving details"',
+            '"lastUpdateTime":"2022-12-31T20:30:40.000+0000"',
+            '"dataSyncEnabled":false',
+            '"dataSyncState":',
+            '"operational":',
+            '"state":"NONE_REQUESTED"',
+            '"lastSyncTime":"2022-12-31T20:30:40.000+0000"',
+            '"running":null'
+        ]
+        return assertContainsAll(response, expectedContent)
+    }
+
+    def assertContainsPublicProperties(response) {
+        def expectedContent = [
+            '"publicCmHandleProperties":' ,
+            '"public prop"' ,
+            '"some public property"'
+        ]
+        return assertContainsAll(response, expectedContent)
+    }
+
 }
 
index 1563c75..ce908e7 100644 (file)
@@ -29,7 +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.ncmp.rest.mapper.CmHandleStateMapper
 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
 import org.onap.cps.ncmp.rest.util.DeprecationHelper
 import org.onap.cps.spi.exceptions.CpsException
@@ -70,7 +70,7 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
     NcmpRestInputMapper ncmpRestInputMapper = Mappers.getMapper(NcmpRestInputMapper)
 
     @SpringBean
-    RestOutputCmHandleStateMapper restOutputCmHandleStateMapper = Mappers.getMapper(RestOutputCmHandleStateMapper)
+    CmHandleStateMapper cmHandleStateMapper = Mappers.getMapper(CmHandleStateMapper)
 
     @SpringBean
     CpsNcmpTaskExecutor stubbedCpsTaskExecutor = Stub()
@@ -25,18 +25,18 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
 import org.onap.cps.ncmp.api.inventory.LockReasonCategory
 import org.onap.cps.ncmp.api.inventory.SyncState
-import org.onap.cps.ncmp.rest.model.RestOutputCmHandleState
+import org.onap.cps.ncmp.rest.model.CmHandleCompositeState
 import spock.lang.Specification
 
 import java.time.OffsetDateTime
 import java.time.ZoneOffset
 import java.time.format.DateTimeFormatter
 
-class RestOutputCmHandleStateMapperTest extends Specification {
+class CmHandleStateMapperTest 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 objectUnderTest = Mappers.getMapper(CmHandleStateMapper)
 
     def 'Composite State to Rest Output CmHandleState'() {
         given: 'a composite state model'
@@ -47,9 +47,9 @@ class RestOutputCmHandleStateMapperTest extends Specification {
                 .withOperationalDataStores(SyncState.SYNCHRONIZED, formattedDateAndTime).build()
         compositeState.setDataSyncEnabled(false)
         when: 'mapper is called'
-            def result = objectUnderTest.toRestOutputCmHandleState(compositeState)
+            def result = objectUnderTest.toCmHandleCompositeState(compositeState)
         then: 'result is of the correct type'
-            assert result.class == RestOutputCmHandleState.class
+            assert result.class == CmHandleCompositeState.class
         and: 'mapped result should have correct values'
             assert !result.dataSyncEnabled
             assert result.lastUpdateTime == formattedDateAndTime
index ce850cc..1ad61e6 100644 (file)
@@ -28,6 +28,7 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
@@ -121,6 +122,14 @@ public interface NetworkCmProxyDataService {
      */
     Map<String, String> getCmHandlePublicProperties(String cmHandleId);
 
+    /**
+     * Get cm handle composite state by cm handle id.
+     *
+     * @param cmHandleId cm handle identifier
+     * @return a cm handle composite state
+     */
+    CompositeState getCmHandleCompositeState(String cmHandleId);
+
     /**
      * Query and return cm handles that match the given query parameters.
      *
index f44c28c..bfc7407 100755 (executable)
@@ -221,6 +221,18 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return cmHandlePublicProperties;
     }
 
+    /**
+     * Get cm handle composite state for a given cm handle id.
+     *
+     * @param cmHandleId cm handle identifier
+     * @return cm handle state
+     */
+    @Override
+    public CompositeState getCmHandleCompositeState(final String cmHandleId) {
+        CpsValidator.validateNameCharacters(cmHandleId);
+        return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
+    }
+
     /**
      * THis method registers a cm handle and initiates modules sync.
      *
index 1d4312c..92183f9 100644 (file)
@@ -27,6 +27,8 @@ import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.inventory.SyncState
 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
 import org.onap.cps.ncmp.api.models.ConditionApiProperties
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
@@ -169,19 +171,29 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def 'Get a cm handle.'() {
         given: 'the system returns a yang modelled cm handle'
             def dmiServiceName = 'some service name'
+            def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(),
+                lastUpdateTime: 'some-timestamp',
+                dataSyncEnabled: false,
+                dataStores: dataStores())
             def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
             def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
-            def compositeState = new CompositeState(cmHandleState: 'ADVISED')
             def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
                 dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
         when: 'getting cm handle details for a given cm handle id from ncmp service'
             def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
-        then: 'the result returns the correct data'
+        then: 'the result is a ncmpServiceCmHandle'
+            result.class == NcmpServiceCmHandle.class
+        and: 'the cm handle contains the cm handle id'
             result.cmHandleId == 'some-cm-handle'
+        and: 'the cm handle contains the DMI Properties'
             result.dmiProperties ==[ Book:'Romance Novel' ]
+        and: 'the cm handle contains the public Properties'
             result.publicProperties == [ "Public Book":'Public Romance Novel' ]
-            result.compositeState.cmHandleState == CmHandleState.ADVISED
+        and: 'the cm handle contains the cm handle composite state'
+            result.compositeState == compositeState
+
     }
 
     def 'Get a cm handle with an invalid id.'() {
@@ -207,7 +219,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     }
 
     def 'Get cm handle public properties with an invalid id.'() {
-        when: 'getting cm handle details for a given cm handle id with an invalid name'
+        when: 'getting cm handle public properties for a given cm handle id with an invalid name'
             objectUnderTest.getCmHandlePublicProperties('invalid cm handle with spaces')
         then: 'an exception is thrown'
             thrown(DataValidationException)
@@ -215,6 +227,33 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             0 * mockInventoryPersistence.getYangModelCmHandle(*_)
     }
 
+    def 'Get cm handle composite state'() {
+        given: 'a yang modelled cm handle'
+            def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(),
+                lastUpdateTime: 'some-timestamp',
+                dataSyncEnabled: false,
+                dataStores: dataStores())
+            def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
+            def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
+            def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
+        and: 'the system returns this yang modelled cm handle'
+            1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
+        when: 'getting cm handle composite state for a given cm handle id from ncmp service'
+            def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle')
+        then: 'the result returns the correct data'
+            result == compositeState
+    }
+
+    def 'Get cm handle composite state with an invalid id.'() {
+        when: 'getting cm handle composite state for a given cm handle id with an invalid name'
+            objectUnderTest.getCmHandleCompositeState('invalid cm handle with spaces')
+        then: 'an exception is thrown'
+            thrown(DataValidationException)
+        and: 'the yang model cm handle retriever is not invoked'
+            0 * mockInventoryPersistence.getYangModelCmHandle(_)
+    }
+
     def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
         given: 'cpsDataService returns valid datanode'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
@@ -265,4 +304,11 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         then: 'result is the same collection as returned by the CPS Data Service'
             assert result == ['cm-handle-id-1'] as Set
     }
+
+    def dataStores() {
+        CompositeState.DataStores.builder()
+            .operationalDataStore(CompositeState.Operational.builder()
+                .syncState(SyncState.NONE_REQUESTED)
+                .lastSyncTime('some-timestamp').build()).build()
+    }
 }
index 438ebed..cf9c6bb 100644 (file)
 package org.onap.cps.ncmp.api.models
 
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.CmHandleState
+import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.inventory.SyncState
 import spock.lang.Specification
 
 import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
@@ -34,6 +38,13 @@ class YangModelCmHandleSpec extends Specification {
             ncmpServiceCmHandle.cmHandleId = 'cm-handle-id01'
             ncmpServiceCmHandle.dmiProperties = [myDmiProperty:'value1']
             ncmpServiceCmHandle.publicProperties = [myPublicProperty:'value2']
+        and: 'with a composite state'
+            def compositeState = new CompositeStateBuilder()
+                .withCmHandleState(CmHandleState.LOCKED)
+                .withLastUpdatedTime('some-update-time')
+                .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, 'locked other details')
+                .withOperationalDataStores(SyncState.SYNCHRONIZED, 'some-sync-time').build()
+            ncmpServiceCmHandle.setCompositeState(compositeState)
         when: 'it is converted to a yang model cm handle'
             def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle)
         then: 'the result has the right size'
@@ -44,6 +55,9 @@ class YangModelCmHandleSpec extends Specification {
         and: 'the public property in the result has the correct name and value'
             assert objectUnderTest.publicProperties[0].name == 'myPublicProperty'
             assert objectUnderTest.publicProperties[0].value == 'value2'
+        and: 'the composite state matches the composite state of the ncmpServiceCmHandle'
+            objectUnderTest.getCompositeState().cmHandleState == CmHandleState.LOCKED
+            objectUnderTest.getCompositeState() == ncmpServiceCmHandle.getCompositeState()
     }
 
     def 'Resolve DMI service name: #scenario and #requiredService service require.'() {