Add test for missing code covereage 25/124025/4
authorToineSiebelink <toine.siebelink@est.tech>
Fri, 10 Sep 2021 10:45:17 +0000 (11:45 +0100)
committerToineSiebelink <toine.siebelink@est.tech>
Tue, 14 Sep 2021 10:30:54 +0000 (11:30 +0100)
- Add test for error scenarios and otehr mising tests
- set up for SpringBean testing
- some small typo fixes
- fixed some SQ violations

Issue-ID: CPS-656

Change-Id: If33f215c8ecaf090f27145005cc1aa7f0331d0f4
Signed-off-by: ToineSiebelink <toine.siebelink@est.tech>
13 files changed:
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/JsonUtils.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/JsonUtilsSpec.groovy
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/impl/client/DmiRestClientSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/moduleReferenceSpec.groovy
cps-ncmp-service/src/test/resources/application.yml [new file with mode: 0644]
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy

index 9ce32e3..6768777 100644 (file)
@@ -26,6 +26,9 @@ public class JsonUtils {
     private static final String NEW_LINE = "\n";
     private static final String QUOTE = "\"";
 
+    private JsonUtils() {
+        throw new IllegalStateException();
+    }
 
     /**
      * Remove redundant beginning and end characters.
index 24203c0..a28b73c 100755 (executable)
@@ -76,6 +76,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private static  final String NCMP_DMI_SERVICE_NAME = "dmi-service-name";
 
+    private  static final String REVISION = "revision";
+
     private CpsDataService cpsDataService;
 
     private ObjectMapper objectMapper;
@@ -88,8 +90,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private CpsAdminService cpsAdminService;
 
-    public static final String NO_NAMESPACE = null;
-
     /**
      * Constructor Injection for Dependencies.
      * @param dmiOperations DMI operation
@@ -279,11 +279,11 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     private String getGenericRequestBody(final DataNode cmHandleDataNode) {
         final Collection<DataNode> cmHandlePropertiesList = cmHandleDataNode.getChildDataNodes();
         final Map<String, String> cmHandlePropertiesMap = getCmHandlePropertiesAsMap(cmHandlePropertiesList);
-        final var requetBodyObject = GenericRequestBody.builder()
+        final var requestBodyObject = GenericRequestBody.builder()
                 .operation(GenericRequestBody.OperationEnum.READ)
                 .cmHandleProperties(cmHandlePropertiesMap)
                 .build();
-        return prepareOperationBody(requetBodyObject);
+        return prepareOperationBody(requestBodyObject);
     }
 
     private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
@@ -299,10 +299,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
             cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 "/dmi-registry", cmHandlesJsonData, NO_TIMESTAMP);
         } catch (final JsonProcessingException e) {
-            log.error("Parsing error occurred while converting Object to JSON DMI Registry.");
-            throw new DataValidationException(
-                "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
-                .getMessage(), e);
+            handleJsonProcessingException(dmiPluginRegistration, e);
         }
     }
 
@@ -317,17 +314,21 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
             }
             final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
 
-            registerAndSyncNode(dmiPluginRegistration, persistenceCmHandlesList, cmHandleJsonData);
+            registerAndSyncNode(persistenceCmHandlesList, cmHandleJsonData);
         } catch (final JsonProcessingException e) {
-            log.error("Parsing error occurred while converting Object to JSON for DMI Registry.");
-            throw new DataValidationException(
-                "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
-                .getMessage(), e);
+            handleJsonProcessingException(dmiPluginRegistration, e);
         }
     }
 
-    private void registerAndSyncNode(final DmiPluginRegistration dmiPluginRegistration,
-                                     final PersistenceCmHandlesList persistenceCmHandlesList,
+    private static void handleJsonProcessingException(final DmiPluginRegistration dmiPluginRegistration,
+                                                      final JsonProcessingException e) {
+        final String message = "Parsing error occurred while processing DMI Plugin Registration"
+            + dmiPluginRegistration;
+        log.error(message);
+        throw new DataValidationException(message, e.getMessage(), e);
+    }
+
+    private void registerAndSyncNode(final PersistenceCmHandlesList persistenceCmHandlesList,
                                      final String cmHandleJsonData) {
         cpsDataService.saveListNodeData(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
             cmHandleJsonData, NO_TIMESTAMP);
@@ -390,7 +391,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         cpsAdminService.createAnchor(NF_PROXY_DATASPACE_NAME, cmHandle.getId(), cmHandle.getId());
     }
 
-    private JsonObject getRequestBodyAsJson(final List<ModuleReference> unknownModuleReferences) {
+    private static JsonObject getRequestBodyAsJson(final List<ModuleReference> unknownModuleReferences) {
 
         final JsonObject requestBodyAsJson = new JsonObject();
         requestBodyAsJson.addProperty("operation", "read");
@@ -404,13 +405,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return requestBodyAsJson;
     }
 
-    private JsonArray getModuleReferencesAsJson(final List<ModuleReference> unknownModuleReferences) {
+    private static JsonArray getModuleReferencesAsJson(final List<ModuleReference> unknownModuleReferences) {
         final JsonArray moduleReferences = new JsonArray();
 
         for (final ModuleReference moduleReference : unknownModuleReferences) {
             final JsonObject moduleReferenceAsJson = new JsonObject();
             moduleReferenceAsJson.addProperty("name", moduleReference.getModuleName());
-            moduleReferenceAsJson.addProperty("revision", moduleReference.getRevision());
+            moduleReferenceAsJson.addProperty(REVISION, moduleReference.getRevision());
             moduleReferences.add(moduleReferenceAsJson);
         }
         return moduleReferences;
@@ -444,7 +445,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return yangResource;
     }
 
-    private List<ModuleReference> getModuleReferences(final ResponseEntity<String> response) {
+    private static List<ModuleReference> getModuleReferences(final ResponseEntity<String> response) {
         final List<ModuleReference> modulesFromDmiForCmHandle = new ArrayList<>();
         final JsonObject convertedObject = new Gson().fromJson(response.getBody(), JsonObject.class);
         final JsonArray moduleReferencesAsJson = convertedObject.getAsJsonArray("schemas");
@@ -456,7 +457,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return modulesFromDmiForCmHandle;
     }
 
-    private ModuleReference toModuleReference(final JsonObject moduleReferenceAsJson) {
+    private static ModuleReference toModuleReference(final JsonObject moduleReferenceAsJson) {
         final var moduleReference = new ModuleReference();
         moduleReference.setModuleName(moduleReferenceAsJson.get("moduleName").getAsString());
         moduleReference.setRevision(moduleReferenceAsJson.get("revision").getAsString());
index a834bfc..c4e82d3 100644 (file)
@@ -41,7 +41,7 @@ public class NcmpConfiguration {
     }
 
     @Bean
-    public RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder) {
+    public static RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder) {
         return restTemplateBuilder.build();
     }
-}
\ No newline at end of file
+}
index ff53464..2c75b5d 100644 (file)
@@ -43,17 +43,5 @@ public class NcmpException extends RuntimeException {
         this.details = details;
     }
 
-    /**
-     * Constructor.
-     *
-     * @param message the error message
-     * @param details the error details
-     * @param cause   the cause of the exception
-     */
-    public NcmpException(final String message, final String details, final Throwable cause) {
-        super(message, cause);
-        this.details = details;
-    }
-
 }
 
