diff options
Diffstat (limited to 'cps-ri/src/test')
4 files changed, 117 insertions, 76 deletions
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy index 2de087fc28..e037350038 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy @@ -31,7 +31,6 @@ import org.onap.cps.spi.exceptions.DataspaceNotFoundException import org.onap.cps.spi.exceptions.SchemaSetNotFoundException import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException import org.onap.cps.spi.model.Anchor -import org.onap.cps.spi.model.CmHandleQueryParameters import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper @@ -45,7 +44,6 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { ObjectMapper objectMapper static final String SET_DATA = '/data/anchor.sql' - static final String SET_FRAGMENT_DATA = '/data/fragment.sql' static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql' static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA' static final Integer DELETED_ANCHOR_ID = 3002 @@ -176,28 +174,17 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES]) def 'Query anchors that have #scenario.'() { when: 'all anchor are retrieved for the given dataspace name and module names' - def anchors = objectUnderTest.queryAnchors('dataspace-1', inputModuleNames) + def anchors = objectUnderTest.queryAnchors(inputDataspaceName, inputModuleNames) then: 'the expected anchors are returned' anchors.size() == expectedAnchors.size() anchors.containsAll(expectedAnchors) where: 'the following data is used' - scenario | inputModuleNames || expectedAnchors - 'one module' | ['module-name-1'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')] - 'two modules' | ['module-name-1', 'module-name-2'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')] - 'no anchors for all three modules' | ['module-name-1', 'module-name-2', 'module-name-3'] || [] - } - - @Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES]) - def 'Query all anchors for an #scenario.'() { - when: 'attempt to query anchors' - objectUnderTest.queryAnchors(dataspaceName, moduleNames) - then: 'the correct exception is thrown with the relevant details' - def thrownException = thrown(expectedException) - thrownException.details.contains(expectedMessageDetails) - where: 'the following data is used' - scenario | dataspaceName | moduleNames || expectedException | expectedMessageDetails | messageDoesNotContain - 'unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || DataspaceNotFoundException | 'db-does-not-exist' | 'does-not-matter' - 'unknown module and known module' | 'dataspace-1' | ['module-name-1', 'module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist' | 'module-name-1' + scenario | inputDataspaceName | inputModuleNames || expectedAnchors + 'one module' | 'dataspace-1' | ['module-name-1'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')] + 'two modules' | 'dataspace-1' | ['module-name-1', 'module-name-2'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')] + 'no anchors for all three modules' | 'dataspace-1' | ['module-name-1', 'module-name-2', 'module-name-3'] || [] + 'unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || [] + 'unknown module and known module' | 'dataspace-1' | ['module-name-1', 'module-does-not-exist'] || [] } def buildAnchor(def anchorName, def dataspaceName, def SchemaSetName) { @@ -225,21 +212,4 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase { 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 2 anchor(s)' 'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)' } - - @Sql([CLEAR_DATA, SET_FRAGMENT_DATA]) - def 'Retrieve cm handle ids when #scenario.'() { - when: 'the service is invoked' - def cmHandleQueryParameters = new CmHandleQueryParameters() - cmHandleQueryParameters.setPublicProperties(publicProperties) - def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) - then: 'the correct expected cm handles are returned' - returnedCmHandles == expectedCmHandleIds - where: 'the following data is used' - scenario | publicProperties || expectedCmHandleIds - 'single matching property' | ['Contact' : 'newemailforstore@bookstore.com'] || ['PNFDemo2', 'PNFDemo', 'PNFDemo4'] as Set - 'public property dont match' | ['wont_match' : 'wont_match'] || [] as Set - '2 properties, only one match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': 'newemailforstore2@bookstore.com'] || ['PNFDemo4'] as Set - '2 properties, no match (and)' | ['Contact' : 'newemailforstore@bookstore.com', 'Contact2': ''] || [] as Set - 'No public properties - return all cm handles' | [ : ] || ['PNFDemo3', 'PNFDemo', 'PNFDemo2', 'PNFDemo4'] as Set - } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index a96b6aff9b..bb80199d09 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -22,7 +22,11 @@ package org.onap.cps.spi.impl import com.fasterxml.jackson.databind.ObjectMapper import org.hibernate.StaleStateException import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.entities.AnchorEntity +import org.onap.cps.spi.entities.DataspaceEntity import org.onap.cps.spi.entities.FragmentEntity +import org.onap.cps.spi.entities.SchemaSetEntity +import org.onap.cps.spi.entities.YangResourceEntity import org.onap.cps.spi.exceptions.ConcurrencyException import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.DataNodeBuilder @@ -31,6 +35,10 @@ import org.onap.cps.spi.repository.DataspaceRepository import org.onap.cps.spi.repository.FragmentRepository import org.onap.cps.spi.utils.SessionManager import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.yang.YangTextSchemaSourceSet +import org.onap.cps.yang.YangTextSchemaSourceSetBuilder +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import spock.lang.Shared import spock.lang.Specification class CpsDataPersistenceServiceSpec extends Specification { @@ -44,6 +52,25 @@ class CpsDataPersistenceServiceSpec extends Specification { def objectUnderTest = new CpsDataPersistenceServiceImpl( mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper,mockSessionManager) + @Shared + def NEW_RESOURCE_CONTENT = 'module stores {\n' + + ' yang-version 1.1;\n' + + ' namespace "org:onap:ccsdk:sample";\n' + + '\n' + + ' prefix book-store;\n' + + '\n' + + ' revision "2020-09-15" {\n' + + ' description\n' + + ' "Sample Model";\n' + + ' }' + + '}' + + @Shared + def yangResourceSet = [new YangResourceEntity(moduleName: 'moduleName', content: NEW_RESOURCE_CONTENT, + name: 'sampleYangResource' + )] as Set + + def 'Handling of StaleStateException (caused by concurrent updates) during data node tree update.'() { def parentXpath = '/parent-01' @@ -51,67 +78,68 @@ class CpsDataPersistenceServiceSpec extends Specification { def myAnchorName = 'my-anchor' given: 'data node object' - def submittedDataNode = new DataNodeBuilder() - .withXpath(parentXpath) - .withLeaves(['leaf-name': 'leaf-value']) - .build() + def submittedDataNode = new DataNodeBuilder() + .withXpath(parentXpath) + .withLeaves(['leaf-name': 'leaf-value']) + .build() and: 'fragment to be updated' - mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> { - def fragmentEntity = new FragmentEntity() - fragmentEntity.setXpath(parentXpath) - fragmentEntity.setChildFragments(Collections.emptySet()) - return fragmentEntity - } + mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> { + def fragmentEntity = new FragmentEntity() + fragmentEntity.setXpath(parentXpath) + fragmentEntity.setChildFragments(Collections.emptySet()) + return fragmentEntity + } and: 'data node is concurrently updated by another transaction' - mockFragmentRepository.save(_) >> { throw new StaleStateException("concurrent updates") } + mockFragmentRepository.save(_) >> { throw new StaleStateException("concurrent updates") } when: 'attempt to update data node' - objectUnderTest.replaceDataNodeTree(myDataspaceName, myAnchorName, submittedDataNode) + objectUnderTest.replaceDataNodeTree(myDataspaceName, myAnchorName, submittedDataNode) then: 'concurrency exception is thrown' - def concurrencyException = thrown(ConcurrencyException) - assert concurrencyException.getDetails().contains(myDataspaceName) - assert concurrencyException.getDetails().contains(myAnchorName) - assert concurrencyException.getDetails().contains(parentXpath) + def concurrencyException = thrown(ConcurrencyException) + assert concurrencyException.getDetails().contains(myDataspaceName) + assert concurrencyException.getDetails().contains(myAnchorName) + assert concurrencyException.getDetails().contains(parentXpath) } def 'Retrieving a data node with a property JSON value of #scenario'() { given: 'a fragment with a property JSON value of #scenario' mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> { new FragmentEntity(childFragments: Collections.emptySet(), - attributes: "{\"some attribute\": ${dataString}}") + attributes: "{\"some attribute\": ${dataString}}", + anchor: new AnchorEntity(schemaSet: new SchemaSetEntity(yangResources: yangResourceSet ))) } when: 'getting the data node represented by this fragment' - def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor', - '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor', + '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) then: 'the leaf is of the correct value and data type' - def attributeValue = dataNode.leaves.get('some attribute') - assert attributeValue == expectedValue - assert attributeValue.class == expectedDataClass + def attributeValue = dataNode.leaves.get('some attribute') + assert attributeValue == expectedValue + assert attributeValue.class == expectedDataClass where: 'the following Data Type is passed' - scenario | dataString || expectedValue | expectedDataClass - 'just numbers' | '15174' || 15174 | Integer - 'number with dot' | '15174.32' || 15174.32 | Double - 'number with 0 value after dot' | '15174.0' || 15174.0 | Double - 'number with 0 value before dot' | '0.32' || 0.32 | Double - 'number higher than max int' | '2147483648' || 2147483648 | Long - 'just text' | '"Test"' || 'Test' | String - 'number with exponent' | '1.2345e5' || 1.2345e5 | Double - 'number higher than max int with dot' | '123456789101112.0' || 123456789101112.0 | Double - 'text and numbers' | '"String = \'1234\'"' || "String = '1234'" | String - 'number as String' | '"12345"' || '12345' | String + scenario | dataString || expectedValue | expectedDataClass + 'just numbers' | '15174' || 15174 | Integer + 'number with dot' | '15174.32' || 15174.32 | Double + 'number with 0 value after dot' | '15174.0' || 15174.0 | Double + 'number with 0 value before dot' | '0.32' || 0.32 | Double + 'number higher than max int' | '2147483648' || 2147483648 | Long + 'just text' | '"Test"' || 'Test' | String + 'number with exponent' | '1.2345e5' || 1.2345e5 | Double + 'number higher than max int with dot' | '123456789101112.0' || 123456789101112.0 | Double + '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') - } + 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) + def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor', + '/parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) then: 'a data validation exception is thrown' - thrown(DataValidationException) + thrown(DataValidationException) } def 'start session'() { diff --git a/cps-ri/src/test/resources/data/cps-path-query.sql b/cps-ri/src/test/resources/data/cps-path-query.sql index d1a62209eb..c406203c8c 100644 --- a/cps-ri/src/test/resources/data/cps-path-query.sql +++ b/cps-ri/src/test/resources/data/cps-path-query.sql @@ -25,6 +25,28 @@ INSERT INTO DATASPACE (ID, NAME) VALUES INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES (2001, 'SCHEMA-SET-001', 1001); +INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES + (4001, 'TEST','', 'SAMPLECHECKSUM','TESTMODULENAME', 'SAMPLEREVISION'); + +UPDATE YANG_RESOURCE SET +content = 'module stores { + yang-version 1.1; + namespace "org:onap:ccsdk:sample"; + + prefix book-store; + + revision "2020-09-15" { + description + "Sample Model"; + } + } +' +where ID = 4001; + + +INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES + (2001, 4001); + INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (1003, 'ANCHOR-004', 1001, 2001); diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql index 4106541061..fd05900e28 100755 --- a/cps-ri/src/test/resources/data/fragment.sql +++ b/cps-ri/src/test/resources/data/fragment.sql @@ -27,6 +27,27 @@ INSERT INTO DATASPACE (ID, NAME) VALUES INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES (2001, 'SCHEMA-SET-001', 1001); +INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES + (4001, 'TEST','', 'SAMPLECHECKSUM','TESTMODULENAME', 'SAMPLEREVISION'); + +UPDATE YANG_RESOURCE SET +content = 'module stores { + yang-version 1.1; + namespace "org:onap:ccsdk:sample"; + + prefix book-store; + + revision "2020-09-15" { + description + "Sample Model"; + } + } +' +where ID = 4001; + +INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES + (2001, 4001); + INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES (3001, 'ANCHOR-001', 1001, 2001), (3003, 'ANCHOR-003', 1001, 2001), |