diff options
author | DylanB95EST <dylan.byrne@est.tech> | 2022-04-04 13:09:22 +0100 |
---|---|---|
committer | DylanB95EST <dylan.byrne@est.tech> | 2022-04-08 12:51:34 +0100 |
commit | b130fd3158c537df1ce2cb1e5a7a86c3d7e0d2a7 (patch) | |
tree | 84129ee13058d2ae9b7e79d1eaa82633ca1f95eb /cps-service/src | |
parent | deac4777c1a245be1dc4c423658523b41071b110 (diff) |
Refactoring/ Adding Tests for Validation
Refactored classes affected by validation
Have added tests for anywhere where validation is used
Have refactored the parse and sync modules validation
to be validated at the public api method
Issue-ID: CPS-322
Change-Id: I4989cfd03300fbdca41571d0aa2d0b96978858ba
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
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() |