From: kissand Date: Fri, 23 Sep 2022 11:49:05 +0000 (+0200) Subject: Fix Id-searches endpoint performance degradation X-Git-Tag: 3.2.1~89^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=d05c1d71f33c1d951d5a5196f6c206457431da9e;p=cps.git Fix Id-searches endpoint performance degradation - create more flexible control over fetch descendants - add a new FETCH_DIRECT_CHILDREN_ONLY option to fetch descendants options - enabel create custom fetch descendants option Reviewer: Toine, Joe, Priyank Issue-ID: CPS-1216 Change-Id: I900b32e813367aa9566c1dec986b20f009d27203 Signed-off-by: kissand --- diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java index f8836e6bf..1674c52fc 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java @@ -21,6 +21,7 @@ package org.onap.cps.ncmp.api.impl; import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle; +import static org.onap.cps.spi.FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY; import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateCpsPathConditionProperties; import static org.onap.cps.utils.CmHandleQueryRestParametersValidator.validateModuleNameConditionProperties; @@ -68,14 +69,14 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm */ @Override public Set queryCmHandles( - final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) { return getAllCmHandles(); } final Map combinedQueryResult = executeInventoryQueries( - cmHandleQueryServiceParameters); + cmHandleQueryServiceParameters); return new HashSet<>(combineWithModuleNameQuery(cmHandleQueryServiceParameters, combinedQueryResult).values()); } @@ -88,17 +89,17 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm */ @Override public Set queryCmHandleIds( - final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) { return getAllCmHandleIds(); } final Map combinedQueryResult = executeInventoryQueries( - cmHandleQueryServiceParameters); + cmHandleQueryServiceParameters); final Collection moduleNamesForQuery = - getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); + getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); if (moduleNamesForQuery.isEmpty()) { return combinedQueryResult.keySet(); } @@ -113,10 +114,10 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } private Map combineWithModuleNameQuery( - final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, - final Map previousQueryResult) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, + final Map previousQueryResult) { final Collection moduleNamesForQuery = - getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); + getModuleNamesForQuery(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); if (moduleNamesForQuery.isEmpty()) { return previousQueryResult; } @@ -138,7 +139,7 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } private Map executeInventoryQueries( - final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { final Map cpsPath = getCpsPath(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); if (!validateCpsPathConditionProperties(cpsPath)) { return Collections.emptyMap(); @@ -149,13 +150,13 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } else { try { cpsPathQueryResult = cmHandleQueries.queryCmHandleDataNodesByCpsPath( - cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS) - .stream().map(this::createNcmpServiceCmHandle) - .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId, - Function.identity())); + cpsPath.get("cpsPath"), INCLUDE_ALL_DESCENDANTS) + .stream().map(this::createNcmpServiceCmHandle) + .collect(Collectors.toMap(NcmpServiceCmHandle::getCmHandleId, + Function.identity())); } catch (final PathParsingException pathParsingException) { throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(), - pathParsingException); + pathParsingException); } if (cpsPathQueryResult.isEmpty()) { return Collections.emptyMap(); @@ -163,9 +164,9 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm } final Map publicPropertyQueryPairs = - getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); + getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters()); final Map propertiesQueryResult = publicPropertyQueryPairs.isEmpty() - ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs); + ? NO_QUERY_TO_EXECUTE : cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs); return cmHandleQueries.combineCmHandleQueries(cpsPathQueryResult, propertiesQueryResult); } @@ -190,14 +191,14 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm private Map getCpsPath(final List conditionProperties) { final Map result = new HashMap<>(); getConditions(conditionProperties, ValidQueryProperties.WITH_CPS_PATH.getQueryProperty()).forEach( - result::putAll); + result::putAll); return result; } private Map getPublicPropertyPairs(final List conditionProperties) { final Map result = new HashMap<>(); getConditions(conditionProperties, - ValidQueryProperties.HAS_ALL_PROPERTIES.getQueryProperty()).forEach(result::putAll); + ValidQueryProperties.HAS_ALL_PROPERTIES.getQueryProperty()).forEach(result::putAll); return result; } @@ -213,17 +214,17 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm private Set getAllCmHandles() { return inventoryPersistence.getDataNode("/dmi-registry") - .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet()); + .getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet()); } private Set getAllCmHandleIds() { - return inventoryPersistence.getDataNode("/dmi-registry") - .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString()) - .collect(Collectors.toSet()); + return inventoryPersistence.getDataNode("/dmi-registry", FETCH_DIRECT_CHILDREN_ONLY) + .getChildDataNodes().stream().map(dataNode -> dataNode.getLeaves().get("id").toString()) + .collect(Collectors.toSet()); } private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) { return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter - .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString())); + .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString())); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java index bfc3a9ac0..b29825e7c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java @@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.inventory; import java.util.Collection; import java.util.Map; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.ModuleDefinition; @@ -113,6 +114,15 @@ public interface InventoryPersistence { */ DataNode getDataNode(String xpath); + /** + * Get data node via xpath. + * + * @param xpath xpath + * @param fetchDescendantsOption fetch descendants option + * @return data node + */ + DataNode getDataNode(String xpath, FetchDescendantsOption fetchDescendantsOption); + /** * Get data node of given cm handle. * diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java index 99edfdb0f..eed47edda 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java @@ -76,18 +76,18 @@ public class InventoryPersistenceImpl implements InventoryPersistence { @Override public CompositeState getCmHandleState(final String cmHandleId) { final DataNode stateAsDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, - String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId) + "/state", - FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); + String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId) + "/state", + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); return new CompositeStateBuilder().fromDataNode(stateAsDataNode).build(); } @Override public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) { final String cmHandleJsonData = String.format("{\"state\":%s}", - jsonObjectMapper.asJsonString(compositeState)); + jsonObjectMapper.asJsonString(compositeState)); cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, - String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId), - cmHandleJsonData, OffsetDateTime.now()); + String.format(CM_HANDLE_XPATH_TEMPLATE, cmHandleId), + cmHandleJsonData, OffsetDateTime.now()); } @Override @@ -153,8 +153,13 @@ public class InventoryPersistenceImpl implements InventoryPersistence { @Override public DataNode getDataNode(final String xpath) { + return getDataNode(xpath, INCLUDE_ALL_DESCENDANTS); + } + + @Override + public DataNode getDataNode(final String xpath, final FetchDescendantsOption fetchDescendantsOption) { return cpsDataPersistenceService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, - xpath, INCLUDE_ALL_DESCENDANTS); + xpath, fetchDescendantsOption); } @Override @@ -164,7 +169,7 @@ public class InventoryPersistenceImpl implements InventoryPersistence { @Override public Collection queryAnchors(final Collection moduleNamesForQuery) { - return cpsAdminPersistenceService.queryAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery); + return cpsAdminPersistenceService.queryAnchors(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery); } @Override diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy index f76316f9c..eea53e82d 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy @@ -153,7 +153,9 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { def 'Retrieve cm handles when the query is empty.'() { given: 'We use an empty query' def cmHandleQueryParameters = new CmHandleQueryServiceParameters() - and: 'the inventory persistence returns the dmi registry datanode' + and: 'the inventory persistence returns the dmi registry datanode with just ids' + inventoryPersistence.getDataNode("/dmi-registry", FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY) >> dmiRegistry + and: 'the inventory persistence returns the dmi registry datanode with data' inventoryPersistence.getDataNode("/dmi-registry") >> dmiRegistry when: 'the query is executed for both cm handle ids and details' def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters) diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index c13422dc4..ebc851a44 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -22,8 +22,6 @@ package org.onap.cps.spi.impl; -import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; - import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import java.util.ArrayList; @@ -102,7 +100,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService @Override public void addMultipleLists(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection> newLists) { + final Collection> newLists) { final Collection failedXpaths = new HashSet<>(); newLists.forEach(newList -> { try { @@ -119,7 +117,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } private void addNewChildDataNode(final String dataspaceName, final String anchorName, - final String parentNodeXpath, final DataNode newChild) { + final String parentNodeXpath, final DataNode newChild) { final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants(parentFragmentEntity.getDataspace(), @@ -134,7 +132,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } private void addChildrenDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath, - final Collection newChildren) { + final Collection newChildren) { final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath); final List fragmentEntities = new ArrayList<>(newChildren.size()); try { @@ -154,7 +152,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } private void retrySavingEachChildIndividually(final String dataspaceName, final String anchorName, - final String parentNodeXpath, final Collection newChildren) { + final String parentNodeXpath, + final Collection newChildren) { final Collection failedXpaths = new HashSet<>(); for (final DataNode newChild : newChildren) { try { @@ -191,7 +190,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService * @return a Fragment built from current DataNode */ private FragmentEntity convertToFragmentWithAllDescendants(final DataspaceEntity dataspaceEntity, - final AnchorEntity anchorEntity, final DataNode dataNodeToBeConverted) { + final AnchorEntity anchorEntity, + final DataNode dataNodeToBeConverted) { final FragmentEntity parentFragment = toFragmentEntity(dataspaceEntity, anchorEntity, dataNodeToBeConverted); final Builder childFragmentsImmutableSetBuilder = ImmutableSet.builder(); for (final DataNode childDataNode : dataNodeToBeConverted.getChildDataNodes()) { @@ -226,7 +226,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); if (isRootXpath(xpath)) { - return fragmentRepository.findFirstRootByDataspaceAndAnchor(dataspaceEntity, anchorEntity); + return fragmentRepository.findFirstRootByDataspaceAndAnchor( + dataspaceEntity, anchorEntity); } else { final String normalizedXpath; try { @@ -235,7 +236,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService throw new CpsPathException(e.getMessage()); } - return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, normalizedXpath); + return fragmentRepository.getByDataspaceAndAnchorAndXpath( + dataspaceEntity, anchorEntity, normalizedXpath); } } @@ -319,10 +321,10 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private List getChildDataNodes(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { - if (fetchDescendantsOption == INCLUDE_ALL_DESCENDANTS) { + if (fetchDescendantsOption.hasNext()) { return fragmentEntity.getChildFragments().stream() - .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption)) - .collect(Collectors.toUnmodifiableList()); + .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption.next())) + .collect(Collectors.toList()); } return Collections.emptyList(); } @@ -355,10 +357,11 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final List dataNodes) { final Map dataNodeFragmentEntityMap = dataNodes.stream() - .collect(Collectors.toMap( - dataNode -> dataNode, dataNode -> getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath()))); + .collect(Collectors.toMap( + dataNode -> dataNode, + dataNode -> getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath()))); dataNodeFragmentEntityMap.forEach( - (dataNode, fragmentEntity) -> updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode)); + (dataNode, fragmentEntity) -> updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode)); try { fragmentRepository.saveAll(dataNodeFragmentEntityMap.values()); } catch (final StaleStateException staleStateException) { @@ -367,7 +370,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } private void retryUpdateDataNodesIndividually(final String dataspaceName, final String anchorName, - final Collection fragmentEntities) { + final Collection fragmentEntities) { final Collection failedXpaths = new HashSet<>(); fragmentEntities.forEach(dataNodeFragment -> { diff --git a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java index 0c994d8d7..b80054ac3 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java +++ b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech + * 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. @@ -19,7 +20,48 @@ package org.onap.cps.spi; -public enum FetchDescendantsOption { - OMIT_DESCENDANTS, - INCLUDE_ALL_DESCENDANTS +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class FetchDescendantsOption { + + public static final FetchDescendantsOption FETCH_DIRECT_CHILDREN_ONLY = new FetchDescendantsOption(1); + public static final FetchDescendantsOption OMIT_DESCENDANTS = new FetchDescendantsOption(0); + public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS = new FetchDescendantsOption(-1); + + private final int depth; + + /** + * Has next depth. + * + * @return true if next level of depth is available + * @throws IllegalArgumentException when depth less than -1 + */ + public boolean hasNext() { + validateDepth(depth); + return depth > 0 || this.depth == INCLUDE_ALL_DESCENDANTS.depth; + } + + /** + * Next fetch descendants option. + * + * @return the next fetch descendants option + * @throws IllegalArgumentException when depth less than -1 or 0 + */ + public FetchDescendantsOption next() { + if (depth == 0) { + throw new IllegalArgumentException("Do not use next() method with zero depth"); + } + final FetchDescendantsOption nextDescendantsOption = this.depth == INCLUDE_ALL_DESCENDANTS.depth + ? INCLUDE_ALL_DESCENDANTS : new FetchDescendantsOption(depth - 1); + validateDepth(nextDescendantsOption.depth); + return nextDescendantsOption; + } + + private static void validateDepth(final int depth) { + if (depth < -1) { + throw new IllegalArgumentException("A depth of less than minus one is not allowed"); + } + } + } 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 3f28f0ac8..a53706a06 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 @@ -188,7 +188,7 @@ class CpsDataServiceImplSpec extends Specification { expect: 'service returns same data if uses same parameters' objectUnderTest.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption) == dataNode where: 'all fetch options are supported' - fetchDescendantsOption << FetchDescendantsOption.values() + fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] } def 'Get data node with option invalid #scenario.'() { 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 55a252c27..b7fec8511 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,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation + * 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. @@ -44,7 +44,7 @@ class CpsQueryServiceImplSpec extends Specification { then: 'the persistence service is called once with the correct parameters' 1 * mockCpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption) where: 'all fetch descendants options are supported' - fetchDescendantsOption << FetchDescendantsOption.values() + fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] } def 'Query data nodes by cps path with invalid #scenario.'() { diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy new file mode 100644 index 000000000..627383561 --- /dev/null +++ b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy @@ -0,0 +1,75 @@ +/* + * ============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 + + +import spock.lang.Specification + +class FetchDescendantsOptionSpec extends Specification { + def 'Check has next descendant for fetch descendant option: #scenario'() { + when: 'fetch descendant option with #depth depth' + def fetchDescendantsOption = new FetchDescendantsOption(depth) + then: 'next level descendants available: #expectedHasNext' + fetchDescendantsOption.hasNext() == expectedHasNext + where: 'following parameters are used' + scenario | depth || expectedHasNext + 'omit descendants' | 0 || false + 'first child' | 1 || true + 'second child' | 2 || true + 'include all descendants' | -1 || true + } + + def 'Check has next descendant for fetch descendant option: invalid depth'() { + given: 'fetch descendant option with -2 depth' + def fetchDescendantsOption = new FetchDescendantsOption(-2) + when: 'next level descendants not available' + fetchDescendantsOption.hasNext() + then: 'exception thrown' + thrown IllegalArgumentException + } + + def 'Get next descendant for fetch descendant option: #scenario'() { + when: 'fetch descendant option with #depth depth' + def fetchDescendantsOption = new FetchDescendantsOption(depth) + then: 'the next level of depth is as expected' + fetchDescendantsOption.next().depth == depth - 1 + where: 'following parameters are used' + scenario | depth + 'first child' | 1 + 'second child' | 2 + } + + def 'Get next descendant for fetch descendant option: include all descendants'() { + when: 'fetch descendant option with -1 depth' + def fetchDescendantsOption = new FetchDescendantsOption(-1) + then: 'the next level of depth is as expected' + fetchDescendantsOption.next().depth == -1 + } + + def 'Get next descendant for fetch descendant option: omit descendants'() { + given: 'fetch descendant option with 0 depth' + def fetchDescendantsOption = new FetchDescendantsOption(0) + when: 'the next level of depth is not allowed' + fetchDescendantsOption.next() + then: 'exception thrown' + thrown IllegalArgumentException + } +}