aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorniamhcore <niamh.core@est.tech>2021-03-01 13:25:13 +0000
committerNiamh Core <niamh.core@est.tech>2021-03-02 11:13:25 +0000
commit32446dce35b5bf9d2c84751718cb4ece7f96fa72 (patch)
tree03a0fb6b16c6c6e692bc54db74440d005c501573
parent7c981df521c9d8eb6f340b2b118491eeeb21ae59 (diff)
CPS-265 - updating cps path to support include-descendants option.
Issue-ID: CPS-265 Signed-off-by: niamhcore <niamh.core@est.tech> Change-Id: I9e9b84760dbc8b5eb4b31ab972fdb2d186c6bb48
-rw-r--r--cps-nf-proxy-rest/docs/openapi/xnfProxy.yml1
-rw-r--r--cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java8
-rw-r--r--cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy27
-rw-r--r--cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/NfProxyDataService.java11
-rwxr-xr-xcps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/impl/NfProxyDataServiceImpl.java5
-rw-r--r--cps-nf-proxy-service/src/test/groovy/org/onap/cps/api/impl/NfProxyDataServiceImplSpec.groovy9
-rw-r--r--cps-rest/docs/api/swagger/cpsQuery.yml1
-rw-r--r--cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java7
-rw-r--r--cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy27
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java6
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy17
-rw-r--r--cps-ri/src/test/resources/data/fragment.sql3
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java5
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java5
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java4
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy12
-rwxr-xr-xdocs/api/swagger/openapi.yml7
17 files changed, 104 insertions, 51 deletions
diff --git a/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml b/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
index c39d2dff0..141e47258 100644
--- a/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
+++ b/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
@@ -33,6 +33,7 @@ nodesByCmHandleAndCpsPath:
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- $ref: 'components.yaml#/components/parameters/cpsPathInQuery'
+ - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery'
responses:
200:
$ref: 'components.yaml#/components/responses/Ok'
diff --git a/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java b/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
index 93ed06580..680ca127b 100644
--- a/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
+++ b/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
@@ -60,8 +60,12 @@ public class NfProxyController implements NfProxyApi {
}
@Override
- public ResponseEntity<Object> queryNodesByCmHandleAndCpsPath(final String cmHandle, @Valid final String cpsPath) {
- final Collection<DataNode> dataNodes = nfProxyDataService.queryDataNodes(cmHandle, cpsPath);
+ public ResponseEntity<Object> queryNodesByCmHandleAndCpsPath(final String cmHandle, @Valid final String cpsPath,
+ @Valid final Boolean includeDescendants) {
+ final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
+ ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
+ final Collection<DataNode> dataNodes =
+ nfProxyDataService.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption);
return new ResponseEntity<>(GSON.toJson(dataNodes), HttpStatus.OK);
}
diff --git a/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy b/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
index 742a643fa..a81411caf 100644
--- a/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
+++ b/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
@@ -21,10 +21,9 @@
package org.onap.cps.nfproxy.rest.controller
-import com.google.common.collect.ImmutableMap
+
import com.google.gson.Gson
import org.onap.cps.nfproxy.api.NfProxyDataService
-import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
@@ -34,7 +33,9 @@ import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification
+import spock.lang.Unroll
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
@@ -59,22 +60,28 @@ class NfProxyControllerSpec extends Specification {
def cmHandle = 'some handle'
def xpath = 'some xpath'
- def 'Query data node by cps path for the given cm handle.'() {
+ @Unroll
+ def 'Query data node by cps path for the given cm handle with #scenario.'() {
given: 'service method returns a list containing a data node'
- def cpsPath = '/xpath/leaves[@leaf=\'value\']'
- def dataNode = new DataNodeBuilder().withXpath("/xpath")
- .withLeaves(ImmutableMap.of("leaf", "value")).build()
- ArrayList<DataNode> dataNodeList = new ArrayList();
- dataNodeList.add(dataNode)
- mockNfProxyDataService.queryDataNodes(cmHandle, cpsPath) >> dataNodeList
+ def dataNode = new DataNodeBuilder().withXpath('/xpath').build()
+ def cpsPath = 'some cps-path'
+ mockNfProxyDataService.queryDataNodes(cmHandle, cpsPath, expectedCpsDataServiceOption) >> [dataNode]
and: 'the query endpoint'
def dataNodeEndpoint = "$dataNodeBaseEndpoint/cm-handles/$cmHandle/nodes/query"
when: 'query data nodes API is invoked'
- def response = mvc.perform(get(dataNodeEndpoint).param('cps-path', cpsPath)).andReturn().response
+ def response = mvc.perform(get(dataNodeEndpoint)
+ .param('cps-path', cpsPath)
+ .param('include-descendants', includeDescendantsOption))
+ .andReturn().response
then: 'the response contains the the datanode in json format'
response.status == HttpStatus.OK.value()
def expectedJsonContent = new Gson().toJson(dataNode)
response.getContentAsString().contains(expectedJsonContent)
+ where: 'the following options for include descendants are provided in the request'
+ scenario | includeDescendantsOption || expectedCpsDataServiceOption
+ 'no descendants by default'| '' || OMIT_DESCENDANTS
+ 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS
+ 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS
}
def 'Update data node leaves.'() {
diff --git a/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/NfProxyDataService.java b/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/NfProxyDataService.java
index ce47d7001..cde1801da 100644
--- a/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/NfProxyDataService.java
+++ b/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/NfProxyDataService.java
@@ -46,12 +46,15 @@ public interface NfProxyDataService {
/**
* Get datanodes for the given cm handle by cps path.
*
- * @param cmHandle The identifier for a network function, network element, subnetwork or any other cm object by
- * managed NF-Proxy
- * @param cpsPath cps path
+ * @param cmHandle The identifier for a network function, network element, subnetwork or any other cm
+ * object by managed NF-Proxy
+ * @param cpsPath cps path
+ * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be
+ * included in the output
* @return a collection of datanodes
*/
- Collection<DataNode> queryDataNodes(@NonNull String cmHandle, @NonNull String cpsPath);
+ Collection<DataNode> queryDataNodes(@NonNull String cmHandle, @NonNull String cpsPath,
+ @NonNull FetchDescendantsOption fetchDescendantsOption);
/**
* Updates data node for given cm handle using xpath to parent node.
diff --git a/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/impl/NfProxyDataServiceImpl.java b/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/impl/NfProxyDataServiceImpl.java
index bb15591a9..cff92fea6 100755
--- a/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/impl/NfProxyDataServiceImpl.java
+++ b/cps-nf-proxy-service/src/main/java/org/onap/cps/nfproxy/api/impl/NfProxyDataServiceImpl.java
@@ -47,8 +47,9 @@ public class NfProxyDataServiceImpl implements NfProxyDataService {
}
@Override
- public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath) {
- return cpsQueryService.queryDataNodes(NF_PROXY_DATASPACE_NAME, cmHandle, cpsPath);
+ public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ return cpsQueryService.queryDataNodes(NF_PROXY_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption);
}
@Override
diff --git a/cps-nf-proxy-service/src/test/groovy/org/onap/cps/api/impl/NfProxyDataServiceImplSpec.groovy b/cps-nf-proxy-service/src/test/groovy/org/onap/cps/api/impl/NfProxyDataServiceImplSpec.groovy
index f89f80e30..24549aec8 100644
--- a/cps-nf-proxy-service/src/test/groovy/org/onap/cps/api/impl/NfProxyDataServiceImplSpec.groovy
+++ b/cps-nf-proxy-service/src/test/groovy/org/onap/cps/api/impl/NfProxyDataServiceImplSpec.groovy
@@ -22,6 +22,7 @@ package org.onap.cps.api.impl
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsQueryService
import org.onap.cps.nfproxy.api.impl.NfProxyDataServiceImpl
+import org.onap.cps.spi.FetchDescendantsOption
import spock.lang.Specification
class NfProxyDataServiceImplSpec extends Specification {
@@ -37,13 +38,15 @@ class NfProxyDataServiceImplSpec extends Specification {
def cmHandle = 'some handle'
def expectedDataspaceName = 'NFP-Operational'
- def 'Query data nodes by cps path.'() {
+ def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
given: 'a cm Handle and a cps path'
def cpsPath = '/cps-path'
when: 'queryDataNodes is invoked'
- objectUnderTest.queryDataNodes(cmHandle, cpsPath)
+ objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
then: 'the persistence service is called once with the correct parameters'
- 1 * mockcpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath)
+ 1 * mockcpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
}
def 'Update data node leaves.'() {
diff --git a/cps-rest/docs/api/swagger/cpsQuery.yml b/cps-rest/docs/api/swagger/cpsQuery.yml
index 91a4bdbfa..779c9a094 100644
--- a/cps-rest/docs/api/swagger/cpsQuery.yml
+++ b/cps-rest/docs/api/swagger/cpsQuery.yml
@@ -9,6 +9,7 @@ nodesByDataspaceAndAnchorAndCpsPath:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/cpsPathInQuery'
+ - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery'
responses:
'200':
$ref: 'components.yml#/components/responses/Ok'
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
index a8816f02b..c6b5284fb 100644
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
@@ -24,6 +24,7 @@ import java.util.Collection;
import javax.validation.Valid;
import org.onap.cps.api.CpsQueryService;
import org.onap.cps.rest.api.CpsQueryApi;
+import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@@ -40,9 +41,11 @@ public class QueryRestController implements CpsQueryApi {
@Override
public ResponseEntity<Object> getNodesByDataspaceAndAnchorAndCpsPath(final String dataspaceName,
- final String anchorName, @Valid final String cpsPath) {
+ final String anchorName, @Valid final String cpsPath, @Valid final Boolean includeDescendants) {
+ final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
+ ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
final Collection<DataNode> dataNodes =
- cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath);
+ cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption);
return new ResponseEntity<>(new Gson().toJson(dataNodes), HttpStatus.OK);
}
}
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
index 4d9a558ef..0927c9d1e 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
@@ -19,7 +19,7 @@
package org.onap.cps.rest.controller
-import com.google.common.collect.ImmutableMap
+
import com.google.gson.Gson
import org.modelmapper.ModelMapper
import org.onap.cps.api.CpsAdminService
@@ -36,7 +36,10 @@ import org.springframework.http.HttpStatus
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Shared
import spock.lang.Specification
+import spock.lang.Unroll
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
@WebMvcTest
@@ -63,22 +66,28 @@ class QueryRestControllerSpec extends Specification {
@Value('${rest.api.cps-base-path}')
def basePath
- def 'Query data node by cps path for the given dataspace and anchor.'() {
+ @Unroll
+ def 'Query data node by cps path for the given dataspace and anchor with #scenario.'() {
given: 'service method returns a list containing a data node'
+ def dataNode = new DataNodeBuilder().withXpath('/xpath').build()
def dataspaceName = 'my_dataspace'
def anchorName = 'my_anchor'
- def cpsPath = '/xpath/leaves[@leaf=\'value\']'
- def dataNode = new DataNodeBuilder().withXpath("/xpath")
- .withLeaves(ImmutableMap.of("leaf", "value")).build()
- ArrayList<DataNode> dataNodeList = new ArrayList();
- dataNodeList.add(dataNode)
- mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath) >> dataNodeList
+ def cpsPath = 'some cps-path'
+ mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, expectedCpsDataServiceOption) >> [dataNode]
and: 'the query endpoint'
def dataNodeEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query"
when: 'query data nodes API is invoked'
- def response = mvc.perform(get(dataNodeEndpoint).param('cps-path', cpsPath)).andReturn().response
+ def response = mvc.perform(get(dataNodeEndpoint)
+ .param('cps-path', cpsPath)
+ .param('include-descendants', includeDescendantsOption))
+ .andReturn().response
then: 'the response contains the the datanode in json format'
response.status == HttpStatus.OK.value()
response.getContentAsString().contains(new Gson().toJson(dataNode))
+ where: 'the following options for include descendants are provided in the request'
+ scenario | includeDescendantsOption || expectedCpsDataServiceOption
+ 'no descendants by default' | '' || OMIT_DESCENDANTS
+ 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS
+ 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS
}
} \ No newline at end of file
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
index 2d9588e8f..0c61c9909 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
@@ -21,7 +21,6 @@
package org.onap.cps.spi.impl;
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
@@ -127,7 +126,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
@Override
- public List<DataNode> queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath) {
+ public List<DataNode> queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath,
+ final FetchDescendantsOption fetchDescendantsOption) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
final CpsPathQuery cpsPathQuery = CpsPathQuery.createFrom(cpsPath);
@@ -135,7 +135,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
.getByAnchorAndXpathAndLeafAttributes(anchorEntity.getId(), cpsPathQuery
.getXpathPrefix(), cpsPathQuery.getLeafName(), cpsPathQuery.getLeafValue());
return fragmentEntities.stream()
- .map(fragmentEntity -> toDataNode(fragmentEntity, OMIT_DESCENDANTS))
+ .map(fragmentEntity -> toDataNode(fragmentEntity, fetchDescendantsOption))
.collect(Collectors.toUnmodifiableList());
}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
index 015893817..8001c659f 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableSet
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.entities.FragmentEntity
import org.onap.cps.spi.exceptions.AnchorNotFoundException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
@@ -309,28 +310,28 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase {
@Sql([CLEAR_DATA, SET_DATA])
def 'Cps Path query for single leaf value with type: #type.'() {
when: 'a query is executed to get a data node by the given cps path'
- def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, cpsPath)
+ def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, cpsPath, includeDescendantsOption)
then: 'the correct data is returned'
def leaves ='[common-leaf-name:common-leaf-value, common-leaf-name-int:5.0]'
- result.size() == 1
- def dataNode = result.stream().findFirst().get()
+ DataNode dataNode = result.stream().findFirst().get()
dataNode.getLeaves().toString() == leaves
+ dataNode.getChildDataNodes().size() == expectedNumberOfChidlNodes
where: 'the following data is used'
- type | cpsPath
- 'String' | '/parent-200/child-202[@common-leaf-name=\'common-leaf-value\']'
- 'Integer' | '/parent-200/child-202[@common-leaf-name-int=5]'
+ type | cpsPath | includeDescendantsOption | expectedNumberOfChidlNodes
+ 'String and no descendants' | '/parent-200/child-202[@common-leaf-name=\'common-leaf-value\']' | OMIT_DESCENDANTS | 0
+ 'Integer and descendants' | '/parent-200/child-202[@common-leaf-name-int=5]' | INCLUDE_ALL_DESCENDANTS | 1
}
@Unroll
@Sql([CLEAR_DATA, SET_DATA])
def 'Query for attribute by cps path with cps paths that return no data because of #scenario.'() {
when: 'a query is executed to get datanodes for the given cps path'
- def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, cpsPath)
+ def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES, cpsPath, FetchDescendantsOption.OMIT_DESCENDANTS)
then: 'no data is returned'
result.isEmpty()
where: 'following cps queries are performed'
scenario | cpsPath
- 'cps path is incomplete' | '/parent-200[@common-leaf-name-int=5]'
+ 'cps path is incomplete' | '/parent-200[@common-leaf-name-int=5]'
'missing / at beginning of path' | 'parent-200/child-202[@common-leaf-name-int=5]'
'leaf value does not exist' | '/parent-200/child-202[@common-leaf-name=\'does not exist\']'
'incomplete end of xpath prefix' | '/parent-200/child-20[@common-leaf-name-int=5]'
diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql
index 4b5057807..3c1f793b9 100644
--- a/cps-ri/src/test/resources/data/fragment.sql
+++ b/cps-ri/src/test/resources/data/fragment.sql
@@ -26,4 +26,5 @@ INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES)
(4201, 1001, 3003, null, '/parent-200', '{"leaf-value": "original"}'),
(4202, 1001, 3003, 4201, '/parent-200/child-201', '{"leaf-value": "original"}'),
(4203, 1001, 3003, 4202, '/parent-200/child-201/grand-child', '{"leaf-value": "original"}'),
- (4204, 1001, 3003, 4201, '/parent-200/child-202', '{"common-leaf-name": "common-leaf-value", "common-leaf-name-int" : 5}'); \ No newline at end of file
+ (4204, 1001, 3003, 4201, '/parent-200/child-202', '{"common-leaf-name": "common-leaf-value", "common-leaf-name-int" : 5}'),
+ (4205, 1001, 3003, 4204, '/parent-200/child-202/grand-child-202', '{"common-leaf-name": "common-leaf-value", "common-leaf-name-int" : 5}'); \ No newline at end of file
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java
index b432af800..0f4bf2dc4 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java
@@ -21,6 +21,7 @@ package org.onap.cps.api;
import java.util.Collection;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
/*
@@ -34,9 +35,11 @@ public interface CpsQueryService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param cpsPath cps path
+ * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be
+ * included in the output
* @return a collection of data nodes
*/
Collection<DataNode> queryDataNodes(@NonNull String dataspaceName, @NonNull String anchorName,
- @NonNull String cpsPath);
+ @NonNull String cpsPath, @NonNull FetchDescendantsOption fetchDescendantsOption);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
index 63d0a0fbb..79fa6c717 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
@@ -22,6 +22,7 @@ package org.onap.cps.api.impl;
import java.util.Collection;
import org.onap.cps.api.CpsQueryService;
import org.onap.cps.spi.CpsDataPersistenceService;
+import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -34,7 +35,7 @@ public class CpsQueryServiceImpl implements CpsQueryService {
@Override
public Collection<DataNode> queryDataNodes(final String dataspaceName, final String anchorName,
- final String cpsPath) {
- return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath);
+ final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) {
+ return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption);
}
} \ No newline at end of file
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
index d2b6d45d6..48f9763ee 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java
@@ -94,8 +94,10 @@ public interface CpsDataPersistenceService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param cpsPath cps path
+ * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be
+ * included in the output
* @return the data nodes found i.e. 0 or more data nodes
*/
Collection<DataNode> queryDataNodes(@NonNull String dataspaceName, @NonNull String anchorName,
- @NonNull String cpsPath);
+ @NonNull String cpsPath, @NonNull FetchDescendantsOption fetchDescendantsOption);
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
index 6e044b044..99d25ecfc 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
@@ -20,7 +20,10 @@
package org.onap.cps.api.impl
import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.FetchDescendantsOption
import spock.lang.Specification
+import spock.lang.Unroll
+
class CpsQueryServiceImplSpec extends Specification {
def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
@@ -31,14 +34,17 @@ class CpsQueryServiceImplSpec extends Specification {
objectUnderTest.cpsDataPersistenceService = mockCpsDataPersistenceService
}
- def 'Query data nodes by cps path.'() {
+ @Unroll
+ def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
given: 'a dataspace name, an anchor name and a cps path'
def dataspaceName = 'some dataspace'
def anchorName = 'some anchor'
def cpsPath = '/cps-path'
when: 'queryDataNodes is invoked'
- objectUnderTest.queryDataNodes(dataspaceName, anchorName, cpsPath)
+ objectUnderTest.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption)
then: 'the persistence service is called once with the correct parameters'
- 1 * mockCpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath)
+ 1 * mockCpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption)
+ where: 'all fetch descendants options are supported'
+ fetchDescendantsOption << FetchDescendantsOption.values()
}
} \ No newline at end of file
diff --git a/docs/api/swagger/openapi.yml b/docs/api/swagger/openapi.yml
index f827e4585..d158561be 100755
--- a/docs/api/swagger/openapi.yml
+++ b/docs/api/swagger/openapi.yml
@@ -764,6 +764,13 @@ paths:
schema:
type: string
default: /
+ - name: include-descendants
+ in: query
+ description: include-descendants
+ required: false
+ schema:
+ type: boolean
+ default: false
responses:
'200':
description: OK