index 2b3d998..be27dfa 100644 (file)
@@ -40,5 +40,12 @@ class JsonUtilsSpec extends Specification  {
             'a string in apostrophes'          | "'abc'"  || 'abc'
             'a string inside any other tokens' | 'abcde'  || 'bcd'
     }
+
+    def 'Cannot use constructor.'() {
+        when: 'attempt to construct object'
+            new JsonUtils()
+        then: 'an exception is thrown'
+            thrown(IllegalStateException)
+    }
 }
 
index 3ebb455..8739355 100644 (file)
@@ -36,6 +36,8 @@ import org.onap.cps.ncmp.api.models.DmiPluginRegistration
 import org.onap.cps.ncmp.api.models.PersistenceCmHandle
 import org.onap.cps.ncmp.utils.TestUtils
 import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.model.DataNode
 import org.onap.cps.spi.model.ModuleReference
 import org.springframework.http.HttpStatus
@@ -56,9 +58,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def mockCpsModuleService = Mock(CpsModuleService)
     def mockCpsAdminService = Mock(CpsAdminService)
     def mockDmiProperties = Mock(NcmpConfiguration.DmiProperties)
+    def spyObjectMapper = Spy(ObjectMapper)
 
     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
-            mockCpsDataService, mockCpsQueryService, mockCpsAdminService, new ObjectMapper())
+            mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
 
     def cmHandle = 'some handle'
     def noTimestamp = null
