aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrajesh.kumar <rk00747546@techmahindra.com>2023-04-21 17:48:44 +0530
committerrajesh.kumar <rk00747546@techmahindra.com>2023-04-21 17:48:44 +0530
commitce3451d10315b54238b886491779b3975f326e02 (patch)
tree95c577b9babdf79acb0d2a7329a9180ffc0c6c51
parenta3697108f9e0ea6ab27b2bda799656de1689a3df (diff)
Fix issues related to query across all anchors
CPS-1580: Query Across All Anchors Does NOT Filter on Dataspace CPS-1582: NullPointerException in queryDataNodesAcrossAnchors Issue-ID: CPS-1580 Change-ID: I73f97f986a817d423f93a8d922dcd9647b2104ab Signed-off-by: rajesh.kumar <rk00747546@techmahindra.com>
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java4
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java3
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntityArranger.java20
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java53
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java8
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java10
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java4
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy1
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy30
11 files changed, 103 insertions, 36 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java
index b89342827..3b0e1834e 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
+ * 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.
@@ -32,6 +33,7 @@ import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -46,12 +48,14 @@ import lombok.Setter;
@Builder
@Entity
@Table(name = "anchor")
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class AnchorEntity implements Serializable {
private static final long serialVersionUID = -8049987915308262518L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
private Integer id;
@NotNull
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java
index 593746d94..30906ade3 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020-2021 Nordix Foundation.
* Modifications Copyright (C) 2020-2021 Pantheon.tech
+ * 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.
@@ -30,6 +31,7 @@ import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -44,12 +46,14 @@ import lombok.Setter;
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "dataspace")
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class DataspaceEntity implements Serializable {
private static final long serialVersionUID = 8395254649813051882L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @EqualsAndHashCode.Include
private Integer id;
@NotNull
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
index 82afc5a81..b90fb799a 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020-2023 Nordix Foundation.
* Modifications Copyright (C) 2021 Pantheon.tech
+ * 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.
@@ -84,10 +85,12 @@ public class FragmentEntity implements Serializable {
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dataspace_id")
+ @EqualsAndHashCode.Include
private DataspaceEntity dataspace;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "anchor_id")
+ @EqualsAndHashCode.Include
private AnchorEntity anchor;
@ToString.Exclude
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntityArranger.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntityArranger.java
index 55d3c7e87..a33c8d055 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntityArranger.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntityArranger.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 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.
@@ -47,6 +48,25 @@ public class FragmentEntityArranger {
return reuniteChildrenWithTheirParents(fragmentEntityPerId);
}
+ /**
+ * Convert a collection of (related) FragmentExtracts into FragmentEntities (trees) with descendants.
+ *
+ * @param fragmentExtracts FragmentExtracts to convert.
+ * @param fragmentExtractAnchorMap Map of fragmentExtract with their anchor.
+ * @return a collection of FragmentEntities (trees) with descendants.
+ */
+ public static Collection<FragmentEntity> toFragmentEntityTreesAcrossAnchors(
+ final Collection<FragmentExtract> fragmentExtracts,
+ final Map<Long, AnchorEntity> fragmentExtractAnchorMap) {
+ final Map<Long, FragmentEntity> fragmentEntityPerId = new HashMap<>();
+ for (final FragmentExtract fragmentExtract : fragmentExtracts) {
+ final AnchorEntity anchorEntity = fragmentExtractAnchorMap.get(fragmentExtract.getId());
+ final FragmentEntity fragmentEntity = toFragmentEntity(anchorEntity, fragmentExtract);
+ fragmentEntityPerId.put(fragmentEntity.getId(), fragmentEntity);
+ }
+ return reuniteChildrenWithTheirParents(fragmentEntityPerId);
+ }
+
private static FragmentEntity toFragmentEntity(final AnchorEntity anchorEntity,
final FragmentExtract fragmentExtract) {
final FragmentEntity fragmentEntity = new FragmentEntity();
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 aa631d1b1..0a77de234 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
@@ -324,17 +324,20 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
} catch (final PathParsingException e) {
throw new CpsPathException(e.getMessage());
}
-
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
Collection<FragmentEntity> fragmentEntities;
if (canUseRegexQuickFind(fetchDescendantsOption, cpsPathQuery)) {
- return getDataNodesUsingRegexQuickFind(fetchDescendantsOption, anchorEntity, cpsPathQuery);
+ return (anchorEntity == ALL_ANCHORS) ? getDataNodesUsingRegexQuickFindAcrossAnchors(fetchDescendantsOption,
+ dataspaceEntity, cpsPathQuery) : getDataNodesUsingRegexQuickFind(fetchDescendantsOption,
+ anchorEntity, cpsPathQuery);
}
- fragmentEntities = (anchorEntity == ALL_ANCHORS) ? fragmentRepository.findByCpsPath(cpsPathQuery)
+ fragmentEntities = (anchorEntity == ALL_ANCHORS) ? fragmentRepository
+ .findByDataspaceAndCpsPath(dataspaceEntity.getId(), cpsPathQuery)
: fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery);
if (cpsPathQuery.hasAncestorAxis()) {
final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
- fragmentEntities = (anchorEntity == ALL_ANCHORS) ? getAncestorFragmentEntitiesAcrossAnchors(cpsPathQuery,
- fragmentEntities) : getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption);
+ fragmentEntities = (anchorEntity == ALL_ANCHORS) ? getAncestorFragmentEntitiesAcrossAnchors(dataspaceEntity,
+ cpsPathQuery, fragmentEntities) : getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption);
}
return createDataNodesFromProxiedFragmentEntities(fetchDescendantsOption, anchorEntity, fragmentEntities);
}
@@ -357,22 +360,48 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
final CpsPathQuery cpsPathQuery) {
Collection<FragmentEntity> fragmentEntities;
final String xpathRegex = FragmentQueryBuilder.getXpathSqlRegex(cpsPathQuery, true);
- final List<FragmentExtract> fragmentExtracts = (anchorEntity == ALL_ANCHORS)
- ? fragmentRepository.quickFindWithDescendantsAcrossAnchor(xpathRegex) :
+ final List<FragmentExtract> fragmentExtracts =
fragmentRepository.quickFindWithDescendants(anchorEntity.getId(), xpathRegex);
fragmentEntities = FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts);
if (cpsPathQuery.hasAncestorAxis()) {
final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
- fragmentEntities = (anchorEntity == ALL_ANCHORS) ? getAncestorFragmentEntitiesAcrossAnchors(cpsPathQuery,
- fragmentEntities) : getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption);
+ fragmentEntities = getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption);
}
return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
}
- private Collection<FragmentEntity> getAncestorFragmentEntitiesAcrossAnchors(final CpsPathQuery cpsPathQuery,
- final Collection<FragmentEntity> fragmentEntities) {
+ private Collection<FragmentEntity> getAncestorFragmentEntitiesAcrossAnchors(final DataspaceEntity dataspaceEntity,
+ final CpsPathQuery cpsPathQuery, final Collection<FragmentEntity> fragmentEntities) {
final Collection<String> ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery);
- return ancestorXpaths.isEmpty() ? Collections.emptyList() : fragmentRepository.findAllByXpathIn(ancestorXpaths);
+ return ancestorXpaths.isEmpty() ? Collections.emptyList() : fragmentRepository
+ .findAllByXpathIn(dataspaceEntity, ancestorXpaths);
+ }
+
+ private List<DataNode> getDataNodesUsingRegexQuickFindAcrossAnchors(
+ final FetchDescendantsOption fetchDescendantsOption, final DataspaceEntity dataspaceEntity,
+ final CpsPathQuery cpsPathQuery) {
+ Collection<FragmentEntity> fragmentEntities;
+ final String xpathRegex = FragmentQueryBuilder.getXpathSqlRegex(cpsPathQuery, true);
+ final List<FragmentExtract> fragmentExtracts = fragmentRepository
+ .quickFindWithDescendantsAcrossAnchor(dataspaceEntity.getId(), xpathRegex);
+ final Map<Long, AnchorEntity> fragmentExtractAnchorMap = getFragmentExtractAnchorMap(fragmentExtracts);
+ fragmentEntities = FragmentEntityArranger.toFragmentEntityTreesAcrossAnchors(fragmentExtracts,
+ fragmentExtractAnchorMap);
+ if (cpsPathQuery.hasAncestorAxis()) {
+ fragmentEntities = getAncestorFragmentEntitiesAcrossAnchors(dataspaceEntity,
+ cpsPathQuery, fragmentEntities);
+ }
+ return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
+ }
+
+ private Map<Long, AnchorEntity> getFragmentExtractAnchorMap(final List<FragmentExtract> fragmentExtracts) {
+ final Map<Long, AnchorEntity> fragmentEntityAnchorMap = new HashMap<>();
+ fragmentExtracts.forEach(fragmentExtract -> {
+ final AnchorEntity anchorEntity = anchorRepository.getById(Math.toIntExact(fragmentExtract.getAnchorId()));
+ fragmentEntityAnchorMap.put(fragmentExtract.getId(), anchorEntity);
+ }
+ );
+ return fragmentEntityAnchorMap;
}
private List<DataNode> createDataNodesFromProxiedFragmentEntities(
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
index c23159593..5716304a1 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
@@ -75,15 +75,17 @@ public class FragmentQueryBuilder {
}
/**
- * Create a sql query to retrieve by cps path.
+ * Create a sql query to retrieve by dataspace id and cps path.
*
* @param cpsPathQuery the cps path query to be transformed into a sql query
* @return a executable query object
*/
- public Query getQueryForCpsPath(final CpsPathQuery cpsPathQuery) {
- final StringBuilder sqlStringBuilder = new StringBuilder("SELECT * FROM FRAGMENT WHERE xpath ~ :xpathRegex");
+ public Query getQueryForDataspaceAndCpsPath(final int dataspaceId, final CpsPathQuery cpsPathQuery) {
+ final StringBuilder sqlStringBuilder = new StringBuilder("SELECT * FROM FRAGMENT WHERE dataspace_id = "
+ + ":dataspaceId AND xpath ~ :xpathRegex");
final Map<String, Object> queryParameters = new HashMap<>();
final String xpathRegex = getXpathSqlRegex(cpsPathQuery, false);
+ queryParameters.put("dataspaceId", dataspaceId);
queryParameters.put("xpathRegex", xpathRegex);
if (cpsPathQuery.hasLeafConditions()) {
sqlStringBuilder.append(" AND attributes @> :leafDataAsJson\\:\\:jsonb");
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 d486a39c7..0067cfe43 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
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.onap.cps.spi.entities.AnchorEntity;
+import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.FragmentEntity;
import org.onap.cps.spi.entities.FragmentExtract;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
@@ -54,7 +55,9 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>,
List<FragmentEntity> findAllByAnchorAndXpathIn(AnchorEntity anchorEntity, Collection<String> xpath);
- List<FragmentEntity> findAllByXpathIn(Collection<String> xpath);
+ @Query("SELECT f FROM FragmentEntity f WHERE dataspace = :dataspace AND xpath IN :xpaths")
+ List<FragmentEntity> findAllByXpathIn(@Param("dataspace") DataspaceEntity dataspace,
+ @Param("xpaths") Collection<String> xpaths);
@Modifying
@Query("DELETE FROM FragmentEntity WHERE anchor IN (:anchors)")
@@ -109,7 +112,8 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>,
@Query(value = "SELECT id, anchor_id AS anchorId, xpath, parent_id AS parentId,"
+ " CAST(attributes AS TEXT) AS attributes"
- + " FROM FRAGMENT WHERE xpath ~ :xpathRegex",
+ + " FROM FRAGMENT WHERE dataspace_id = :dataspaceId AND xpath ~ :xpathRegex",
nativeQuery = true)
- List<FragmentExtract> quickFindWithDescendantsAcrossAnchor(@Param("xpathRegex") String xpathRegex);
+ List<FragmentExtract> quickFindWithDescendantsAcrossAnchor(@Param("dataspaceId") int dataspaceId,
+ @Param("xpathRegex") String xpathRegex);
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java
index 32041e7d5..4195f62a6 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java
@@ -28,5 +28,5 @@ import org.onap.cps.spi.entities.FragmentEntity;
public interface FragmentRepositoryCpsPathQuery {
List<FragmentEntity> findByAnchorAndCpsPath(int anchorId, CpsPathQuery cpsPathQuery);
- List<FragmentEntity> findByCpsPath(CpsPathQuery cpsPathQuery);
+ List<FragmentEntity> findByDataspaceAndCpsPath(int dataspaceId, CpsPathQuery cpsPathQuery);
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java
index b95491cd3..3ea5cef83 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java
@@ -51,8 +51,8 @@ public class FragmentRepositoryCpsPathQueryImpl implements FragmentRepositoryCps
@Override
@Transactional
- public List<FragmentEntity> findByCpsPath(final CpsPathQuery cpsPathQuery) {
- final Query query = fragmentQueryBuilder.getQueryForCpsPath(cpsPathQuery);
+ public List<FragmentEntity> findByDataspaceAndCpsPath(final int dataspaceId, final CpsPathQuery cpsPathQuery) {
+ final Query query = fragmentQueryBuilder.getQueryForDataspaceAndCpsPath(dataspaceId, cpsPathQuery);
final List<FragmentEntity> fragmentEntities = query.getResultList();
log.debug("Fetched {} fragment entities by cps path across all anchors.", fragmentEntities.size());
return fragmentEntities;
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
index 60aaa8114..fae2c5aae 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
@@ -193,6 +193,7 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase {
'String and no descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005']
'Integer and descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]' | INCLUDE_ALL_DESCENDANTS || 3 || ['ANCHOR-004', 'ANCHOR-005']
'No condition no descendants' | '/shops/shop[@id=1]/categories' | OMIT_DESCENDANTS || 6 || ['ANCHOR-004', 'ANCHOR-005']
+ 'top node and all descendants' | '/shops' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005']
'multiple list-ancestors' | '//book/ancestor::categories' | INCLUDE_ALL_DESCENDANTS || 4 || ['ANCHOR-004', 'ANCHOR-005']
'one ancestor with list value' | '//book/ancestor::categories[@code=1]' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005']
'list with index value in the xpath prefix' | '//categories[@code=1]/book/ancestor::shop[@id=1]' | INCLUDE_ALL_DESCENDANTS || 2 || ['ANCHOR-004', 'ANCHOR-005']
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 f02aa754f..fcd8f4637 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
@@ -212,32 +212,32 @@ class CpsDataPersistenceServiceSpec extends Specification {
when: 'replace data node tree'
objectUnderTest.updateDataNodesAndDescendants('dataspaceName', 'anchorName', dataNodes)
then: 'call fragment repository save all method'
- 1 * mockFragmentRepository.saveAll({fragmentEntities -> assert fragmentEntities as List == expectedFragmentEntities})
+ 1 * mockFragmentRepository.saveAll({fragmentEntities -> fragmentEntities.containsAll(expectedFragmentEntities)})
where: 'the following Data Type is passed'
scenario | dataNodes || expectedFragmentEntities
'empty data node list' | [] || []
- 'one data node in list' | [new DataNode(xpath: '/test/xpath', leaves: ['id': 'testId'], childDataNodes: [])] || [new FragmentEntity(xpath: '/test/xpath', attributes: '{"id":"testId"}', childFragments: [])]
+ 'one data node in list' | [new DataNode(xpath: '/test/xpath', leaves: ['id': 'testId'], childDataNodes: [])] || [new FragmentEntity(xpath: '/test/xpath', attributes: '{"id":"testId"}', childFragments: [], anchor: new AnchorEntity(id: 123), dataspace: new DataspaceEntity(id: 1))]
}
def 'update data nodes and descendants'() {
given: 'the fragment repository returns fragment entities related to the xpath inputs'
- mockFragmentRepository.findExtractsWithDescendants(123, ['/test/xpath1', '/test/xpath2'] as Set, _) >> [
+ mockFragmentRepository.findExtractsWithDescendants(123, ['/test/xpath1', '/test/xpath2'] as Set, _) >> [
mockFragmentExtract(1, null, 123, '/test/xpath1', null),
mockFragmentExtract(2, null, 123, '/test/xpath2', null)
- ]
+ ]
and: 'some data nodes with descendants'
- def dataNode1 = new DataNode(xpath: '/test/xpath1', leaves: ['id': 'testId1'], childDataNodes: [new DataNode(xpath: '/test/xpath1/child', leaves: ['id': 'childTestId1'])])
- def dataNode2 = new DataNode(xpath: '/test/xpath2', leaves: ['id': 'testId2'], childDataNodes: [new DataNode(xpath: '/test/xpath2/child', leaves: ['id': 'childTestId2'])])
+ def dataNode1 = new DataNode(xpath: '/test/xpath1', leaves: ['id': 'testId1'], childDataNodes: [new DataNode(xpath: '/test/xpath1/child', leaves: ['id': 'childTestId1'])])
+ def dataNode2 = new DataNode(xpath: '/test/xpath2', leaves: ['id': 'testId2'], childDataNodes: [new DataNode(xpath: '/test/xpath2/child', leaves: ['id': 'childTestId2'])])
when: 'the fragment entities are update by the data nodes'
- objectUnderTest.updateDataNodesAndDescendants('dataspaceName', 'anchorName', [dataNode1, dataNode2])
+ objectUnderTest.updateDataNodesAndDescendants('dataspaceName', 'anchorName', [dataNode1, dataNode2])
then: 'call fragment repository save all method is called with the updated fragments'
- 1 * mockFragmentRepository.saveAll({fragmentEntities -> {
- fragmentEntities.containsAll([
- new FragmentEntity(xpath: '/test/xpath1', attributes: '{"id":"testId1"}', childFragments: [new FragmentEntity(xpath: '/test/xpath1/child', attributes: '{"id":"childTestId1"}', childFragments: [])]),
- new FragmentEntity(xpath: '/test/xpath2', attributes: '{"id":"testId2"}', childFragments: [new FragmentEntity(xpath: '/test/xpath2/child', attributes: '{"id":"childTestId2"}', childFragments: [])])
- ])
- assert fragmentEntities.size() == 2
- }})
+ 1 * mockFragmentRepository.saveAll({fragmentEntities -> {
+ fragmentEntities.containsAll([
+ new FragmentEntity(xpath: '/test/xpath1', anchor: new AnchorEntity(id: 123), dataspace: new DataspaceEntity(id: 1), attributes: '{"id":"testId1"}', childFragments: [new FragmentEntity(xpath: '/test/xpath1/child', attributes: '{"id":"childTestId1"}', childFragments: [])]),
+ new FragmentEntity(xpath: '/test/xpath2', anchor: new AnchorEntity(id: 123), dataspace: new DataspaceEntity(id: 1), attributes: '{"id":"testId2"}', childFragments: [new FragmentEntity(xpath: '/test/xpath2/child', attributes: '{"id":"childTestId2"}', childFragments: [])])
+ ])
+ assert fragmentEntities.size() == 2
+ }})
}
def createDataNodeAndMockRepositoryMethodSupportingIt(xpath, scenario) {
@@ -261,7 +261,7 @@ class CpsDataPersistenceServiceSpec extends Specification {
dataNodes.add(dataNode)
def fragmentExtract = mockFragmentExtract(fragmentId, null, null, xpath, null)
fragmentExtracts.add(fragmentExtract)
- def fragmentEntity = new FragmentEntity(id: fragmentId, xpath: xpath, childFragments: [])
+ def fragmentEntity = new FragmentEntity(id: fragmentId, xpath: xpath, childFragments: [], anchor: new AnchorEntity(id: 123), dataspace: new DataspaceEntity(id: 1))
mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
if ('EXCEPTION' == scenario) {
mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }