Add tests of attribute-axis feature 88/139588/3
authordanielhanrahan <daniel.hanrahan@est.tech>
Mon, 2 Dec 2024 14:49:10 +0000 (14:49 +0000)
committerdanielhanrahan <daniel.hanrahan@est.tech>
Tue, 3 Dec 2024 15:49:03 +0000 (15:49 +0000)
Following TDD, functional acceptance tests are added for
attribute-axis feature. This covers xpaths such as '//books/@title'

- Add stub to CpsQueryService throwing UnsupportedOperationException
- Add tests showing expected behaviour (tests currently ignored)
- Implementation will be provided in following commmit for CPS-2416

Issue-ID: CPS-2416
Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech>
Change-Id: I71817e66b28dfc21e7b75243fd0135f3cceddb8e

cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy

index edd2d2a..34dcbb9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2022 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +22,7 @@
 package org.onap.cps.api;
 
 import java.util.Collection;
+import java.util.Set;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.PaginationOption;
 import org.onap.cps.spi.model.DataNode;
@@ -44,6 +45,18 @@ public interface CpsQueryService {
     Collection<DataNode> queryDataNodes(String dataspaceName, String anchorName,
                                         String cpsPath, FetchDescendantsOption fetchDescendantsOption);
 
+
+    /**
+     * Get data leaf for the given dataspace and anchor by cps path.
+     *
+     * @param dataspaceName          dataspace name
+     * @param anchorName             anchor name
+     * @param cpsPath                cps path
+     * @param targetClass            class of the expected data type
+     * @return a collection of data objects of expected type
+     */
+    <T> Set<T> queryDataLeaf(String dataspaceName, String anchorName, String cpsPath, Class<T> targetClass);
+
     /**
      * Get data nodes for the given dataspace across all anchors by cps path.
      *
index d1c9898..1de7c17 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +23,7 @@ package org.onap.cps.api.impl;
 
 import io.micrometer.core.annotation.Timed;
 import java.util.Collection;
+import java.util.Set;
 import lombok.RequiredArgsConstructor;
 import org.onap.cps.api.CpsQueryService;
 import org.onap.cps.impl.utils.CpsValidator;
@@ -43,15 +44,23 @@ public class CpsQueryServiceImpl implements CpsQueryService {
     @Timed(value = "cps.data.service.datanode.query",
             description = "Time taken to query data nodes")
     public Collection<DataNode> queryDataNodes(final String dataspaceName, final String anchorName,
-        final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) {
+                                               final String cpsPath,
+                                               final FetchDescendantsOption fetchDescendantsOption) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
         return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption);
     }
 
     @Override
-    public Collection<DataNode> queryDataNodesAcrossAnchors(final String dataspaceName,
-        final String cpsPath, final FetchDescendantsOption fetchDescendantsOption,
-        final PaginationOption paginationOption) {
+    public <T> Set<T> queryDataLeaf(final String dataspaceName, final String anchorName, final String cpsPath,
+                                    final Class<T> targetClass) {
+        cpsValidator.validateNameCharacters(dataspaceName, anchorName);
+        throw new UnsupportedOperationException("Query by attribute-axis not implemented yet!");
+    }
+
+    @Override
+    public Collection<DataNode> queryDataNodesAcrossAnchors(final String dataspaceName, final String cpsPath,
+                                                            final FetchDescendantsOption fetchDescendantsOption,
+                                                            final PaginationOption paginationOption) {
         cpsValidator.validateNameCharacters(dataspaceName);
         cpsValidator.validatePaginationOption(paginationOption);
         return cpsDataPersistenceService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath,
index 3b10669..74127e0 100644 (file)
@@ -71,4 +71,12 @@ class CpsQueryServiceImplSpec extends Specification {
         then: 'the persistence service is called once with the correct parameters'
             1 * mockCpsDataPersistenceService.countAnchorsForDataspaceAndCpsPath("some-dataspace", "/cps-path")
     }
+
+    // TODO will be implemented in CPS-2416
+    def 'Query data leaf.'() {
+        when: 'a query for a specific leaf is executed'
+            objectUnderTest.queryDataLeaf('some-dataspace', 'some-anchor', '/cps-path/@id', Object.class)
+        then: 'solution is not implemented yet'
+            thrown(UnsupportedOperationException)
+    }
 }
index 3b49cfc..23e41c4 100644 (file)
@@ -27,6 +27,7 @@ import org.onap.cps.integration.base.FunctionalSpecBase
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.PaginationOption
 import org.onap.cps.spi.exceptions.CpsPathException
+import spock.lang.Ignore
 
 import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
@@ -56,6 +57,44 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase {
             'the AND is used where result does not exist' | '//books[@lang="English" and @price=1000]' || 0                  | []
     }
 
+    @Ignore  // TODO will be implemented in CPS-2416
+    def 'Query data leaf using CPS path for #scenario.'() {
+        when: 'query data leaf for bookstore container'
+            def result = objectUnderTest.queryDataLeaf(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, Object.class)
+        then: 'the result contains the expected number of leaf values'
+            assert result.size() == expectedUniqueBooksTitles
+        where:
+            scenario                  | cpsPath                                       || expectedUniqueBooksTitles
+            'all books'               | '//books/@title'                              || 19
+            'all books in a category' | '/bookstore/categories[@code=5]/books/@title' || 10
+            'non-existing path'       | '/non-existing/@title'                        || 0
+    }
+
+    @Ignore
+    def 'Query data leaf with type #leafType using CPS path.'() {
+        given: 'a cps path query for two books, returning only #leafName'
+            def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/@' + leafName
+        when: 'query data leaf for bookstore container'
+            def results = objectUnderTest.queryDataLeaf(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, leafType)
+        then: 'the result contains the expected leaf values'
+            assert results == expectedResults as Set
+        where:
+            leafName    | leafType      || expectedResults
+            'lang'      | String.class  || ['English']
+            'price'     | Number.class  || [13, 20]
+            'editions'  | List.class    || [[1988, 2000], [2006]]
+    }
+
+    @Ignore
+    def 'Query data leaf using CPS path with ancestor axis.'() {
+        given: 'a cps path query that will return the names of the categories of two books'
+            def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/ancestor::categories/@name'
+        when: 'query data leaf for bookstore container'
+            def result = objectUnderTest.queryDataLeaf(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, String.class)
+        then: 'the result contains the expected leaf values'
+            assert result == ['Children', 'Comedy'] as Set
+    }
+
     def 'Cps Path query using comparative and boolean operators.'() {
         given: 'a cps path query in the discount category'
             def cpsPath = "/bookstore/categories[@code='5']/books" + leafCondition