aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRishi.Chail <rishi.chail@est.tech>2021-04-14 00:51:44 +0100
committerRishi.Chail <rishi.chail@est.tech>2021-04-26 12:58:17 +0100
commit2b7d23c2ffa067732df1ecc3879d252646dad2da (patch)
treed8ef8bcb618aeb10d2917afd49af0f6d7f0d7cd6
parent964fc0f1f9a19e64aa45c3f3469a8f4d5079724c (diff)
Get Data under anchor using single root
Issue-ID: CPS-325 Signed-off-by: Rishi.Chail <rishi.chail@est.tech> Change-Id: Id8da3d767199c5767c625b55d175ac6791dcca48
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java7
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy2
-rwxr-xr-x[-rw-r--r--]cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java11
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java9
-rwxr-xr-x[-rw-r--r--]cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy20
-rwxr-xr-x[-rw-r--r--]cps-ri/src/test/resources/data/fragment.sql14
-rwxr-xr-x[-rw-r--r--]cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java11
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy8
8 files changed, 62 insertions, 20 deletions
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index 3385f35fe8..ddd3ac48ec 100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -60,13 +60,10 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> getNodeByDataspaceAndAnchor(final String dataspaceName, final String anchorName,
final String xpath, final Boolean includeDescendants) {
- if (isRootXpath(xpath)) {
- return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
- }
final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
- final DataNode dataNode =
- cpsDataService.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption);
+ final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath,
+ fetchDescendantsOption);
return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK);
}
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
index 713dda1403..299299ce28 100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -191,7 +191,7 @@ class DataRestControllerSpec extends Specification {
'no dataspace' | '/x-path' | new DataspaceNotFoundException('') || HttpStatus.BAD_REQUEST
'no anchor' | '/x-path' | new AnchorNotFoundException('', '') || HttpStatus.BAD_REQUEST
'no data' | '/x-path' | new DataNodeNotFoundException('', '', '') || HttpStatus.NOT_FOUND
- 'empty path' | '' | new IllegalStateException() || HttpStatus.NOT_IMPLEMENTED
+ 'root path' | '/' | new DataNodeNotFoundException('', '') || HttpStatus.NOT_FOUND
'already defined' | '/x-path' | new AlreadyDefinedException('', new Throwable()) || HttpStatus.CONFLICT
}
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 fa13c7d14d..a02b193d9e 100644..100755
--- 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
@@ -130,7 +130,12 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
final String xpath) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
- return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, xpath);
+ if (isRootXpath(xpath)) {
+ return fragmentRepository.getFirstByDataspaceAndAnchor(dataspaceEntity, anchorEntity);
+ } else {
+ return fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity,
+ xpath);
+ }
}
@Override
@@ -205,4 +210,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
fragmentEntity.setChildFragments(Collections.emptySet());
fragmentRepository.save(fragmentEntity);
}
+
+ private boolean isRootXpath(final String xpath) {
+ return "/".equals(xpath) || "".equals(xpath);
+ }
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java
index b896fe86d0..74d04613d9 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java
@@ -48,6 +48,15 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>
.orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName(), xpath));
}
+ Optional<FragmentEntity> findFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity,
+ @NonNull AnchorEntity anchorEntity);
+
+ default FragmentEntity getFirstByDataspaceAndAnchor(@NonNull DataspaceEntity dataspaceEntity,
+ @NonNull AnchorEntity anchorEntity) {
+ return findFirstByDataspaceAndAnchor(dataspaceEntity, anchorEntity)
+ .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName()));
+ }
+
@Modifying
@Query("DELETE FROM FragmentEntity fe WHERE fe.anchor IN (:anchors)")
void deleteByAnchorIn(@NotNull @Param("anchors") Collection<AnchorEntity> anchorEntities);
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 a47bd65d02..ea6b26923a 100644..100755
--- 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
@@ -167,23 +167,30 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase {
return fragmentRepository.findByDataspaceAndAnchorAndXpath(dataspace, anchor, xpath).orElseThrow()
}
+ @Unroll
@Sql([CLEAR_DATA, SET_DATA])
def 'Get data node by xpath without descendants.'() {
when: 'data node is requested'
def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES,
- XPATH_DATA_NODE_WITH_LEAVES, OMIT_DESCENDANTS)
+ inputXPath, OMIT_DESCENDANTS)
then: 'data node is returned with no descendants'
assert result.getXpath() == XPATH_DATA_NODE_WITH_LEAVES
and: 'expected leaves'
assert result.getChildDataNodes().size() == 0
assertLeavesMaps(result.getLeaves(), expectedLeavesByXpathMap[XPATH_DATA_NODE_WITH_LEAVES])
+ where: 'the following data is used'
+ scenario | inputXPath
+ 'some xpath' |'/parent-100'
+ 'root xpath' |'/'
+ 'empty xpath' |''
}
+ @Unroll
@Sql([CLEAR_DATA, SET_DATA])
def 'Get data node by xpath with all descendants.'() {
when: 'data node is requested with all descendants'
def result = objectUnderTest.getDataNode(DATASPACE_NAME, ANCHOR_FOR_DATA_NODES_WITH_LEAVES,
- XPATH_DATA_NODE_WITH_LEAVES, INCLUDE_ALL_DESCENDANTS)
+ inputXPath, INCLUDE_ALL_DESCENDANTS)
def mappedResult = treeToFlatMapByXpath(new HashMap<>(), result)
then: 'data node is returned with all the descendants populated'
assert mappedResult.size() == 4
@@ -192,9 +199,12 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase {
assert mappedResult.get('/parent-100/child-002').getChildDataNodes().size() == 1
and: 'extracted leaves maps are matching expected'
mappedResult.forEach(
- (xpath, dataNode) ->
- assertLeavesMaps(dataNode.getLeaves(), expectedLeavesByXpathMap[xpath])
- )
+ (inputXPath, dataNode) -> assertLeavesMaps(dataNode.getLeaves(), expectedLeavesByXpathMap[inputXPath]))
+ where: 'the following data is used'
+ scenario | inputXPath
+ 'some xpath' |'/parent-100'
+ 'root xpath' |'/'
+ 'empty xpath' |''
}
def static assertLeavesMaps(actualLeavesMap, expectedLeavesMap) {
diff --git a/cps-ri/src/test/resources/data/fragment.sql b/cps-ri/src/test/resources/data/fragment.sql
index b6dc2ca307..d252fbbb59 100644..100755
--- a/cps-ri/src/test/resources/data/fragment.sql
+++ b/cps-ri/src/test/resources/data/fragment.sql
@@ -8,13 +8,13 @@ INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(3001, 'ANCHOR-001', 1001, 2001),
(3003, 'ANCHOR-003', 1001, 2001);
-INSERT INTO FRAGMENT (ID, XPATH, ANCHOR_ID, PARENT_ID, DATASPACE_ID) VALUES
- (4001, '/parent-1', 3001, null, 1001),
- (4002, '/parent-2', 3001, null, 1001),
- (4003, '/parent-3', 3001, null, 1001),
- (4004, '/parent-1/child-1', 3001, 4001, 1001),
- (4005, '/parent-2/child-2', 3001, 4002, 1001),
- (4006, '/parent-1/child-1/grandchild-1', 3001, 4004, 1001);
+INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH) VALUES
+ (4001, 1001, 3001, null, '/parent-1'),
+ (4002, 1001, 3001, null, '/parent-2'),
+ (4003, 1001, 3001, null, '/parent-3'),
+ (4004, 1001, 3001, 4001, '/parent-1/child-1'),
+ (4005, 1001, 3001, 4002, '/parent-2/child-2'),
+ (4006, 1001, 3001, 4004, '/parent-1/child-1/grandchild-1');
INSERT INTO FRAGMENT (ID, DATASPACE_ID, ANCHOR_ID, PARENT_ID, XPATH, ATTRIBUTES) VALUES
(4101, 1001, 3003, null, '/parent-100', '{"parent-leaf": "parent-leaf value"}'),
diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java
index 125b93d70a..6e7ac3b897 100644..100755
--- a/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataNodeNotFoundException.java
@@ -39,4 +39,15 @@ public class DataNodeNotFoundException extends DataValidationException {
.format("DataNode with xpath %s was not found for anchor %s and dataspace %s.", xpath,
anchorName, dataspaceName));
}
+
+ /**
+ * Constructor.
+ *
+ * @param dataspaceName the name of the dataspace
+ * @param anchorName the anchor name
+ */
+ public DataNodeNotFoundException(final String dataspaceName, final String anchorName) {
+ super("DataNode not found", String.format(
+ "DataNode not found for anchor %s and dataspace %s.", anchorName, dataspaceName));
+ }
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy
index d2f43c9362..8592af908d 100755
--- a/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy
@@ -119,12 +119,18 @@ class CpsExceptionsSpec extends Specification {
+ "Anchor records associated.")
}
- def 'Creating a exception that a datanode does not exist.'() {
+ def 'Creating a exception that a datanode with a specified xpath does not exist.'() {
expect: 'the exception details contains the correct message with dataspace name and xpath.'
(new DataNodeNotFoundException(dataspaceName, anchorName, xpath)).details
== "DataNode with xpath ${xpath} was not found for anchor ${anchorName} and dataspace ${dataspaceName}."
}
+ def 'Creating a exception that a datanode does not exist.'() {
+ expect: 'the exception details contains the correct message with dataspace name and anchor.'
+ (new DataNodeNotFoundException(dataspaceName, anchorName)).details
+ == "DataNode not found for anchor ${anchorName} and dataspace ${dataspaceName}."
+ }
+
def 'Creating a exception that a dataspace already exists.'() {
expect: 'the exception details contains the correct message with dataspace name.'
(AlreadyDefinedException.forDataspace(dataspaceName, rootCause)).details