@@ -154,12 +157,12 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
                 'ncmp-dmi-registry', "/dmi-registry/cm-handles[@id='cmHandle001']", noTimestamp)
 
         where:
-            scenario                        | createdCmHandles       | updatedCmHandles       | removedCmHandles || expectedCallsToSaveNode   | expectedCallsToUpdateNode | expectedCallsToDeleteListDataNode
-            'create'                        | [persistenceCmHandle ] | []                     | []               || 1                         | 0                         | 0
-            'update'                        | []                     | [persistenceCmHandle ] | []               || 0                         | 1                         | 0
-            'delete'                        | []                     | []                     | cmHandlesArray   || 0                         | 0                         | 1
-            'create, update and delete'     | [persistenceCmHandle ] | [persistenceCmHandle ] | cmHandlesArray   || 1                         | 1                         | 1
-
+            scenario                        | createdCmHandles      | updatedCmHandles      | removedCmHandles || expectedCallsToSaveNode   | expectedCallsToUpdateNode | expectedCallsToDeleteListDataNode
+            'create'                        | [persistenceCmHandle] | []                    | []               || 1                         | 0                         | 0
+            'update'                        | []                    | [persistenceCmHandle] | []               || 0                         | 1                         | 0
+            'delete'                        | []                    | []                    | cmHandlesArray   || 0                         | 0                         | 1
+            'create, update and delete'     | [persistenceCmHandle] | [persistenceCmHandle] | cmHandlesArray   || 1                         | 1                         | 1
+            'no valid data'                 | null                  | null                  |  null            || 0                         | 0                         | 0
     }
 
     def 'Register a DMI Plugin for the given cmHandle without additional properties.'() {
@@ -169,7 +172,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             dmiPluginRegistration.dmiPlugin = 'my-server'
             persistenceCmHandle.cmHandleID = '123'
             persistenceCmHandle.cmHandleProperties = null
-            dmiPluginRegistration.createdCmHandles = [persistenceCmHandle ]
+            dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
             def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","additional-properties":[]}]}'
         when: 'registration is updated'
             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
@@ -178,6 +181,37 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
                 '/dmi-registry', expectedJsonData, noTimestamp)
     }
 
+    def 'Register a DMI Plugin with JSON processing errors during #scenario.'() {
+        given: 'a registration without cmHandle properties '
+            NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+            def dmiPluginRegistration = new DmiPluginRegistration()
+            dmiPluginRegistration.createdCmHandles = createdCmHandles
+            dmiPluginRegistration.updatedCmHandles = updatedCmHandles
+        and: 'an JSON processing exception occurs'
+            spyObjectMapper.writeValueAsString(_) >> { throw (new JsonProcessingException('')) }
+        when: 'registration is updated'
+            objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+        then: 'a data validation exception is thrown'
+            thrown(DataValidationException)
+        where:
+            scenario | createdCmHandles      | updatedCmHandles
+            'create' | [persistenceCmHandle] | []
+            'update' | []                    | [persistenceCmHandle]
+    }
+
+    def 'Register a DMI Plugin with no data found during delete.'() {
+        given: 'a registration without cmHandle properties '
+            NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
+            def dmiPluginRegistration = new DmiPluginRegistration()
+            dmiPluginRegistration.removedCmHandles = ['some cm handle']
+        and: 'an JSON processing exception occurs'
+            mockCpsDataService.deleteListNodeData(*_) >>  { throw (new DataNodeNotFoundException('','')) }
+        when: 'registration is updated'
+            objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+        then: 'no exception is thrown'
+            noExceptionThrown()
+    }
+
     def 'Get resource data for pass-through operational from dmi.'() {
         given: 'data node representing cmHandle and its properties'
             def cmHandleDataNode = getCmHandleDataNodeForTest()
@@ -211,15 +245,16 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         and: 'objectMapper not able to parse object'
             def mockObjectMapper = Mock(ObjectMapper)
             objectUnderTest.objectMapper = mockObjectMapper
-            mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
+            mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
         when: 'get resource data is called'
             def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
                     'testResourceId',
                     'testAcceptParam',
                     'testFieldQuery',
                     5)
