diff options
Diffstat (limited to 'cps-service/src')
7 files changed, 405 insertions, 7 deletions
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java index 399457dd6d..99358984c7 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java @@ -105,10 +105,10 @@ public class CpsDataServiceImpl implements CpsDataService { final String parentNodeXpath, final String dataNodeUpdatesAsJson, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection<DataNode> dataNodeUpdates = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodeUpdatesAsJson); - CpsValidator.validateNameCharacters(dataspaceName, anchorName); for (final DataNode dataNodeUpdate : dataNodeUpdates) { processDataNodeUpdate(dataspaceName, anchorName, dataNodeUpdate); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java index 8e43227f97..db8a81f276 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java @@ -101,18 +101,18 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public Collection<ModuleReference> getYangResourcesModuleReferences(final String dataspaceName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName); + CpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName, anchorName); } - private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) { - return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed; - } - @Override public Collection<ModuleReference> identifyNewModuleReferences( final Collection<ModuleReference> moduleReferencesToCheck) { return cpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck); } + private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) { + return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed; + } + } diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy index cbe1ebbbdf..33868ccf06 100755 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy @@ -24,6 +24,7 @@ package org.onap.cps.api.impl import org.onap.cps.api.CpsDataService import org.onap.cps.spi.CpsAdminPersistenceService +import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.Anchor import org.onap.cps.spi.model.CmHandleQueryParameters import spock.lang.Specification @@ -41,6 +42,15 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsAdminPersistenceService.createDataspace('someDataspace') } + def 'Create a dataspace with an invalid dataspace name.'() { + when: 'create dataspace method is invoked with incorrectly named dataspace' + objectUnderTest.createDataspace('Dataspace Name with spaces') + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsAdminPersistenceService.createDataspace(_) + } + def 'Create anchor method invokes persistence service.'() { when: 'create anchor method is invoked' objectUnderTest.createAnchor('someDataspace', 'someSchemaSet', 'someAnchorName') @@ -48,6 +58,15 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsAdminPersistenceService.createAnchor('someDataspace', 'someSchemaSet', 'someAnchorName') } + def 'Create an anchor with an invalid anchor name.'() { + when: 'create anchor method is invoked with incorrectly named dataspace' + objectUnderTest.createAnchor('someDataspace', 'someSchemaSet', 'Anchor Name With Spaces') + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsAdminPersistenceService.createAnchor(_, _, _) + } + def 'Retrieve all anchors for dataspace.'() { given: 'that anchor is associated with the dataspace' def anchors = [new Anchor()] @@ -56,6 +75,15 @@ class CpsAdminServiceImplSpec extends Specification { objectUnderTest.getAnchors('someDataspace') == anchors } + def 'Retrieve all anchors with an invalid dataspace name.'() { + when: 'get anchors is invoked with an invalid dataspace name' + objectUnderTest.getAnchors('Dataspace name with spaces') + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'cps admin persistence get anchors is not invoked' + 0 * mockCpsAdminPersistenceService.getAnchors(_) + } + def 'Retrieve all anchors for schema-set.'() { given: 'that anchor is associated with the dataspace and schemaset' def anchors = [new Anchor()] @@ -63,6 +91,20 @@ class CpsAdminServiceImplSpec extends Specification { expect: 'the collection provided by persistence service is returned as result' objectUnderTest.getAnchors('someDataspace', 'someSchemaSet') == anchors } + def 'Retrieve all anchors for schema-set with invalid #scenario.'() { + when: 'the collection provided by persistence service is returned as result' + objectUnderTest.getAnchors(dataspaceName, schemaSetName) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'cps admin persistence get anchors is not invoked' + 0 * mockCpsAdminPersistenceService.getAnchors(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Retrieve anchor for dataspace and provided anchor name.'() { given: 'that anchor name is associated with the dataspace' @@ -72,6 +114,20 @@ class CpsAdminServiceImplSpec extends Specification { assert objectUnderTest.getAnchor('someDataspace','someAnchor') == anchor } + def 'Retrieve anchor with invalid #scenario.'() { + when: 'get anchors is invoked with an invalid dataspace name' + objectUnderTest.getAnchor(dataspaceName, anchorName) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'cps admin persistence get anchor is not invoked' + 0 * mockCpsAdminPersistenceService.getAnchor(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Delete anchor.'() { when: 'delete anchor is invoked' objectUnderTest.deleteAnchor('someDataspace','someAnchor') @@ -81,6 +137,22 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsAdminPersistenceService.deleteAnchor('someDataspace','someAnchor') } + def 'Delete anchor with invalid #scenario.'() { + when: 'delete anchor is invoked' + objectUnderTest.deleteAnchor(dataspaceName, anchorName) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'delete data nodes is invoked on the data service with expected parameters' + 0 * mockCpsDataService.deleteDataNodes(_,_, _ as OffsetDateTime ) + and: 'the persistence service method is invoked with same parameters to delete anchor' + 0 * mockCpsAdminPersistenceService.deleteAnchor(_,_) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Query all anchor identifiers for a dataspace and module names.'() { given: 'the persistence service is invoked with the expected parameters and returns a list of anchors' mockCpsAdminPersistenceService.queryAnchors('some-dataspace-name', ['some-module-name']) >> [new Anchor(name:'some-anchor-identifier')] @@ -89,6 +161,15 @@ class CpsAdminServiceImplSpec extends Specification { } + def 'Query all anchor identifiers for a dataspace and module names with an invalid dataspace name.'() { + when: 'delete anchor is invoked' + objectUnderTest.queryAnchorNames('some dataspace name', _ as Collection<String>) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'delete data nodes is not invoked' + 0 * mockCpsAdminPersistenceService.queryAnchors(_, _) + } + def 'Delete dataspace.'() { when: 'delete dataspace is invoked' objectUnderTest.deleteDataspace('someDataspace') @@ -105,4 +186,13 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsAdminPersistenceService.queryCmHandles(cmHandleQueryParameters) } + def 'Delete dataspace with invalid dataspace id.'() { + when: 'delete dataspace is invoked' + objectUnderTest.deleteDataspace('some dataspace name') + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'associated persistence service method is not invoked' + 0 * mockCpsAdminPersistenceService.deleteDataspace(_) + } + } diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy index fc1293cb76..faeba8d51a 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy @@ -30,6 +30,7 @@ import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.model.Anchor +import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder import org.onap.cps.yang.YangTextSchemaSourceSet import org.onap.cps.yang.YangTextSchemaSourceSetBuilder @@ -69,6 +70,22 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockNotificationService.processDataUpdatedEvent(anchor, observedTimestamp, '/', Operation.CREATE) } + def 'Saving json data with invalid #scenario.'() { + when: 'save data method is invoked with invalid #scenario' + objectUnderTest.saveData(dataspaceName, anchorName, _ as String, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.storeDataNode(_, _, _) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Saving child data fragment under existing node.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -82,6 +99,22 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockNotificationService.processDataUpdatedEvent(anchor, observedTimestamp, '/test-tree', Operation.CREATE) } + def 'Saving child data fragment under existing node with invalid #scenario.'() { + when: 'save data method is invoked with test-tree and an invalid #scenario' + objectUnderTest.saveData(dataspaceName, anchorName, '/test-tree', _ as String, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.addChildDataNode(_, _, _,_) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Saving list element data fragment under existing node.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -112,6 +145,20 @@ class CpsDataServiceImplSpec extends Specification { thrown(DataValidationException) } + def 'Saving list element data fragment with invalid #scenario.'() { + when: 'save data method is invoked with an invalid #scenario' + objectUnderTest.saveListElements(dataspaceName, anchorName, '/test-tree', _ as String, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'add list elements persistence method is not invoked' + 0 * mockCpsDataPersistenceService.addListElements(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Get data node with option #fetchDescendantsOption.'() { def xpath = '/xpath' def dataNode = new DataNodeBuilder().withXpath(xpath).build() @@ -123,6 +170,20 @@ class CpsDataServiceImplSpec extends Specification { fetchDescendantsOption << FetchDescendantsOption.values() } + def 'Get data node with option invalid #scenario.'() { + when: 'get data node is invoked with #scenario' + objectUnderTest.getDataNode(dataspaceName, anchorName, '/test-tree', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'get data node persistence service is not invoked' + 0 * mockCpsDataPersistenceService.getDataNode(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Update data node leaves: #scenario.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -138,6 +199,22 @@ class CpsDataServiceImplSpec extends Specification { 'level 2 node' | '/test-tree' | '{"branch": [{"name":"Name"}]}' || '/test-tree/branch[@name=\'Name\']' | ['name': 'Name'] } + def 'Update data node with invalid #scenario.'() { + when: 'update data method is invoked with json data #jsonData and parent node xpath #parentNodeXpath' + objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, '/', '{"test-tree": {"branch": []}}', observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.updateDataLeaves(_, _, _, _) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Update list-element data node with : #scenario.'() { given: 'schema set for given anchor and dataspace references bookstore model' setupSchemaSetMocks('bookstore.yang') @@ -167,6 +244,24 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockNotificationService.processDataUpdatedEvent(anchor, observedTimestamp, '/bookstore', Operation.UPDATE) } + def 'Update Bookstore node leaves with invalid #scenario' () { + when: 'update data method is invoked with an invalid #scenario' + objectUnderTest.updateNodeLeavesAndExistingDescendantLeaves(dataspaceName, anchorName, + '/bookstore', _ as String, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.updateDataLeaves(_, _, _, _) + and: 'the data updated event is not sent to the notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + + def 'Replace data node: #scenario.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -183,6 +278,22 @@ class CpsDataServiceImplSpec extends Specification { 'level 2 node' | '/test-tree' | '{"branch": [{"name":"Name"}]}' || '/test-tree/branch[@name=\'Name\']' } + def 'Replace data node with invalid #scenario.'() { + when: 'replace data method is invoked with invalid #scenario' + objectUnderTest.replaceNodeTree(dataspaceName, anchorName, '/', _ as String, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.replaceDataNodeTree(_, _,_) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Replace list content data fragment under parent node.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -213,6 +324,22 @@ class CpsDataServiceImplSpec extends Specification { thrown(DataValidationException) } + def 'Replace whole list content with an invalid #scenario.'() { + when: 'replace list data method is invoked with invalid #scenario' + objectUnderTest.replaceListContent(dataspaceName, anchorName, '/test-tree', _ as Collection<DataNode>, observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.replaceListContent(_, _,_) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Delete list element under existing node.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -224,6 +351,23 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockNotificationService.processDataUpdatedEvent(anchor, observedTimestamp, '/test-tree/branch', Operation.DELETE) } + + def 'Delete list element with an invalid #scenario.'() { + when: 'delete list data method is invoked with with invalid #scenario' + objectUnderTest.deleteDataNode(dataspaceName, anchorName, '/data-node', observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.deleteListDataNode(_, _, _) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Delete data node under anchor and dataspace.'() { given: 'schema set for given anchor and dataspace references test tree model' setupSchemaSetMocks('test-tree.yang') @@ -235,6 +379,22 @@ class CpsDataServiceImplSpec extends Specification { 1 * mockNotificationService.processDataUpdatedEvent(anchor, observedTimestamp, '/data-node', Operation.DELETE) } + def 'Delete data node with an invalid #scenario.'() { + when: 'delete data node method is invoked with invalid #scenario' + objectUnderTest.deleteDataNode(dataspaceName, anchorName, '/data-node', observedTimestamp) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsDataPersistenceService.deleteDataNode(_, _, _) + and: 'data updated event is not sent to notification service' + 0 * mockNotificationService.processDataUpdatedEvent(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Delete all data nodes for a given anchor and dataspace.'() { given: 'schema set for given anchor and dataspace references test tree model' setupSchemaSetMocks('test-tree.yang') diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy index bae06bb9ec..95d731478f 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy @@ -24,7 +24,9 @@ package org.onap.cps.api.impl import org.onap.cps.TestUtils import org.onap.cps.api.CpsAdminService +import org.onap.cps.spi.CascadeDeleteAllowed import org.onap.cps.spi.CpsModulePersistenceService +import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.exceptions.ModelValidationException import org.onap.cps.spi.exceptions.SchemaSetInUseException import org.onap.cps.spi.model.Anchor @@ -51,6 +53,20 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockCpsModulePersistenceService.storeSchemaSet('someDataspace', 'someSchemaSet', yangResourcesNameToContentMap) } + def 'Create a schema set with an invalid #scenario.'() { + when: 'create dataspace method is invoked with incorrectly named dataspace' + objectUnderTest.createSchemaSet(dataspaceName, schemaSetName, _ as Map<String, String>) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsModulePersistenceService.storeSchemaSet(_, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Create schema set from new modules and existing modules.'() { given: 'a list of existing modules module reference' def moduleReferenceForExistingModule = new ModuleReference("test", "2021-10-12","test.org") @@ -61,6 +77,20 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockCpsModulePersistenceService.storeSchemaSetFromModules("someDataspaceName", "someSchemaSetName", [newModule: "newContent"], listOfExistingModulesModuleReference) } + def 'Create schema set from new modules and existing modules with invalid #scenario.'() { + when: 'create dataspace method is invoked with incorrectly named dataspace' + objectUnderTest.createSchemaSetFromModules(dataspaceName, schemaSetName, _ as Map<String, String>, _ as Collection<ModuleReference>) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsModulePersistenceService.storeSchemaSetFromModules(_, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Create schema set from invalid resources'() { given: 'Invalid yang resource as name-to-content map' def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('invalid.yang') @@ -83,6 +113,20 @@ class CpsModuleServiceImplSpec extends Specification { result.getModuleReferences().contains(new ModuleReference('stores', '2020-09-15', 'org:onap:ccsdk:sample')) } + def 'Get a schema set with an invalid #scenario'() { + when: 'create dataspace method is invoked with incorrectly named dataspace' + objectUnderTest.getSchemaSet(dataspaceName, schemaSetName) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the yang resource cache is not invoked' + 0 * mockYangTextSchemaSourceSetCache.get(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Delete schema-set when cascade is allowed.'() { given: '#numberOfAnchors anchors are associated with schemaset' def associatedAnchors = createAnchors(numberOfAnchors) @@ -125,6 +169,26 @@ class CpsModuleServiceImplSpec extends Specification { thrown(SchemaSetInUseException) } + def 'Delete a schema set with an invalid #scenario.'() { + when: 'create dataspace method is invoked with incorrectly named dataspace' + objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_ALLOWED) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'anchor deletion is called 0 times' + 0 * mockCpsAdminService.deleteAnchor(_, _) + and: 'the delete schema set persistence service method is not invoked' + 0 * mockCpsModulePersistenceService.deleteSchemaSet(_, _, _) + and: 'schema set will be removed from the cache is not invoked' + 0 * mockYangTextSchemaSourceSetCache.removeFromCache(_, _) + and: 'orphan yang resources are deleted is not invoked' + 0 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules() + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def createAnchors(int anchorCount) { def anchors = [] (0..<anchorCount).each { anchors.add(new Anchor("my-anchor-$it", 'my-dataspace', 'my-schemaset')) } @@ -139,6 +203,15 @@ class CpsModuleServiceImplSpec extends Specification { objectUnderTest.getYangResourceModuleReferences('someDataspaceName') == moduleReferences } + def 'Get all yang resources module references given an invalid dataspace name.'() { + when: 'the get yang resources module references method is invoked with an invalid dataspace name' + objectUnderTest.getYangResourceModuleReferences('dataspace name with spaces') + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsModulePersistenceService.getYangResourceModuleReferences(_) + } + def 'Get all yang resources module references for the given dataspace name and anchor name.'() { given: 'the module store service service returns a list module references' @@ -148,6 +221,20 @@ class CpsModuleServiceImplSpec extends Specification { objectUnderTest.getYangResourcesModuleReferences('someDataspaceName', 'someAnchorName') == moduleReferences } + def 'Get all yang resources module references given an invalid #scenario.'() { + when: 'the get yang resources module references method is invoked with invalid #scenario' + objectUnderTest.getYangResourcesModuleReferences(dataspaceName, anchorName) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service method is not invoked' + 0 * mockCpsModulePersistenceService.getYangResourceModuleReferences(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + def 'Identifying new module references'(){ given: 'module references from cm handle' def moduleReferencesToCheck = [new ModuleReference('some-module', 'some-revision')] diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy index aa01b44019..55a252c27d 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy @@ -22,6 +22,7 @@ package org.onap.cps.api.impl import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.exceptions.DataValidationException import spock.lang.Specification class CpsQueryServiceImplSpec extends Specification { @@ -45,4 +46,19 @@ class CpsQueryServiceImplSpec extends Specification { where: 'all fetch descendants options are supported' fetchDescendantsOption << FetchDescendantsOption.values() } + + def 'Query data nodes by cps path with invalid #scenario.'() { + when: 'queryDataNodes is invoked' + objectUnderTest.queryDataNodes(dataspaceName, anchorName, '/cps-path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + then: 'a data validation exception is thrown' + thrown(DataValidationException) + and: 'the persistence service is not invoked' + 0 * mockCpsDataPersistenceService.queryDataNodes(_, _, _, _) + where: 'the following parameters are used' + scenario | dataspaceName | anchorName + 'dataspace name' | 'dataspace names with spaces' | 'anchorName' + 'anchor name' | 'dataspaceName' | 'anchor name with spaces' + 'dataspace and anchor name' | 'dataspace name with spaces' | 'anchor name with spaces' + } + } diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy index 860b7399d2..06c675a255 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada + * Modifications 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. @@ -22,6 +23,7 @@ package org.onap.cps.api.impl import org.onap.cps.TestUtils import org.onap.cps.spi.CpsModulePersistenceService +import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.yang.YangTextSchemaSourceSet import org.onap.cps.yang.YangTextSchemaSourceSetBuilder import org.spockframework.spring.SpringBean @@ -88,6 +90,20 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { 0 * mockModuleStoreService.getYangSchemaResources(_, _) } + def 'Cache Hit: with invalid #scenario'() { + when: 'schema-set information is asked' + objectUnderTest.get(dataspaceName, schemaSetName) + then: 'an data validation exception is thrown' + thrown(DataValidationException) + and: 'module persistence is not invoked' + 0 * mockModuleStoreService.getYangSchemaResources(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Cache Update: when no data exist in the cache'() { given: 'a schema set exists' def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang') @@ -99,7 +115,24 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { cachedValue.getModuleReferences() == yangTextSchemaSourceSet.getModuleReferences() } - def 'Cache Evict: remove when exist'() { + def 'Cache Update: with invalid #scenario'() { + given: 'a schema set exists' + def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang') + def yangTextSchemaSourceSet = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap) + when: 'schema-set information is asked' + objectUnderTest.updateCache(dataspaceName, schemaSetName, yangTextSchemaSourceSet) + then: 'an data validation exception is thrown' + thrown(DataValidationException) + and: 'module persistence is not invoked' + 0 * mockModuleStoreService.getYangSchemaResources(_, _) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + + def 'Cache Evict:with invalid #scenario'() { given: 'a schema set exists in cache' def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang') def yangTextSchemaSourceSet = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap) @@ -112,6 +145,18 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { assert getCachedValue('my-dataspace', 'my-schemaset') == null } + def 'Cache Evict: remove when exist'() { + when: 'cache is evicted for schemaset' + objectUnderTest.removeFromCache(dataspaceName, schemaSetName) + then: 'an data validation exception is thrown' + thrown(DataValidationException) + where: 'the following parameters are used' + scenario | dataspaceName | schemaSetName + 'dataspace name' | 'dataspace names with spaces' | 'schemaSetName' + 'schema set name' | 'dataspaceName' | 'schema set name with spaces' + 'dataspace and schema set name' | 'dataspace name with spaces' | 'schema set name with spaces' + } + def 'Cache Evict: remove when does not exist'() { given: 'cache is empty' yangResourceCacheImpl.clear() |