Merge "[CPS] Re-structuring the packages for better understanding"
authorToine Siebelink <toine.siebelink@est.tech>
Mon, 17 Apr 2023 09:36:00 +0000 (09:36 +0000)
committerGerrit Code Review <gerrit@onap.org>
Mon, 17 Apr 2023 09:36:00 +0000 (09:36 +0000)
19 files changed:
cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBooleanOperatorType.java [new file with mode: 0644]
cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
cps-ri/pom.xml
cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
cps-ri/src/main/resources/changelog/changelog-master.yaml
cps-ri/src/main/resources/changelog/db/changes/18-cascade-delete-fragment-children.yaml [new file with mode: 0644]
integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsAdminServiceLimits.groovy [new file with mode: 0644]
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataServiceLimits.groovy [new file with mode: 0644]
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/GetPerfTest.groovy

index db09b3c..d471811 100644 (file)
@@ -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 (file)
index 0000000..b2f1ddd
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+ *  ============LICENSE_START=======================================================\r
+ *  Copyright (C) 2023 TechMahindra Ltd\r
+ *  ================================================================================\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ *\r
+ *  SPDX-License-Identifier: Apache-2.0\r
+ *  ============LICENSE_END=========================================================\r
+ */\r
+\r
+package org.onap.cps.cpspath.parser;\r
+\r
+public enum CpsPathBooleanOperatorType {\r
+    AND("and"),\r
+    OR("or");\r
+\r
+    private final String operatorValue;\r
+\r
+    CpsPathBooleanOperatorType(final String operatorValue) {\r
+        this.operatorValue = operatorValue;\r
+    }\r
+\r
+    public String getValues() {\r
+        return this.operatorValue;\r
+    }\r
+\r
+    /**\r
+     * Finds the value of the given enumeration.\r
+     *\r
+     * @param operatorValue value of the enum\r
+     * @return a booleanOperatorType\r
+     */\r
+    public static CpsPathBooleanOperatorType fromString(final String operatorValue) {\r
+        for (final CpsPathBooleanOperatorType booleanOperatorType : CpsPathBooleanOperatorType.values()) {\r
+            if (booleanOperatorType.operatorValue.equalsIgnoreCase(operatorValue)) {\r
+                return booleanOperatorType;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+}\r
index 3a9d70e..4299d13 100644 (file)
@@ -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,12 +97,22 @@ 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);
@@ -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("'");
     }
 }
index 3985455..2c96d91 100644 (file)
@@ -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.
index b837a64..153dfbe 100644 (file)
@@ -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.'() {
index e9b2abb..7ce24d9 100644 (file)
@@ -33,7 +33,7 @@
     <artifactId>cps-ri</artifactId>\r
 \r
     <properties>\r
-        <minimum-coverage>0.82</minimum-coverage>\r
+        <minimum-coverage>0.80</minimum-coverage>\r
     </properties>\r
 \r
     <dependencies>\r
index 46b0fec..f7b586d 100755 (executable)
@@ -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);
 }
index 10c6541..b1ce127 100755 (executable)
@@ -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));
     }
 }
index 13320bf..bad68f7 100644 (file)
@@ -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.
index 5c5458a..04b7080 100644 (file)
@@ -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;
-    }
-
 }
index c231595..ca6e18b 100644 (file)
 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);
index 98d4420..3263f34 100644 (file)
@@ -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);
 }
index 6ca4fff..fff0a6a 100644 (file)
@@ -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"
index 43a54ca..bf172d8 100644 (file)
@@ -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 (file)
index 0000000..62a9e2f
--- /dev/null
@@ -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
index 47027e4..bd39605 100644 (file)
@@ -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 (file)
index 0000000..2c7c6ce
--- /dev/null
@@ -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 (file)
index 0000000..1cb4ed8
--- /dev/null
@@ -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)
+    }
+
+}
index 4edc1d7..4676c90 100644 (file)
@@ -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)
-    }
-
 }