-        then: 'exception is thrown'
-            thrown(NcmpException.class)
+        then: 'exception is thrown with the expected details'
+            def exceptionThrown = thrown(NcmpException.class)
+            exceptionThrown.details == 'testException'
     }
 
     def 'Get resource data for pass-through operational from dmi return NOK response.'() {
@@ -244,7 +279,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
                     'testFieldQuery',
                     5)
         then: 'exception is thrown'
-            thrown(NcmpException.class)
+            def exceptionThrown = thrown(NcmpException.class)
+        and: 'details contains the original response'
+            exceptionThrown.details.contains('NOK-json')
     }
 
     def 'Get resource data for pass-through running from dmi.'() {
@@ -280,15 +317,16 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         and: 'objectMapper not able to parse object'
             def mockObjectMapper = Mock(ObjectMapper)
             objectUnderTest.objectMapper = mockObjectMapper
-            mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException("testException") }
+            mockObjectMapper.writeValueAsString(_) >> { throw new JsonProcessingException('testException') }
         when: 'get resource data is called'
             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
                     'testResourceId',
                     'testAcceptParam',
                     'testFieldQuery',
                     5)
-        then: 'exception is thrown'
-            thrown(NcmpException.class)
+        then: 'exception is thrown with the expected details'
+            def exceptionThrown = thrown(NcmpException.class)
+            exceptionThrown.details == 'testException'
     }
 
     def 'Get resource data for pass-through running from dmi return NOK response.'() {
@@ -313,7 +351,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
                     'testFieldQuery',
                     5)
         then: 'exception is thrown'
-            thrown(NcmpException.class)
+            def exceptionThrown = thrown(NcmpException.class)
+        and: 'details contains the original response'
+            exceptionThrown.details.contains('NOK-json')
     }
 
     def 'Write resource data for pass-through running from dmi using POST.'() {
@@ -348,7 +388,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
                     'testResourceId',
                     '{some-json}', 'application/json')
         then: 'exception is thrown'
-            thrown(NcmpException.class)
+            def exceptionThrown = thrown(NcmpException.class)
+        and: 'details contains (not found) error code: 404'
+            exceptionThrown.details.contains('404')
     }
 
     def 'Sync model for a (new) cm handle with #scenario'() {
@@ -373,6 +415,13 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             'no unknown module'  | '[]'                                                                                   || [:]
     }
 
+    def 'Getting Yang Resources.'() {
+        when: 'yang resources is called'
+            objectUnderTest.getYangResourcesModuleReferences('some cm handle')
+        then: 'CPS module services is invoked for the correct dataspace and cm handle'
+            1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
+    }
+
     def getModulesForCmHandle() {
         def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
         mockDmiProperties.getAuthUsername() >> 'someUser'
@@ -384,7 +433,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
 
     def getObjectUnderTestWithModelSyncDisabled() {
         def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
-                mockCpsDataService, mockCpsQueryService, mockCpsAdminService, new ObjectMapper()))
+                mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper))
         objectUnderTest.createAnchorAndSyncModel(_) >> null
         return objectUnderTest
     }
