From e5254a7b007e4a0dc59003d94f43e688c25cf7d1 Mon Sep 17 00:00:00 2001 From: lukegleeson Date: Fri, 26 Aug 2022 10:55:04 +0100 Subject: CPS Validator Changes Changed CPS Validator from static to non-static Moved CPSValidator implementation to rest interface layer to prevent duplicated usage Created CPSValidator interface in persistence layer Removed unnecessary tests Refactored misplaced tests Copyright fixes Copyright Check Script output formatting fix Issue-ID: CPS-1228 Signed-off-by: lukegleeson Change-Id: I4c99a51870e7d3b8e416bc1f909aeed5dc3baa42 --- .../org/onap/cps/api/impl/CpsAdminServiceImpl.java | 19 +- .../org/onap/cps/api/impl/CpsDataServiceImpl.java | 35 ++-- .../onap/cps/api/impl/CpsModuleServiceImpl.java | 21 ++- .../org/onap/cps/api/impl/CpsQueryServiceImpl.java | 15 +- .../cps/api/impl/YangTextSchemaSourceSetCache.java | 18 +- .../java/org/onap/cps/spi/utils/CpsValidator.java | 31 ++++ .../main/java/org/onap/cps/utils/CpsValidator.java | 56 ------ .../cps/api/impl/CpsAdminServiceImplSpec.groovy | 137 ++++---------- .../cps/api/impl/CpsDataServiceImplSpec.groovy | 201 +++------------------ .../cps/api/impl/CpsModuleServiceImplSpec.groovy | 121 +++---------- .../cps/api/impl/CpsQueryServiceImplSpec.groovy | 27 +-- .../onap/cps/api/impl/E2ENetworkSliceSpec.groovy | 10 +- .../impl/YangTextSchemaSourceSetCacheSpec.groovy | 59 ++---- .../org/onap/cps/utils/CpsValidatorSpec.groovy | 48 ----- 14 files changed, 203 insertions(+), 595 deletions(-) create mode 100644 cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java delete mode 100644 cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java delete mode 100644 cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy (limited to 'cps-service') diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java index a67dfe503..56f424164 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java @@ -30,7 +30,7 @@ import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsDataService; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.model.Anchor; -import org.onap.cps.utils.CpsValidator; +import org.onap.cps.spi.utils.CpsValidator; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -41,53 +41,54 @@ public class CpsAdminServiceImpl implements CpsAdminService { private final CpsAdminPersistenceService cpsAdminPersistenceService; @Lazy private final CpsDataService cpsDataService; + private final CpsValidator cpsValidator; @Override public void createDataspace(final String dataspaceName) { - CpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(dataspaceName); cpsAdminPersistenceService.createDataspace(dataspaceName); } @Override public void deleteDataspace(final String dataspaceName) { - CpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(dataspaceName); cpsAdminPersistenceService.deleteDataspace(dataspaceName); } @Override public void createAnchor(final String dataspaceName, final String schemaSetName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName, anchorName); cpsAdminPersistenceService.createAnchor(dataspaceName, schemaSetName, anchorName); } @Override public Collection getAnchors(final String dataspaceName) { - CpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(dataspaceName); return cpsAdminPersistenceService.getAnchors(dataspaceName); } @Override public Collection getAnchors(final String dataspaceName, final String schemaSetName) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetName); } @Override public Anchor getAnchor(final String dataspaceName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName); } @Override public void deleteAnchor(final String dataspaceName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataService.deleteDataNodes(dataspaceName, anchorName, OffsetDateTime.now()); cpsAdminPersistenceService.deleteAnchor(dataspaceName, anchorName); } @Override public Collection queryAnchorNames(final String dataspaceName, final Collection moduleNames) { - CpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(dataspaceName); final Collection anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames); return anchors.stream().map(Anchor::getName).collect(Collectors.toList()); } 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 b6aa04be7..88ebe3bd0 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 @@ -31,7 +31,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsDataService; @@ -43,7 +43,7 @@ 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.utils.CpsValidator; +import org.onap.cps.spi.utils.CpsValidator; import org.onap.cps.utils.YangUtils; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -51,7 +51,7 @@ import org.springframework.stereotype.Service; @Service @Slf4j -@AllArgsConstructor +@RequiredArgsConstructor public class CpsDataServiceImpl implements CpsDataService { private static final String ROOT_NODE_XPATH = "/"; @@ -61,11 +61,12 @@ public class CpsDataServiceImpl implements CpsDataService { private final CpsAdminService cpsAdminService; private final YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache; private final NotificationService notificationService; + private final CpsValidator cpsValidator; @Override public void saveData(final String dataspaceName, final String anchorName, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final DataNode dataNode = buildDataNode(dataspaceName, anchorName, ROOT_NODE_XPATH, jsonData); cpsDataPersistenceService.storeDataNode(dataspaceName, anchorName, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, ROOT_NODE_XPATH, CREATE, observedTimestamp); @@ -74,7 +75,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveData(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final DataNode dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.addChildDataNode(dataspaceName, anchorName, parentNodeXpath, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, parentNodeXpath, CREATE, observedTimestamp); @@ -83,7 +84,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection listElementDataNodeCollection = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath, @@ -94,7 +95,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveListElementsBatch(final String dataspaceName, final String anchorName, final String parentNodeXpath, final Collection jsonDataList, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection> listElementDataNodeCollections = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonDataList); cpsDataPersistenceService.addMultipleLists(dataspaceName, anchorName, parentNodeXpath, @@ -105,14 +106,14 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public DataNode getDataNode(final String dataspaceName, final String anchorName, final String xpath, final FetchDescendantsOption fetchDescendantsOption) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsDataPersistenceService.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption); } @Override public void updateNodeLeaves(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final DataNode dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService .updateDataLeaves(dataspaceName, anchorName, dataNode.getXpath(), dataNode.getLeaves()); @@ -124,7 +125,7 @@ public class CpsDataServiceImpl implements CpsDataService { final String parentNodeXpath, final String dataNodeUpdatesAsJson, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection dataNodeUpdates = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodeUpdatesAsJson); @@ -159,7 +160,7 @@ public class CpsDataServiceImpl implements CpsDataService { public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final DataNode dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.updateDataNodeAndDescendants(dataspaceName, anchorName, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, parentNodeXpath, UPDATE, observedTimestamp); @@ -169,7 +170,7 @@ public class CpsDataServiceImpl implements CpsDataService { public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName, final Map nodesJsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final List dataNodes = buildDataNodes(dataspaceName, anchorName, nodesJsonData); cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes); nodesJsonData.keySet().forEach(nodeXpath -> @@ -180,7 +181,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection newListElements = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData); replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements, observedTimestamp); @@ -189,7 +190,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath, final Collection dataNodes, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, dataNodes); processDataUpdatedEventAsync(dataspaceName, anchorName, parentNodeXpath, UPDATE, observedTimestamp); } @@ -197,7 +198,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteDataNode(final String dataspaceName, final String anchorName, final String dataNodeXpath, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath); processDataUpdatedEventAsync(dataspaceName, anchorName, dataNodeXpath, DELETE, observedTimestamp); } @@ -205,7 +206,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteDataNodes(final String dataspaceName, final String anchorName, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); processDataUpdatedEventAsync(dataspaceName, anchorName, ROOT_NODE_XPATH, DELETE, observedTimestamp); cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName); } @@ -213,7 +214,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteListOrListElement(final String dataspaceName, final String anchorName, final String listNodeXpath, final OffsetDateTime observedTimestamp) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, listNodeXpath); processDataUpdatedEventAsync(dataspaceName, anchorName, listNodeXpath, DELETE, observedTimestamp); } 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 20b4a23a9..b4890f4a7 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 @@ -24,7 +24,7 @@ package org.onap.cps.api.impl; import java.util.Collection; import java.util.Map; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.spi.CascadeDeleteAllowed; @@ -34,23 +34,24 @@ import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.spi.model.SchemaSet; -import org.onap.cps.utils.CpsValidator; +import org.onap.cps.spi.utils.CpsValidator; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service("CpsModuleServiceImpl") -@AllArgsConstructor +@RequiredArgsConstructor public class CpsModuleServiceImpl implements CpsModuleService { private final CpsModulePersistenceService cpsModulePersistenceService; private final YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache; private final CpsAdminService cpsAdminService; + private final CpsValidator cpsValidator; @Override public void createSchemaSet(final String dataspaceName, final String schemaSetName, final Map yangResourcesNameToContentMap) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final var yangTextSchemaSourceSet = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap); cpsModulePersistenceService.storeSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap); @@ -61,7 +62,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName, final Map newModuleNameToContentMap, final Collection allModuleReferences) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); cpsModulePersistenceService.storeSchemaSetFromModules(dataspaceName, schemaSetName, newModuleNameToContentMap, allModuleReferences); @@ -69,7 +70,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public SchemaSet getSchemaSet(final String dataspaceName, final String schemaSetName) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final var yangTextSchemaSourceSet = yangTextSchemaSourceSetCache .get(dataspaceName, schemaSetName); return SchemaSet.builder().name(schemaSetName).dataspaceName(dataspaceName) @@ -80,7 +81,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Transactional public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, final CascadeDeleteAllowed cascadeDeleteAllowed) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final Collection anchors = cpsAdminService.getAnchors(dataspaceName, schemaSetName); if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) { throw new SchemaSetInUseException(dataspaceName, schemaSetName); @@ -95,21 +96,21 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public Collection getYangResourceModuleReferences(final String dataspaceName) { - CpsValidator.validateNameCharacters(dataspaceName); + cpsValidator.validateNameCharacters(dataspaceName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName); } @Override public Collection getYangResourcesModuleReferences(final String dataspaceName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName, anchorName); } @Override public Collection getModuleDefinitionsByAnchorName(final String dataspaceName, final String anchorName) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsModulePersistenceService.getYangResourceDefinitions(dataspaceName, anchorName); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java index c2003d6bf..7b9043a60 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java @@ -1,6 +1,6 @@ /* - * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation + * ============LICENSE_START======================================================= + * Copyright (C) 2021-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. @@ -21,24 +21,25 @@ package org.onap.cps.api.impl; import java.util.Collection; +import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsQueryService; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; -import org.onap.cps.utils.CpsValidator; -import org.springframework.beans.factory.annotation.Autowired; +import org.onap.cps.spi.utils.CpsValidator; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class CpsQueryServiceImpl implements CpsQueryService { - @Autowired - private CpsDataPersistenceService cpsDataPersistenceService; + private final CpsDataPersistenceService cpsDataPersistenceService; + private final CpsValidator cpsValidator; @Override public Collection queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { - CpsValidator.validateNameCharacters(dataspaceName, anchorName); + cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); } } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java index fb881a97b..0f620b0dd 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java @@ -1,7 +1,8 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech * Modifications 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. @@ -23,11 +24,11 @@ package org.onap.cps.api.impl; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Map; +import lombok.RequiredArgsConstructor; import org.onap.cps.spi.CpsModulePersistenceService; -import org.onap.cps.utils.CpsValidator; +import org.onap.cps.spi.utils.CpsValidator; import org.onap.cps.yang.YangTextSchemaSourceSet; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; @@ -39,10 +40,11 @@ import org.springframework.stereotype.Service; */ @Service @CacheConfig(cacheNames = {"yangSchema"}) +@RequiredArgsConstructor public class YangTextSchemaSourceSetCache { - @Autowired - private CpsModulePersistenceService cpsModulePersistenceService; + private final CpsModulePersistenceService cpsModulePersistenceService; + private final CpsValidator cpsValidator; /** * Cache YangTextSchemaSourceSet. @@ -53,7 +55,7 @@ public class YangTextSchemaSourceSetCache { */ @Cacheable(key = "#p0.concat('-').concat(#p1)") public YangTextSchemaSourceSet get(final String dataspaceName, final String schemaSetName) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final Map yangResourceNameToContent = cpsModulePersistenceService.getYangSchemaResources(dataspaceName, schemaSetName); return YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent); @@ -71,7 +73,7 @@ public class YangTextSchemaSourceSetCache { @CanIgnoreReturnValue public YangTextSchemaSourceSet updateCache(final String dataspaceName, final String schemaSetName, final YangTextSchemaSourceSet yangTextSchemaSourceSet) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); return yangTextSchemaSourceSet; } @@ -84,7 +86,7 @@ public class YangTextSchemaSourceSetCache { */ @CacheEvict(key = "#p0.concat('-').concat(#p1)") public void removeFromCache(final String dataspaceName, final String schemaSetName) { - CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); + cpsValidator.validateNameCharacters(dataspaceName, schemaSetName); // Spring provides implementation for removing object from cache } diff --git a/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java new file mode 100644 index 000000000..c7ce8fc92 --- /dev/null +++ b/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java @@ -0,0 +1,31 @@ +/* + * ============LICENSE_START======================================================= + * 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. + * 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.spi.utils; + +public interface CpsValidator { + + /** + * Validate characters in names within cps. + * + * @param names names of data to be validated + */ + void validateNameCharacters(final String... names); +} diff --git a/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java deleted file mode 100644 index f3774d952..000000000 --- a/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * 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. - * 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.utils; - -import com.google.common.collect.Lists; -import java.util.Collection; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.spi.exceptions.DataValidationException; - -@Slf4j -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class CpsValidator { - - private static final char[] UNSUPPORTED_NAME_CHARACTERS = "!\" #$%&'()*+,./\\:;<=>?@[]^`{|}~".toCharArray(); - - /** - * Validate characters in names within cps. - * - * @param names names of data to be validated - */ - public static void validateNameCharacters(final String... names) { - for (final String name : names) { - final Collection charactersOfName = Lists.charactersOf(name); - for (final char unsupportedCharacter : UNSUPPORTED_NAME_CHARACTERS) { - if (charactersOfName.contains(unsupportedCharacter)) { - throw new DataValidationException("Name or ID Validation Error.", - name + " invalid token encountered at position " - + (name.indexOf(unsupportedCharacter) + 1)); - } - } - } - } - - - -} 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 41fcb29ed..2979c0986 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,30 +24,24 @@ 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.utils.CpsValidator import spock.lang.Specification import java.time.OffsetDateTime class CpsAdminServiceImplSpec extends Specification { def mockCpsAdminPersistenceService = Mock(CpsAdminPersistenceService) def mockCpsDataService = Mock(CpsDataService) - def objectUnderTest = new CpsAdminServiceImpl(mockCpsAdminPersistenceService, mockCpsDataService) + def mockCpsValidator = Mock(CpsValidator) + def objectUnderTest = new CpsAdminServiceImpl(mockCpsAdminPersistenceService, mockCpsDataService,mockCpsValidator) def 'Create dataspace method invokes persistence service.'() { when: 'create dataspace method is invoked' objectUnderTest.createDataspace('someDataspace') then: 'the persistence service method is invoked with same parameters' 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(_) + and: 'the CpsValidator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') } def 'Create anchor method invokes persistence service.'() { @@ -55,76 +49,44 @@ class CpsAdminServiceImplSpec extends Specification { objectUnderTest.createAnchor('someDataspace', 'someSchemaSet', 'someAnchorName') then: 'the persistence service method is invoked with same parameters' 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(_, _, _) + and: 'the CpsValidator is called on the dataspaceName, schemaSetName and anchorName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet', 'someAnchorName') } def 'Retrieve all anchors for dataspace.'() { - given: 'that anchor is associated with the dataspace' + given: 'that an anchor is associated with the dataspace' def anchors = [new Anchor()] mockCpsAdminPersistenceService.getAnchors('someDataspace') >> anchors - expect: 'the collection provided by persistence service is returned as result' - 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(_) + when: 'get Anchors is called for a dataspace name' + def result = objectUnderTest.getAnchors('someDataspace') + then: 'the collection provided by persistence service is returned as result' + result == anchors + and: 'the CpsValidator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') } def 'Retrieve all anchors for schema-set.'() { given: 'that anchor is associated with the dataspace and schemaset' def anchors = [new Anchor()] mockCpsAdminPersistenceService.getAnchors('someDataspace', 'someSchemaSet') >> anchors - expect: 'the collection provided by persistence service is returned as result' - objectUnderTest.getAnchors('someDataspace', 'someSchemaSet') == anchors + when: 'get anchors is called for a dataspace name and schema set name' + def result = objectUnderTest.getAnchors('someDataspace', 'someSchemaSet') + then: 'the collection provided by persistence service is returned as result' + result == anchors + and: 'the CpsValidator is called on the dataspaceName, schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet') } - 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' Anchor anchor = new Anchor() mockCpsAdminPersistenceService.getAnchor('someDataspace','someAnchor') >> anchor - expect: 'the anchor provided by persistence service is returned as result' - 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' + when: 'get anchor is called for a dataspace name and anchor name' + def result = objectUnderTest.getAnchor('someDataspace','someAnchor') + then: 'the anchor provided by persistence service is returned as result' + result == anchor + and: 'the CpsValidator is called on the dataspaceName, anchorName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someAnchor') } def 'Delete anchor.'() { @@ -134,39 +96,19 @@ class CpsAdminServiceImplSpec extends Specification { 1 * mockCpsDataService.deleteDataNodes('someDataspace','someAnchor', _ as OffsetDateTime ) and: 'the persistence service method is invoked with same parameters to delete anchor' 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' + and: 'the CpsValidator is called on the dataspaceName, anchorName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someAnchor') } 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')] - expect: 'get anchor identifiers returns the same anchor identifier returned by the persistence layer' - objectUnderTest.queryAnchorNames('some-dataspace-name', ['some-module-name']) == ['some-anchor-identifier'] - - } - - 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) - then: 'a data validation exception is thrown' - thrown(DataValidationException) - and: 'delete data nodes is not invoked' - 0 * mockCpsAdminPersistenceService.queryAnchors(_, _) + when: 'query anchor names is called using a dataspace name and module name' + def result = objectUnderTest.queryAnchorNames('some-dataspace-name', ['some-module-name']) + then: 'get anchor identifiers returns the same anchor identifier returned by the persistence layer' + result == ['some-anchor-identifier'] + and: 'the CpsValidator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('some-dataspace-name') } def 'Delete dataspace.'() { @@ -174,14 +116,7 @@ class CpsAdminServiceImplSpec extends Specification { objectUnderTest.deleteDataspace('someDataspace') then: 'associated persistence service method is invoked with correct parameter' 1 * mockCpsAdminPersistenceService.deleteDataspace('someDataspace') - } - - 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(_) + and: 'the CpsValidator is called on the dataspaceName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace') } } 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 a53706a06..b60e7e86e 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 @@ -35,6 +35,7 @@ import org.onap.cps.spi.model.DataNodeBuilder import org.onap.cps.yang.YangTextSchemaSourceSet import org.onap.cps.yang.YangTextSchemaSourceSetBuilder import spock.lang.Specification +import org.onap.cps.spi.utils.CpsValidator import java.time.OffsetDateTime import java.util.stream.Collectors @@ -44,9 +45,10 @@ class CpsDataServiceImplSpec extends Specification { def mockCpsAdminService = Mock(CpsAdminService) def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache) def mockNotificationService = Mock(NotificationService) + def mockCpsValidator = Mock(CpsValidator) def objectUnderTest = new CpsDataServiceImpl(mockCpsDataPersistenceService, mockCpsAdminService, - mockYangTextSchemaSourceSetCache, mockNotificationService) + mockYangTextSchemaSourceSetCache, mockNotificationService, mockCpsValidator) def setup() { mockCpsAdminService.getAnchor(dataspaceName, anchorName) >> anchor @@ -67,26 +69,12 @@ class CpsDataServiceImplSpec extends Specification { then: 'the persistence service method is invoked with correct parameters' 1 * mockCpsDataPersistenceService.storeDataNode(dataspaceName, anchorName, { dataNode -> dataNode.xpath == '/test-tree' }) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/', Operation.CREATE, observedTimestamp) } - 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') @@ -96,26 +84,12 @@ class CpsDataServiceImplSpec extends Specification { then: 'the persistence service method is invoked with correct parameters' 1 * mockCpsDataPersistenceService.addChildDataNode(dataspaceName, anchorName, '/test-tree', { dataNode -> dataNode.xpath == '/test-tree/branch[@name=\'New\']' }) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree', Operation.CREATE, observedTimestamp) } - 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') @@ -132,6 +106,8 @@ class CpsDataServiceImplSpec extends Specification { } } ) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree', Operation.UPDATE, observedTimestamp) } @@ -166,20 +142,6 @@ 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() @@ -191,20 +153,6 @@ class CpsDataServiceImplSpec extends Specification { fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] } - 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') @@ -212,6 +160,8 @@ class CpsDataServiceImplSpec extends Specification { objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp) then: 'the persistence service method is invoked with correct parameters' 1 * mockCpsDataPersistenceService.updateDataLeaves(dataspaceName, anchorName, expectedNodeXpath, leaves) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, parentNodeXpath, Operation.UPDATE, observedTimestamp) where: 'following parameters were used' @@ -220,22 +170,6 @@ 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') @@ -261,28 +195,12 @@ class CpsDataServiceImplSpec extends Specification { then: 'the persistence service method is invoked with correct parameters' 1 * mockCpsDataPersistenceService.updateDataLeaves(dataspaceName, anchorName, "/bookstore/categories[@code='01']", ['name':'Romance', 'code': '01']) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'the data updated event is sent to the notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/bookstore', Operation.UPDATE, observedTimestamp) } - 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 using singular data node: #scenario.'() { given: 'schema set for given anchor and dataspace references test-tree model' setupSchemaSetMocks('test-tree.yang') @@ -293,6 +211,8 @@ class CpsDataServiceImplSpec extends Specification { { dataNode -> dataNode.xpath == expectedNodeXpath }) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, parentNodeXpath, Operation.UPDATE, observedTimestamp) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) where: 'following parameters were used' scenario | parentNodeXpath | jsonData || expectedNodeXpath 'top level node' | '/' | '{"test-tree": {"branch": []}}' || '/test-tree' @@ -310,44 +230,14 @@ class CpsDataServiceImplSpec extends Specification { and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, nodesJsonData.keySet()[0], Operation.UPDATE, observedTimestamp) 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, nodesJsonData.keySet()[1], Operation.UPDATE, observedTimestamp) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) where: 'following parameters were used' scenario | nodesJsonData || expectedNodeXpath 'top level node' | ['/' : '{"test-tree": {"branch": []}}', '/test-tree' : '{"branch": [{"name":"Name"}]}'] || ["/test-tree", "/test-tree/branch[@name='Name']"] 'level 2 node' | ['/test-tree' : '{"branch": [{"name":"Name"}]}', '/test-tree/branch[@name=\'Name\']':'{"nest":{"name":"nestName"}}'] || ["/test-tree/branch[@name='Name']", "/test-tree/branch[@name='Name']/nest"] } - def 'Replace data node using singular data node with invalid #scenario.'() { - when: 'replace data method is invoked with invalid #scenario' - objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, '/', _ as String, observedTimestamp) - then: 'a data validation exception is thrown' - thrown(DataValidationException) - and: 'the persistence service method is not invoked' - 0 * mockCpsDataPersistenceService.updateDataNodeAndDescendants(*_) - 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 data node using multiple data nodes with invalid #scenario.'() { - when: 'replace data method is invoked with invalid #scenario' - objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, ['/': _ as String], observedTimestamp) - then: 'a data validation exception is thrown' - thrown(DataValidationException) - and: 'the persistence service method is not invoked' - 0 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(*_) - 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') @@ -364,6 +254,8 @@ class CpsDataServiceImplSpec extends Specification { } } ) + and: 'the CpsValidator is called on the dataspaceName and AnchorName twice' + 2 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree', Operation.UPDATE, observedTimestamp) } @@ -378,22 +270,6 @@ 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, 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') @@ -401,27 +277,12 @@ class CpsDataServiceImplSpec extends Specification { objectUnderTest.deleteListOrListElement(dataspaceName, anchorName, '/test-tree/branch', observedTimestamp) then: 'the persistence service method is invoked with correct parameters' 1 * mockCpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, '/test-tree/branch') + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/test-tree/branch', Operation.DELETE, observedTimestamp) } - - 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') @@ -429,26 +290,12 @@ class CpsDataServiceImplSpec extends Specification { objectUnderTest.deleteDataNode(dataspaceName, anchorName, '/data-node', observedTimestamp) then: 'the persistence service method is invoked with the correct parameters' 1 * mockCpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, '/data-node') + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'data updated event is sent to notification service' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/data-node', Operation.DELETE, observedTimestamp) } - 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') @@ -456,6 +303,8 @@ class CpsDataServiceImplSpec extends Specification { objectUnderTest.deleteDataNodes(dataspaceName, anchorName, observedTimestamp) then: 'data updated event is sent to notification service before the delete' 1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, '/', Operation.DELETE, observedTimestamp) + and: 'the CpsValidator is called on the dataspaceName and AnchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) and: 'the persistence service method is invoked with the correct parameters' 1 * mockCpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName) } 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 429de7d51..690578ea0 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 @@ -1,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2021 Pantheon.tech * Modifications Copyright (C) 2020-2022 Bell Canada. @@ -25,9 +25,9 @@ package org.onap.cps.api.impl import org.onap.cps.TestUtils import org.onap.cps.api.CpsAdminService 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.utils.CpsValidator import org.onap.cps.spi.model.Anchor import org.onap.cps.spi.model.ModuleReference import org.onap.cps.yang.YangTextSchemaSourceSetBuilder @@ -40,8 +40,9 @@ class CpsModuleServiceImplSpec extends Specification { def mockCpsModulePersistenceService = Mock(CpsModulePersistenceService) def mockCpsAdminService = Mock(CpsAdminService) def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache) + def mockCpsValidator = Mock(CpsValidator) - def objectUnderTest = new CpsModuleServiceImpl(mockCpsModulePersistenceService, mockYangTextSchemaSourceSetCache, mockCpsAdminService) + def objectUnderTest = new CpsModuleServiceImpl(mockCpsModulePersistenceService, mockYangTextSchemaSourceSetCache, mockCpsAdminService, mockCpsValidator) def 'Create schema set.'() { given: 'Valid yang resource as name-to-content map' @@ -50,20 +51,8 @@ class CpsModuleServiceImplSpec extends Specification { objectUnderTest.createSchemaSet('someDataspace', 'someSchemaSet', yangResourcesNameToContentMap) then: 'Parameters are validated and processing is delegated to persistence service' 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) - 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' + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet') } def 'Create schema set from new modules and existing modules.'() { @@ -74,20 +63,8 @@ class CpsModuleServiceImplSpec extends Specification { objectUnderTest.createSchemaSetFromModules("someDataspaceName", "someSchemaSetName", [newModule: "newContent"], listOfExistingModulesModuleReference) then: 'processing is delegated to persistence service' 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, _ as Collection) - 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' + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspaceName', 'someSchemaSetName') } def 'Create schema set from invalid resources'() { @@ -110,20 +87,8 @@ class CpsModuleServiceImplSpec extends Specification { result.getName().contains('someSchemaSet') result.getDataspaceName().contains('someDataspace') 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' + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someSchemaSet') } def 'Delete schema-set when cascade is allowed.'() { @@ -140,6 +105,8 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', 'my-schemaset') and: 'orphan yang resources are deleted' 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules() + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', _) where: 'following parameters are used' numberOfAnchors << [0, 3] } @@ -157,6 +124,8 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockYangTextSchemaSourceSetCache.removeFromCache('my-dataspace', 'my-schemaset') and: 'orphan yang resources are deleted' 1 * mockCpsModulePersistenceService.deleteUnusedYangResourceModules() + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset') } def 'Delete schema-set when cascade is prohibited and schema-set has anchors.'() { @@ -168,26 +137,6 @@ 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..> moduleReferences - expect: 'the list provided by persistence service is returned as result' - 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(_) + when: 'get yang resource module references is called' + def result = objectUnderTest.getYangResourceModuleReferences('someDataspaceName') + then: 'the list provided by persistence service is returned as result' + result == moduleReferences + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspaceName') } - 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' def moduleReferences = [new ModuleReference()] mockCpsModulePersistenceService.getYangResourceModuleReferences('someDataspaceName', 'someAnchorName') >> moduleReferences - expect: 'the list provided by persistence service is returned as result' - 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' + when: 'get yang resource module references is called for dataspace name and anchor name' + def result = objectUnderTest.getYangResourcesModuleReferences('someDataspaceName', 'someAnchorName') + then: 'the list provided by persistence service is returned as result' + result == moduleReferences + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('someDataspaceName', 'someAnchorName') } def 'Identifying new module references'(){ @@ -248,5 +181,7 @@ class CpsModuleServiceImplSpec extends Specification { objectUnderTest.getModuleDefinitionsByAnchorName('some-dataspace-name', 'some-anchor-name') then: 'CPS module persistence service is invoked the correct number of times' 1 * mockCpsModulePersistenceService.getYangResourceDefinitions('some-dataspace-name', 'some-anchor-name') + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name') } } 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 b7fec8511..8b232b420 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 @@ -1,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,17 +22,14 @@ 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 org.onap.cps.spi.utils.CpsValidator import spock.lang.Specification class CpsQueryServiceImplSpec extends Specification { def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) + def mockCpsValidator = Mock(CpsValidator) - def objectUnderTest = new CpsQueryServiceImpl() - - def setup() { - objectUnderTest.cpsDataPersistenceService = mockCpsDataPersistenceService - } + def objectUnderTest = new CpsQueryServiceImpl(mockCpsDataPersistenceService, mockCpsValidator) def 'Query data nodes by cps path with #fetchDescendantsOption.'() { given: 'a dataspace name, an anchor name and a cps path' @@ -43,22 +40,10 @@ class CpsQueryServiceImplSpec extends Specification { objectUnderTest.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption) then: 'the persistence service is called once with the correct parameters' 1 * mockCpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption) + and: 'the CpsValidator is called on the dataspaceName, schemaSetName and anchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) where: 'all fetch descendants options are supported' fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] } - 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/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy index 52389522f..2fc85aa5a 100755 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation. + * Copyright (C) 2021-2022 Nordix Foundation. * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ @@ -8,7 +8,7 @@ * 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 + * 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, @@ -28,6 +28,7 @@ import org.onap.cps.notification.NotificationService import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.spi.model.Anchor +import org.onap.cps.spi.utils.CpsValidator import org.onap.cps.utils.YangUtils import org.onap.cps.yang.YangTextSchemaSourceSetBuilder import spock.lang.Specification @@ -38,10 +39,11 @@ class E2ENetworkSliceSpec extends Specification { def mockCpsAdminService = Mock(CpsAdminService) def mockNotificationService = Mock(NotificationService) def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache) + def mockCpsValidator = Mock(CpsValidator) def cpsModuleServiceImpl = new CpsModuleServiceImpl(mockModuleStoreService, - mockYangTextSchemaSourceSetCache,mockCpsAdminService ) + mockYangTextSchemaSourceSetCache, mockCpsAdminService, mockCpsValidator) def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockCpsAdminService, - mockYangTextSchemaSourceSetCache, mockNotificationService) + mockYangTextSchemaSourceSetCache, mockNotificationService, mockCpsValidator) def dataspaceName = 'someDataspace' def anchorName = 'someAnchor' 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 06c675a25..a9f50ee5b 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,5 +1,5 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada * Modifications Copyright (C) 2022 Nordix Foundation * ================================================================================ @@ -23,7 +23,6 @@ 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 @@ -35,6 +34,8 @@ import org.springframework.cache.annotation.EnableCaching import org.springframework.cache.caffeine.CaffeineCacheManager import org.springframework.test.context.ContextConfiguration import spock.lang.Specification +import org.onap.cps.spi.utils.CpsValidator + @SpringBootTest @EnableCaching @@ -44,6 +45,9 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { @SpringBean CpsModulePersistenceService mockModuleStoreService = Mock() + @SpringBean + CpsValidator mockCpsValidator = Mock(CpsValidator) + @Autowired YangTextSchemaSourceSetCache objectUnderTest @@ -74,6 +78,8 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { assert cachedValue.getModuleReferences() == expectedYangTextSchemaSourceSet.getModuleReferences() and: 'the response is as expected' assert result.getModuleReferences() == expectedYangTextSchemaSourceSet.getModuleReferences() + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset') } def 'Cache Hit: Respond from cache'() { @@ -90,20 +96,6 @@ 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') @@ -113,23 +105,8 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { then: 'cached value is same as expected' def cachedValue = getCachedValue('my-dataspace', 'my-schemaset') cachedValue.getModuleReferences() == yangTextSchemaSourceSet.getModuleReferences() - } - - 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' + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset') } def 'Cache Evict:with invalid #scenario'() { @@ -143,18 +120,8 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { objectUnderTest.removeFromCache('my-dataspace', 'my-schemaset') then: 'cached does not have value' 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' + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset') } def 'Cache Evict: remove when does not exist'() { @@ -164,6 +131,8 @@ class YangTextSchemaSourceSetCacheSpec extends Specification { objectUnderTest.removeFromCache('my-dataspace', 'my-schemaset') then: 'cached does not have value' assert getCachedValue('my-dataspace', 'my-schemaset') == null + and: 'the CpsValidator is called on the dataspaceName and schemaSetName' + 1 * mockCpsValidator.validateNameCharacters('my-dataspace', 'my-schemaset') } def getCachedValue(dataSpace, schemaSet) { diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy deleted file mode 100644 index ea7a5d6d1..000000000 --- a/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * 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. - * 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.utils - -import org.onap.cps.spi.exceptions.DataValidationException -import spock.lang.Specification - -class CpsValidatorSpec extends Specification { - - def 'Validating a valid string.'() { - when: 'the string is validated using a valid name' - CpsValidator.validateNameCharacters('name-with-no-spaces') - then: 'no exception is thrown' - noExceptionThrown() - } - - def 'Validating an invalid string.'() { - when: 'the string is validated using an invalid name' - CpsValidator.validateNameCharacters(name) - then: 'a data validation exception is thrown' - def exceptionThrown = thrown(DataValidationException) - and: 'the error was encountered at the following index in #scenario' - assert exceptionThrown.getDetails().contains(expectedErrorMessage) - where: 'the following names are used' - scenario | name || expectedErrorMessage - 'position 5' | 'name with spaces' || 'name with spaces invalid token encountered at position 5' - 'position 9' | 'nameWith Space' || 'nameWith Space invalid token encountered at position 9' - } - -} -- cgit 1.2.3-korg