aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g48
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBooleanOperatorType.java51
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java35
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java2
-rw-r--r--cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy64
-rw-r--r--cps-ri/pom.xml2
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java24
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java6
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java1
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java33
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java38
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java17
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java5
-rw-r--r--cps-ri/src/main/resources/changelog/changelog-master.yaml2
-rw-r--r--cps-ri/src/main/resources/changelog/db/changes/18-cascade-delete-fragment-children.yaml34
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy41
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsAdminServiceLimits.groovy50
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimits.groovy63
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy10
19 files changed, 355 insertions, 131 deletions
diff --git a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
index db09b3c53..d4718111f 100644
--- a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
+++ b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,14 +41,16 @@ yangElement : containerName listElementRef? ;
containerName : QName ;
-listElementRef : OB leafCondition ( KW_AND leafCondition)* CB ;
+listElementRef : OB leafCondition ( booleanOperators leafCondition)* CB ;
-multipleLeafConditions : OB leafCondition ( KW_AND leafCondition)* CB ;
+multipleLeafConditions : OB leafCondition ( booleanOperators leafCondition)* CB ;
leafCondition : AT leafName EQ ( IntegerLiteral | StringLiteral) ;
leafName : QName ;
+booleanOperators : ( KW_AND | KW_OR ) ;
+
invalidPostFix : (AT | CB | COLONCOLON | EQ ).+ ;
/*
@@ -68,6 +71,7 @@ SLASH : '/' ;
KW_ANCESTOR : 'ancestor' ;
KW_AND : 'and' ;
KW_TEXT_FUNCTION: 'text()' ;
+KW_OR : 'or' ;
IntegerLiteral : FragDigits ;
// Add below type definitions for leafvalue comparision in https://jira.onap.org/browse/CPS-440
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBooleanOperatorType.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBooleanOperatorType.java
new file mode 100644
index 000000000..b2f1dddb1
--- /dev/null
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBooleanOperatorType.java
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 TechMahindra Ltd
+ * ================================================================================
+ * 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.cpspath.parser;
+
+public enum CpsPathBooleanOperatorType {
+ AND("and"),
+ OR("or");
+
+ private final String operatorValue;
+
+ CpsPathBooleanOperatorType(final String operatorValue) {
+ this.operatorValue = operatorValue;
+ }
+
+ public String getValues() {
+ return this.operatorValue;
+ }
+
+ /**
+ * Finds the value of the given enumeration.
+ *
+ * @param operatorValue value of the enum
+ * @return a booleanOperatorType
+ */
+ public static CpsPathBooleanOperatorType fromString(final String operatorValue) {
+ for (final CpsPathBooleanOperatorType booleanOperatorType : CpsPathBooleanOperatorType.values()) {
+ if (booleanOperatorType.operatorValue.equalsIgnoreCase(operatorValue)) {
+ return booleanOperatorType;
+ }
+ }
+ return null;
+ }
+}
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
index 3a9d70ebb..4299d1308 100644
--- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +25,10 @@ import static org.onap.cps.cpspath.parser.CpsPathPrefixType.DESCENDANT;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext;
@@ -54,6 +57,10 @@ public class CpsPathBuilder extends CpsPathBaseListener {
private List<String> containerNames = new ArrayList<>();
+ final List<String> booleanOperators = new ArrayList<>();
+
+ final Queue<String> booleanOperatorsQueue = new LinkedList<>();
+
@Override
public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) {
throw new PathParsingException(ctx.getText());
@@ -90,13 +97,23 @@ public class CpsPathBuilder extends CpsPathBaseListener {
throw new PathParsingException("Unsupported comparison value encountered in expression" + ctx.getText());
}
leavesData.put(ctx.leafName().getText(), comparisonValue);
- appendCondition(normalizedXpathBuilder, ctx.leafName().getText(), comparisonValue);
+ final String booleanOperator = booleanOperatorsQueue.poll();
+ appendCondition(normalizedXpathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue);
if (processingAncestorAxis) {
- appendCondition(normalizedAncestorPathBuilder, ctx.leafName().getText(), comparisonValue);
+ appendCondition(normalizedAncestorPathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue);
}
}
@Override
+ public void exitBooleanOperators(final CpsPathParser.BooleanOperatorsContext ctx) {
+ final CpsPathBooleanOperatorType cpsPathBooleanOperatorType = CpsPathBooleanOperatorType.fromString(
+ ctx.getText());
+ booleanOperators.add(cpsPathBooleanOperatorType.getValues());
+ booleanOperatorsQueue.add(cpsPathBooleanOperatorType.getValues());
+ cpsPathQuery.setBooleanOperatorsType(booleanOperators);
+ }
+
+ @Override
public void exitDescendant(final DescendantContext ctx) {
cpsPathQuery.setCpsPathPrefixType(DESCENDANT);
cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(1));
@@ -170,13 +187,13 @@ public class CpsPathBuilder extends CpsPathBaseListener {
}
private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name,
- final Object value) {
+ final String booleanOperator, final Object value) {
final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
- currentNormalizedPathBuilder.append(lastCharacter == '[' ? "" : " and ")
- .append("@")
- .append(name)
- .append("='")
- .append(value)
- .append("'");
+ currentNormalizedPathBuilder.append(lastCharacter == '[' ? "" : " " + booleanOperator + " ")
+ .append("@")
+ .append(name)
+ .append("='")
+ .append(value)
+ .append("'");
}
}
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
index 398545526..2c96d9105 100644
--- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +43,7 @@ public class CpsPathQuery {
private String ancestorSchemaNodeIdentifier = "";
private String textFunctionConditionLeafName;
private String textFunctionConditionValue;
+ private List<String> booleanOperatorsType;
/**
* Returns a cps path query.
diff --git a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
index b837a64fe..153dfbe9e 100644
--- a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
+++ b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,19 +67,23 @@ class CpsPathQuerySpec extends Specification {
then: 'the query has the right normalized xpath type'
assert result.normalizedXpath == expectedNormalizedXPath
where: 'the following data is used'
- scenario | cpsPath || expectedNormalizedXPath
- 'yang container' | '/cps-path' || '/cps-path'
- 'descendant anywhere' | '//cps-path' || '//cps-path'
- 'descendant with leaf condition' | '//cps-path[@key=1]' || "//cps-path[@key='1']"
- 'descendant with leaf value and ancestor' | '//cps-path[@key=1]/ancestor:parent[@key=1]' || "//cps-path[@key='1']/ancestor:parent[@key='1']"
- 'parent & child' | '/parent/child' || '/parent/child'
- 'parent leaf of type Integer & child' | '/parent/child[@code=1]/child2' || "/parent/child[@code='1']/child2"
- 'parent leaf with double quotes' | '/parent/child[@code="1"]/child2' || "/parent/child[@code='1']/child2"
- 'parent leaf with double quotes inside single quotes' | '/parent/child[@code=\'"1"\']/child2' || "/parent/child[@code='\"1\"']/child2"
- 'parent leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]/child2' || "/parent/child[@code='\\\'1\\\'']/child2"
- 'leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]' || "/parent/child[@code='\\\'1\\\'']"
- 'leaf with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]' || "/parent/child[@key1='1' and @key2='abc']"
- 'parent & child with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]/child2' || "/parent/child[@key1='1' and @key2='abc']/child2"
+ scenario | cpsPath || expectedNormalizedXPath
+ 'yang container' | '/cps-path' || '/cps-path'
+ 'descendant anywhere' | '//cps-path' || '//cps-path'
+ 'descendant with leaf condition' | '//cps-path[@key=1]' || "//cps-path[@key='1']"
+ 'descendant with leaf value and ancestor' | '//cps-path[@key=1]/ancestor:parent[@key=1]' || "//cps-path[@key='1']/ancestor:parent[@key='1']"
+ 'parent & child' | '/parent/child' || '/parent/child'
+ 'parent leaf of type Integer & child' | '/parent/child[@code=1]/child2' || "/parent/child[@code='1']/child2"
+ 'parent leaf with double quotes' | '/parent/child[@code="1"]/child2' || "/parent/child[@code='1']/child2"
+ 'parent leaf with double quotes inside single quotes' | '/parent/child[@code=\'"1"\']/child2' || "/parent/child[@code='\"1\"']/child2"
+ 'parent leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]/child2' || "/parent/child[@code='\\\'1\\\'']/child2"
+ 'leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]' || "/parent/child[@code='\\\'1\\\'']"
+ 'leaf with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]' || "/parent/child[@key1='1' and @key2='abc']"
+ 'parent & child with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]/child2' || "/parent/child[@key1='1' and @key2='abc']/child2"
+ 'leaf with more than one attribute has OR operator' | '/parent/child[@key1=1 or @key2="abc"]' || "/parent/child[@key1='1' or @key2='abc']"
+ 'parent & child with more than one attribute has OR operator' | '/parent/child[@key1=1 or @key2="abc"]/child2' || "/parent/child[@key1='1' or @key2='abc']/child2"
+ 'parent & child with multiple AND operators' | '/parent/child[@key1=1 and @key2="abc" and @key="xyz"]/child2' || "/parent/child[@key1='1' and @key2='abc' and @key='xyz']/child2"
+ 'parent & child with multiple OR operators' | '/parent/child[@key1=1 or @key2="abc" or @key="xyz"]/child2' || "/parent/child[@key1='1' or @key2='abc' or @key='xyz']/child2"
}
def 'Parse xpath to form the Normalized xpath containing #scenario.'() {
@@ -100,10 +105,14 @@ class CpsPathQuerySpec extends Specification {
and: 'the right parameters are set'
result.descendantName == "child"
result.leavesData.size() == expectedNumberOfLeaves
+ result.booleanOperatorsType == expectedOperators
where: 'the following data is used'
- scenario | cpsPath || expectedNumberOfLeaves
- 'one attribute' | '//child[@common-leaf-name-int=5]' || 1
- 'more than one attribute' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2
+ scenario | cpsPath || expectedNumberOfLeaves || expectedOperators
+ 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 || null
+ 'more than one attribute has AND operator' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 || ['and']
+ 'more than one attribute has OR operator' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 || ['or']
+ 'more than one attribute has combinations and/or operator' | '//child[@int-leaf=5 and @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['and', 'and']
+ 'more than one attribute has combinations or/and operator' | '//child[@int-leaf=5 or @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['or', 'or']
}
def 'Parse #scenario cps path with text function condition'() {
@@ -133,18 +142,17 @@ class CpsPathQuerySpec extends Specification {
then: 'a CpsPathException is thrown'
thrown(PathParsingException)
where: 'the following data is used'
- scenario | cpsPath
- 'no / at the start' | 'invalid-cps-path/child'
- 'additional / after descendant option' | '///cps-path'
- 'float value' | '/parent/child[@someFloat=5.0]'
- 'unmatched quotes, double quote first ' | '/parent/child[@someString="value with unmatched quotes\']'
- 'unmatched quotes, single quote first' | '/parent/child[@someString=\'value with unmatched quotes"]'
- 'end with descendant and more than one attribute separated by "or"' | '//child[@int-leaf=5 or @leaf-name="leaf value"]'
- 'missing attribute value' | '//child[@int-leaf=5 and @name]'
- 'incomplete ancestor value' | '//books/ancestor::'
- 'invalid list element with missing [' | '/parent-206/child-206/grand-child-206@key="A"]'
- 'invalid list element with incorrect ]' | '/parent-206/child-206/grand-child-206]@key="A"]'
- 'invalid list element with incorrect ::' | '/parent-206/child-206/grand-child-206::@key"A"]'
+ scenario | cpsPath
+ 'no / at the start' | 'invalid-cps-path/child'
+ 'additional / after descendant option' | '///cps-path'
+ 'float value' | '/parent/child[@someFloat=5.0]'
+ 'unmatched quotes, double quote first ' | '/parent/child[@someString="value with unmatched quotes\']'
+ 'unmatched quotes, single quote first' | '/parent/child[@someString=\'value with unmatched quotes"]'
+ 'missing attribute value' | '//child[@int-leaf=5 and @name]'
+ 'incomplete ancestor value' | '//books/ancestor::'
+ 'invalid list element with missing [' | '/parent-206/child-206/grand-child-206@key="A"]'
+ 'invalid list element with incorrect ]' | '/parent-206/child-206/grand-child-206]@key="A"]'
+ 'invalid list element with incorrect ::' | '/parent-206/child-206/grand-child-206::@key"A"]'
}
def 'Parse cps path using ancestor by schema node identifier with a #scenario.'() {
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml
index e9b2abb3f..7ce24d960 100644
--- a/cps-ri/pom.xml
+++ b/cps-ri/pom.xml
@@ -33,7 +33,7 @@
<artifactId>cps-ri</artifactId>
<properties>
- <minimum-coverage>0.82</minimum-coverage>
+ <minimum-coverage>0.80</minimum-coverage>
</properties>
<dependencies>
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
index 46b0fec1c..f7b586d7b 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
@@ -22,7 +22,6 @@ package org.onap.cps.spi.repository;
import java.util.Collection;
import java.util.Optional;
-import javax.validation.constraints.NotNull;
import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.SchemaSetEntity;
@@ -35,25 +34,24 @@ import org.springframework.stereotype.Repository;
@Repository
public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
- Optional<AnchorEntity> findByDataspaceAndName(@NotNull DataspaceEntity dataspaceEntity, @NotNull String name);
+ Optional<AnchorEntity> findByDataspaceAndName(DataspaceEntity dataspaceEntity, String name);
- default AnchorEntity getByDataspaceAndName(@NotNull DataspaceEntity dataspace,
- @NotNull String anchorName) {
+ default AnchorEntity getByDataspaceAndName(DataspaceEntity dataspace, String anchorName) {
return findByDataspaceAndName(dataspace, anchorName)
.orElseThrow(() -> new AnchorNotFoundException(anchorName, dataspace.getName()));
}
- Collection<AnchorEntity> findAllByDataspace(@NotNull DataspaceEntity dataspaceEntity);
+ Collection<AnchorEntity> findAllByDataspace(DataspaceEntity dataspaceEntity);
- Collection<AnchorEntity> findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity);
+ Collection<AnchorEntity> findAllBySchemaSet(SchemaSetEntity schemaSetEntity);
- Collection<AnchorEntity> findAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
- @NotNull Collection<String> anchorNames);
+ Collection<AnchorEntity> findAllByDataspaceAndNameIn(DataspaceEntity dataspaceEntity,
+ Collection<String> anchorNames);
- Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(@NotNull DataspaceEntity dataspaceEntity,
- @NotNull Collection<String> schemaSetNames);
+ Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(DataspaceEntity dataspaceEntity,
+ Collection<String> schemaSetNames);
- Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity);
+ Integer countByDataspace(DataspaceEntity dataspaceEntity);
@Query(value = "SELECT anchor.* FROM yang_resource\n"
+ "JOIN schema_set_yang_resources ON schema_set_yang_resources.yang_resource_id = yang_resource.id\n"
@@ -65,6 +63,6 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
@Param("moduleNames") Collection<String> moduleNames, @Param("sizeOfModuleNames") int sizeOfModuleNames);
- void deleteAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
- @NotNull Collection<String> anchorNames);
+ void deleteAllByDataspaceAndNameIn(DataspaceEntity dataspaceEntity,
+ Collection<String> anchorNames);
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java
index 10c6541d0..b1ce127c4 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Bell Canada. All rights reserved.
+ * Modifications Copyright (C) 2023 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +21,6 @@
package org.onap.cps.spi.repository;
import java.util.Optional;
-import javax.validation.constraints.NotNull;
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.exceptions.DataspaceNotFoundException;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -29,7 +29,7 @@ import org.springframework.stereotype.Repository;
@Repository
public interface DataspaceRepository extends JpaRepository<DataspaceEntity, Integer> {
- Optional<DataspaceEntity> findByName(@NotNull String name);
+ Optional<DataspaceEntity> findByName(String name);
/**
* Get a dataspace by name.
@@ -38,7 +38,7 @@ public interface DataspaceRepository extends JpaRepository<DataspaceEntity, Inte
* @param name the name of the dataspace
* @return the Dataspace found
*/
- default DataspaceEntity getByName(@NotNull final String name) {
+ default DataspaceEntity getByName(final String name) {
return findByName(name).orElseThrow(() -> new DataspaceNotFoundException(name));
}
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java
index 13320bf76..bad68f7e5 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java
@@ -26,7 +26,6 @@ import java.util.Collection;
* This interface is used in delete fragment entity by id with child using native sql queries.
*/
public interface FragmentNativeRepository {
- void deleteFragmentEntity(long fragmentEntityId);
/**
* Delete fragment entities for each supplied xpath.
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
index 5c5458a03..04b7080de 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
@@ -31,30 +31,13 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class FragmentNativeRepositoryImpl implements FragmentNativeRepository {
- private static final String DROP_FRAGMENT_CONSTRAINT
- = "ALTER TABLE fragment DROP CONSTRAINT fragment_parent_id_fkey;";
- private static final String ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
- = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) "
- + "REFERENCES fragment (id) ON DELETE CASCADE;";
- private static final String ADD_ORIGINAL_FRAGMENT_CONSTRAINT
- = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) "
- + "REFERENCES fragment (id) ON DELETE NO ACTION;";
-
@PersistenceContext
private final EntityManager entityManager;
@Override
- public void deleteFragmentEntity(final long fragmentEntityId) {
- entityManager.createNativeQuery(
- addFragmentConstraintWithDeleteCascade("DELETE FROM fragment WHERE id = ?"))
- .setParameter(1, fragmentEntityId)
- .executeUpdate();
- }
-
- @Override
public void deleteByAnchorIdAndXpaths(final int anchorId, final Collection<String> xpaths) {
- final String queryString = addFragmentConstraintWithDeleteCascade(
- "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath IN (:parameterPlaceholders))");
+ final String queryString =
+ "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath IN (:parameterPlaceholders))";
executeUpdateWithAnchorIdAndCollection(queryString, anchorId, xpaths);
}
@@ -62,8 +45,8 @@ public class FragmentNativeRepositoryImpl implements FragmentNativeRepository {
public void deleteListsByAnchorIdAndXpaths(final int anchorId, final Collection<String> listXpaths) {
final Collection<String> listXpathPatterns =
listXpaths.stream().map(listXpath -> listXpath + "[%").collect(Collectors.toSet());
- final String queryString = addFragmentConstraintWithDeleteCascade(
- "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath LIKE ANY (array[:parameterPlaceholders]))");
+ final String queryString =
+ "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath LIKE ANY (array[:parameterPlaceholders]))";
executeUpdateWithAnchorIdAndCollection(queryString, anchorId, listXpathPatterns);
}
@@ -86,12 +69,4 @@ public class FragmentNativeRepositoryImpl implements FragmentNativeRepository {
}
}
- private static String addFragmentConstraintWithDeleteCascade(final String queryString) {
- return DROP_FRAGMENT_CONSTRAINT
- + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
- + queryString + ";"
- + DROP_FRAGMENT_CONSTRAINT
- + ADD_ORIGINAL_FRAGMENT_CONSTRAINT;
- }
-
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
index c23159593..ca6e18bad 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
@@ -22,12 +22,16 @@
package org.onap.cps.spi.repository;
import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
+import java.util.Queue;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
import org.onap.cps.cpspath.parser.CpsPathPrefixType;
import org.onap.cps.cpspath.parser.CpsPathQuery;
import org.onap.cps.spi.entities.FragmentEntity;
@@ -60,18 +64,7 @@ public class FragmentQueryBuilder {
final Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("anchorId", anchorId);
sqlStringBuilder.append(" AND xpath ~ :xpathRegex");
- final String xpathRegex = getXpathSqlRegex(cpsPathQuery, false);
- queryParameters.put("xpathRegex", xpathRegex);
- if (cpsPathQuery.hasLeafConditions()) {
- sqlStringBuilder.append(" AND attributes @> :leafDataAsJson\\:\\:jsonb");
- queryParameters.put("leafDataAsJson", jsonObjectMapper.asJsonString(
- cpsPathQuery.getLeavesData()));
- }
-
- addTextFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
- final Query query = entityManager.createNativeQuery(sqlStringBuilder.toString(), FragmentEntity.class);
- setQueryParameters(query, queryParameters);
- return query;
+ return getQuery(cpsPathQuery, sqlStringBuilder, queryParameters);
}
/**
@@ -83,14 +76,27 @@ public class FragmentQueryBuilder {
public Query getQueryForCpsPath(final CpsPathQuery cpsPathQuery) {
final StringBuilder sqlStringBuilder = new StringBuilder("SELECT * FROM FRAGMENT WHERE xpath ~ :xpathRegex");
final Map<String, Object> queryParameters = new HashMap<>();
+ return getQuery(cpsPathQuery, sqlStringBuilder, queryParameters);
+ }
+
+ private Query getQuery(final CpsPathQuery cpsPathQuery, final StringBuilder sqlStringBuilder,
+ final Map<String, Object> queryParameters) {
final String xpathRegex = getXpathSqlRegex(cpsPathQuery, false);
queryParameters.put("xpathRegex", xpathRegex);
+ final List<String> queryBooleanOperatorsType = cpsPathQuery.getBooleanOperatorsType();
if (cpsPathQuery.hasLeafConditions()) {
- sqlStringBuilder.append(" AND attributes @> :leafDataAsJson\\:\\:jsonb");
- queryParameters.put("leafDataAsJson", jsonObjectMapper.asJsonString(
- cpsPathQuery.getLeavesData()));
+ sqlStringBuilder.append(" AND (");
+ final Queue<String> booleanOperatorsQueue = (queryBooleanOperatorsType == null) ? null : new LinkedList<>(
+ queryBooleanOperatorsType);
+ cpsPathQuery.getLeavesData().entrySet().forEach(entry -> {
+ sqlStringBuilder.append(" attributes @> ");
+ sqlStringBuilder.append("'" + jsonObjectMapper.asJsonString(entry) + "'");
+ if (!CollectionUtils.isEmpty(booleanOperatorsQueue)) {
+ sqlStringBuilder.append(" " + booleanOperatorsQueue.poll() + " ");
+ }
+ });
+ sqlStringBuilder.append(")");
}
-
addTextFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
final Query query = entityManager.createNativeQuery(sqlStringBuilder.toString(), FragmentEntity.class);
setQueryParameters(query, queryParameters);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java
index 98d442010..3263f3447 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java
@@ -25,7 +25,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
-import javax.validation.constraints.NotNull;
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.SchemaSetEntity;
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
@@ -38,17 +37,16 @@ import org.springframework.stereotype.Repository;
@Repository
public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Integer> {
- Optional<SchemaSetEntity> findByDataspaceAndName(@NotNull DataspaceEntity dataspaceEntity,
- @NotNull String schemaSetName);
+ Optional<SchemaSetEntity> findByDataspaceAndName(DataspaceEntity dataspaceEntity, String schemaSetName);
/**
* Gets schema sets by dataspace.
* @param dataspaceEntity dataspace entity
* @return list of schema set entity
*/
- Collection<SchemaSetEntity> findByDataspace(@NotNull DataspaceEntity dataspaceEntity);
+ Collection<SchemaSetEntity> findByDataspace(DataspaceEntity dataspaceEntity);
- Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity);
+ Integer countByDataspace(DataspaceEntity dataspaceEntity);
/**
* Gets a schema set by dataspace and schema set name.
@@ -58,8 +56,7 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte
* @return schema set entity
* @throws SchemaSetNotFoundException if SchemaSet not found
*/
- default SchemaSetEntity getByDataspaceAndName(@NotNull final DataspaceEntity dataspaceEntity,
- @NotNull final String schemaSetName) {
+ default SchemaSetEntity getByDataspaceAndName(final DataspaceEntity dataspaceEntity, final String schemaSetName) {
return findByDataspaceAndName(dataspaceEntity, schemaSetName)
.orElseThrow(() -> new SchemaSetNotFoundException(dataspaceEntity.getName(), schemaSetName));
}
@@ -71,7 +68,7 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte
* @return list of schema set entity
* @throws SchemaSetNotFoundException if SchemaSet not found
*/
- default List<SchemaSetEntity> getByDataspace(@NotNull final DataspaceEntity dataspaceEntity) {
+ default List<SchemaSetEntity> getByDataspace(final DataspaceEntity dataspaceEntity) {
return findByDataspace(dataspaceEntity).stream().collect(Collectors.toList());
}
@@ -82,6 +79,6 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte
*/
@Modifying
@Query("DELETE FROM SchemaSetEntity s WHERE s.dataspace = :dataspaceEntity AND s.name IN (:schemaSetNames)")
- void deleteByDataspaceAndNameIn(@NotNull @Param("dataspaceEntity") final DataspaceEntity dataspaceEntity,
- @NotNull @Param("schemaSetNames") final Collection<String> schemaSetNames);
+ void deleteByDataspaceAndNameIn(@Param("dataspaceEntity") DataspaceEntity dataspaceEntity,
+ @Param("schemaSetNames") Collection<String> schemaSetNames);
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
index 6ca4fff4f..fff0a6a03 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
- * Modifications Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2021-2023 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,7 +23,6 @@ package org.onap.cps.spi.repository;
import java.util.Collection;
import java.util.List;
import java.util.Set;
-import javax.validation.constraints.NotNull;
import org.onap.cps.spi.entities.YangResourceEntity;
import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -36,7 +35,7 @@ import org.springframework.stereotype.Repository;
public interface YangResourceRepository extends JpaRepository<YangResourceEntity, Long>,
YangResourceNativeRepository, SchemaSetYangResourceRepository {
- List<YangResourceEntity> findAllByChecksumIn(@NotNull Set<String> checksum);
+ List<YangResourceEntity> findAllByChecksumIn(Set<String> checksum);
@Query(value = "SELECT DISTINCT\n"
+ "yang_resource.module_name AS module_name,\n"
diff --git a/cps-ri/src/main/resources/changelog/changelog-master.yaml b/cps-ri/src/main/resources/changelog/changelog-master.yaml
index 43a54caf6..bf172d8ea 100644
--- a/cps-ri/src/main/resources/changelog/changelog-master.yaml
+++ b/cps-ri/src/main/resources/changelog/changelog-master.yaml
@@ -50,3 +50,5 @@ databaseChangeLog:
file: changelog/db/changes/16-insert-cm-handle-state.yaml
- include:
file: changelog/db/changes/17-add-index-to-schema-set-yang-resources.yaml
+ - include:
+ file: changelog/db/changes/18-cascade-delete-fragment-children.yaml
diff --git a/cps-ri/src/main/resources/changelog/db/changes/18-cascade-delete-fragment-children.yaml b/cps-ri/src/main/resources/changelog/db/changes/18-cascade-delete-fragment-children.yaml
new file mode 100644
index 000000000..62a9e2f63
--- /dev/null
+++ b/cps-ri/src/main/resources/changelog/db/changes/18-cascade-delete-fragment-children.yaml
@@ -0,0 +1,34 @@
+databaseChangeLog:
+ - changeSet:
+ author: cps
+ id: 18
+ changes:
+ - dropForeignKeyConstraint:
+ baseTableName: fragment
+ constraintName: fragment_parent_id_fkey
+ - addForeignKeyConstraint:
+ baseColumnNames: parent_id
+ baseTableName: fragment
+ constraintName: fragment_parent_id_fkey
+ deferrable: false
+ initiallyDeferred: false
+ onDelete: CASCADE
+ onUpdate: NO ACTION
+ referencedColumnNames: id
+ referencedTableName: fragment
+ validate: true
+ rollback:
+ - dropForeignKeyConstraint:
+ baseTableName: fragment
+ constraintName: fragment_parent_id_fkey
+ - addForeignKeyConstraint:
+ baseColumnNames: parent_id
+ baseTableName: fragment
+ constraintName: fragment_parent_id_fkey
+ deferrable: false
+ initiallyDeferred: false
+ onDelete: NO ACTION
+ onUpdate: NO ACTION
+ referencedColumnNames: id
+ referencedTableName: fragment
+ validate: true
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy
index 47027e463..bd39605de 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023 Nordix Foundation
+ * Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -53,6 +54,30 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase {
'the AND is used where result does not exist' | '//books[@lang="English" and @price=1000]' || 0 | []
}
+ def 'Cps Path query using combinations of OR operator #scenario.'() {
+ when: 'a query is executed to get response by the given cps path'
+ def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpspath, OMIT_DESCENDANTS)
+ then: 'the result contains expected number of nodes'
+ assert result.size() == expectedResultSize
+ and: 'the cps-path of queryDataNodes has the expectedLeaves'
+ assert result.leaves.sort() == expectedLeaves.sort()
+ println(expectedLeaves.toArray())
+ where: 'the following data is used'
+ scenario | cpspath || expectedResultSize | expectedLeaves
+ 'the "OR" condition' | '//books[@lang="English" or @price=15]' || 6 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]],
+ [lang: "English", price: 14, title: "The Light Fantastic", authors: ["Terry Pratchett"], editions: [1986]],
+ [lang: "English", price: 13, title: "Good Omens", authors: ["Terry Pratchett", "Neil Gaiman"], editions: [2006]],
+ [lang: "English", price: 12, title: "The Colour of Magic", authors: ["Terry Pratchett"], editions: [1983]],
+ [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]]]
+ 'the "OR" condition with non-json data' | '//books[@title="xyz" or @price=15]' || 2 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
+ 'combination of multiple AND' | '//books[@lang="English" and @price=15 and @edition=1983]' || 0 | []
+ 'combination of multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=1983]' || 3 | [[lang: "English", price: 15, title: "Annihilation", authors: ["Jeff VanderMeer"], editions: [2014]],
+ [lang: "English", price: 10, title: "Matilda", authors: ["Roald Dahl"], editions: [1988, 2000]],
+ [lang: "English", price: 15, title: "The Gruffalo", authors: ["Julia Donaldson"], editions: [1999]]]
+ }
+
def 'Cps Path query for leaf value(s) with #scenario.'() {
when: 'a query is executed to get a data node by the given cps path'
def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, fetchDescendantsOption)
@@ -129,12 +154,16 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase {
def bookTitles = result.collect { it.getLeaves().get('title') }
assert bookTitles.sort() == expectedBookTitles.sort()
where: 'the following data is used'
- scenario | cpsPath || expectedBookTitles
- 'one leaf' | '//books[@price=14]' || ['The Light Fantastic']
- 'one text' | '//books/authors[text()="Terry Pratchett"]' || ['Good Omens', 'The Colour of Magic', 'The Light Fantastic']
- 'more than one leaf' | '//books[@price=12 and @lang="English"]' || ['The Colour of Magic']
- 'leaves reversed in order' | '//books[@lang="English" and @price=12]' || ['The Colour of Magic']
- 'leaf and text' | '//books[@price=14]/authors[text()="Terry Pratchett"]' || ['The Light Fantastic']
+ scenario | cpsPath || expectedBookTitles
+ 'one leaf' | '//books[@price=14]' || ['The Light Fantastic']
+ 'one text' | '//books/authors[text()="Terry Pratchett"]' || ['Good Omens', 'The Colour of Magic', 'The Light Fantastic']
+ 'more than one leaf' | '//books[@price=12 and @lang="English"]' || ['The Colour of Magic']
+ 'more than one leaf has "OR" condition' | '//books[@lang="English" or @price=15]' || ['Annihilation', 'Good Omens', 'Matilda', 'The Colour of Magic', 'The Gruffalo', 'The Light Fantastic']
+ 'more than one leaf has "OR" condition with non-json data' | '//books[@title="xyz" or @price=13]' || ['Good Omens']
+ 'more than one leaf has multiple AND' | '//books[@lang="English" and @price=13 and @edition=1983]' || []
+ 'more than one leaf has multiple OR' | '//books[ @title="Matilda" or @price=15 or @edition=2006]' || ['Annihilation', 'Matilda', 'The Gruffalo']
+ 'leaves reversed in order' | '//books[@lang="English" and @price=12]' || ['The Colour of Magic']
+ 'leaf and text' | '//books[@price=14]/authors[text()="Terry Pratchett"]' || ['The Light Fantastic']
}
def 'Cps Path query using descendant anywhere with #scenario condition(s) for a list element.'() {
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsAdminServiceLimits.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsAdminServiceLimits.groovy
new file mode 100644
index 000000000..2c7c6ce35
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsAdminServiceLimits.groovy
@@ -0,0 +1,50 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 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.integration.performance.cps
+
+import org.onap.cps.integration.performance.base.CpsPerfTestBase
+import org.springframework.dao.DataAccessResourceFailureException
+
+class CpsAdminServiceLimits extends CpsPerfTestBase {
+
+ def objectUnderTest
+
+ def setup() { objectUnderTest = cpsAdminService }
+
+ def 'Get anchors from multiple schema set names limit exceeded: 32,766 (~ 2^15) schema set names.'() {
+ given: 'more than 32,766 schema set names'
+ def schemaSetNames = (0..32_766).collect { "size-of-this-name-does-not-matter-for-limit-" + it }
+ when: 'single get is executed to get all the anchors'
+ objectUnderTest.getAnchors(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetNames)
+ then: 'a database exception is thrown'
+ thrown(DataAccessResourceFailureException.class)
+ }
+
+ def 'Querying anchor names limit exceeded: 32,766 (~ 2^15) modules.'() {
+ given: 'more than 32,766 module names'
+ def moduleNames = (0..32_766).collect { "size-of-this-name-does-not-matter-for-limit-" + it }
+ when: 'single query is executed to get all the anchors'
+ objectUnderTest.queryAnchorNames(CPS_PERFORMANCE_TEST_DATASPACE, moduleNames)
+ then: 'a database exception is thrown'
+ thrown(DataAccessResourceFailureException.class)
+ }
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimits.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimits.groovy
new file mode 100644
index 000000000..1cb4ed800
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimits.groovy
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 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.integration.performance.cps
+
+import java.time.OffsetDateTime
+import org.onap.cps.integration.performance.base.CpsPerfTestBase
+import org.springframework.dao.DataAccessResourceFailureException
+import org.springframework.transaction.TransactionSystemException
+
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+
+class CpsDataServiceLimits extends CpsPerfTestBase {
+
+ def objectUnderTest
+
+ def setup() { objectUnderTest = cpsDataService }
+
+ def 'Multiple get limit exceeded: 32,764 (~ 2^15) xpaths.'() {
+ given: 'more than 32,764 xpaths'
+ def xpaths = (0..32_764).collect { "/size/of/this/path/does/not/matter/for/limit[@id='" + it + "']" }
+ when: 'single operation is executed to get all datanodes with given xpaths'
+ objectUnderTest.getDataNodesForMultipleXpaths(CPS_PERFORMANCE_TEST_DATASPACE, 'bookstore1', xpaths, INCLUDE_ALL_DESCENDANTS)
+ then: 'a database exception is thrown'
+ thrown(DataAccessResourceFailureException.class)
+ }
+
+ def 'Delete multiple datanodes limit exceeded: 32,767 (~ 2^15) xpaths.'() {
+ given: 'more than 32,767 xpaths'
+ def xpaths = (0..32_767).collect { "/size/of/this/path/does/not/matter/for/limit[@id='" + it + "']" }
+ when: 'single operation is executed to delete all datanodes with given xpaths'
+ objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, 'bookstore1', xpaths, OffsetDateTime.now())
+ then: 'a database exception is thrown'
+ thrown(TransactionSystemException.class)
+ }
+
+ def 'Delete datanodes from multiple anchors limit exceeded: 32,766 (~ 2^15) anchors.'() {
+ given: 'more than 32,766 anchor names'
+ def anchorNames = (0..32_766).collect { "size-of-this-name-does-not-matter-for-limit-" + it }
+ when: 'single operation is executed to delete all datanodes in given anchors'
+ objectUnderTest.deleteDataNodes(CPS_PERFORMANCE_TEST_DATASPACE, anchorNames, OffsetDateTime.now())
+ then: 'a database exception is thrown'
+ thrown(DataAccessResourceFailureException.class)
+ }
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
index 4edc1d72a..4676c908b 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy
@@ -21,7 +21,6 @@
package org.onap.cps.integration.performance.cps
import org.onap.cps.integration.performance.base.CpsPerfTestBase
-import org.springframework.dao.DataAccessResourceFailureException
import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
@@ -81,13 +80,4 @@ class GetPerfTest extends CpsPerfTestBase {
'openroadm top element' | 'openroadm' | '/openroadm-devices' || 1000 | 1 + 50 * 86
}
- def 'Multiple get limit exceeded: 32,764 (~ 2^15) xpaths.'() {
- given: 'more than 32,764 xpaths)'
- def xpaths = (0..32_764).collect { "/size/of/this/path/does/not/matter/for/limit[@id='" + it + "']" }
- when: 'single get is executed to get all the parent objects and their descendants'
- cpsDataService.getDataNodesForMultipleXpaths(CPS_PERFORMANCE_TEST_DATASPACE, 'bookstore1', xpaths, INCLUDE_ALL_DESCENDANTS)
- then: 'an exception is thrown'
- thrown(DataAccessResourceFailureException.class)
- }
-
}