index 809c48a..bf6179b 100644 (file)
 package org.onap.cps.ncmp.api.impl.client
 
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.http.HttpEntity
 import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpMethod
 import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
 import org.springframework.web.client.RestTemplate
 import spock.lang.Specification
-import  org.springframework.http.HttpMethod
 
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiRestClient])
 class DmiRestClientSpec extends Specification {
 
-    def mockDmiProperties = Mock(NcmpConfiguration.DmiProperties)
-    def mockRestTemplate = Mock(RestTemplate)
-    def objectUnderTest = new DmiRestClient(mockRestTemplate, mockDmiProperties)
+    @SpringBean
+    RestTemplate mockRestTemplate = Mock(RestTemplate)
+
+    @Autowired
+    DmiRestClient objectUnderTest
 
     def 'DMI PUT operation.'() {
         given: 'a PUT url'
             def getResourceDataUrl = 'http://some-uri/getResourceDataUrl'
-        and: 'dmi properties'
-            setupTestConfigurationData()
         and: 'the rest template returns a valid response entity'
             def mockResponseEntity = Mock(ResponseEntity)
             mockRestTemplate.exchange(getResourceDataUrl, HttpMethod.PUT, _ as HttpEntity, Object.class) >> mockResponseEntity
@@ -51,8 +57,6 @@ class DmiRestClientSpec extends Specification {
     def 'DMI POST operation.'() {
         given: 'a POST url'
             def getResourceDataUrl = 'http://some-uri/createResourceDataUrl'
-        and: 'dmi properties'
-            setupTestConfigurationData()
         and: 'the rest template returns a valid response entity'
             def mockResponseEntity = Mock(ResponseEntity)
             mockRestTemplate.postForEntity(getResourceDataUrl, _ as HttpEntity, String.class) >> mockResponseEntity
@@ -62,8 +66,4 @@ class DmiRestClientSpec extends Specification {
             result == mockResponseEntity
     }
 
-    def setupTestConfigurationData() {
-        mockDmiProperties.authUsername >> 'some-username'
-        mockDmiProperties.authPassword >> 'some-password'
-    }
-}
\ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/NcmpConfigurationSpec.groovy
new file mode 100644 (file)
index 0000000..dd4c137
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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.api.impl.config
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.boot.web.client.RestTemplateBuilder
+import org.springframework.test.context.ContextConfiguration
+import org.springframework.web.client.RestTemplate
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [NcmpConfiguration.DmiProperties])
+class NcmpConfigurationSpec extends Specification{
+
+    @Autowired
+    NcmpConfiguration.DmiProperties dmiProperties
+
+    def 'DMI Properties.'() {
+        expect: 'properties are set to values in test configuration yaml file'
+            dmiProperties.authUsername == 'some-user'
+            dmiProperties.authPassword == 'some-password'
+    }
+
+    def 'Rest Template creation.'() {
+        given: 'a rest template builder'
+            def mockRestTemplateBuilder = Mock(RestTemplateBuilder)
+            def expectedRestTemplate = Mock(RestTemplate)
+            mockRestTemplateBuilder.build() >> expectedRestTemplate
+        when: 'a rest template is created'
+            def result = NcmpConfiguration.restTemplate(mockRestTemplateBuilder)
+        then: 'the rest template from the builder is returned'
+            assert result == expectedRestTemplate
+    }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
new file mode 100644 (file)
index 0000000..bfed795
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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.api.models
+
+import spock.lang.Specification
+
+class PersistenceCmHandleSpec extends Specification {
+
+    def objectUnderTest = new PersistenceCmHandle()
+
+    def 'Setting and getting additional properties.'() {
+        given: 'a map of one property is added'
+            objectUnderTest.setAdditionalProperties([myProperty: 'some value'])
+        when: 'the additional properties are retrieved'
+            def result = objectUnderTest.getAdditionalProperties()
+        then: 'the result has the right size'
+            assert result.size() == 1
+        and: 'the property in the result has the correct name and value'
+            def actualAdditionalProperty = result.get(0)
+            def expectedAdditionalProperty = new PersistenceCmHandle.AdditionalProperty('myProperty','some value')
+            assert actualAdditionalProperty.name == expectedAdditionalProperty.name
+            assert actualAdditionalProperty.value == expectedAdditionalProperty.value
+    }
+
+}
index 9f161a9..444a258 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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.api.models
 
 import org.onap.cps.spi.model.ExtendedModuleReference
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
new file mode 100644 (file)
index 0000000..71ac2c9
--- /dev/null
@@ -0,0 +1,23 @@
+#  ============LICENSE_START=======================================================
+#  Copyright (C) 2021 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=========================================================
+
+dmi:
+    auth:
+        username: some-user
+        password: some-password
+
index 8217a4f..e2316e8 100755 (executable)
  */
 package org.onap.cps.spi.impl
 
-import org.onap.cps.spi.exceptions.DataValidationException
-
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-
 import com.google.common.collect.ImmutableSet
 import com.google.gson.Gson
 import com.google.gson.GsonBuilder
@@ -42,6 +37,9 @@ import org.springframework.test.context.jdbc.Sql
 
 import javax.validation.ConstraintViolationException
 
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
 class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
 
     @Autowired
@@ -155,17 +153,25 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
-    def 'Add list-node fragment with multiple elements.'() {
-        given: 'list node data fragment as a collection of data nodes'
+    def 'Add list-node fragment with multiple elements including an element with a child datanode.'() {
+        given: 'two new data nodes for an existing list'
             def listNodeXpaths = ['/parent-201/child-204[@key="B"]', '/parent-201/child-204[@key="C"]']
             def listNodeCollection = buildDataNodeCollection(listNodeXpaths)
-        when: 'list-node elements added to existing parent node'
+        and: 'a child node for one of the new data nodes'
+            def childDataNode = buildDataNode('/parent-201/child-204[@key="C"]/grand-child-204[@key2="Z"]', [leave:'value'], [])
+            listNodeCollection.iterator().next().childDataNodes = [childDataNode]
+        when: 'the data nodes (list elements) are added to existing parent node'
             objectUnderTest.addListDataNodes(DATASPACE_NAME, ANCHOR_NAME3, '/parent-201', listNodeCollection)
         then: 'new entries successfully persisted, parent node now contains 5 children (2 new + 3 existing before)'
             def parentFragment = fragmentRepository.getById(LIST_DATA_NODE_PARENT201_FRAGMENT_ID)
             def allChildXpaths = parentFragment.getChildFragments().collect { it.getXpath() }
             assert allChildXpaths.size() == 5
             assert allChildXpaths.containsAll(listNodeXpaths)
+        and: 'the child node of the new list entry is also present'
+            def dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME)
+            def anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, ANCHOR_NAME3)
+            def listElementChild = fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, childDataNode.xpath)
+            assert listElementChild.isPresent()
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
index 9fcd550..162a566 100644 (file)
@@ -22,6 +22,7 @@ import org.hibernate.StaleStateException
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.entities.FragmentEntity
 import org.onap.cps.spi.exceptions.ConcurrencyException
+import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.model.DataNodeBuilder
 import org.onap.cps.spi.repository.AnchorRepository
 import org.onap.cps.spi.repository.DataspaceRepository
@@ -95,4 +96,17 @@ class CpsDataPersistenceServiceSpec extends Specification {
             'text and numbers'                    | '"String = \'1234\'"' || "String = '1234'" | String
             'number as String'                    | '"12345"'             || '12345'           | String
     }
+
+    def 'Retrieving a data node with invalid JSON'() {
+        given: 'a fragment with invalid JSON'
+            mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
+                new FragmentEntity(childFragments: Collections.emptySet(), attributes: '{invalid json')
+            }
+        when: 'getting the data node represented by this fragment'
+            def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor',
+                'parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+        then: 'a data validation exception is thrown'
+            thrown(DataValidationException)
+    }
+
 }