final Collection<String> xpathsOfUpdatedLeaves = updatedLeavesPerXPath.keySet();
final Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpathsOfUpdatedLeaves);
-
+ if (fragmentEntities.isEmpty()) {
+ throw new DataNodeNotFoundExceptionBatch(dataspaceName, anchorName, xpathsOfUpdatedLeaves);
+ }
for (final FragmentEntity fragmentEntity : fragmentEntities) {
final Map<String, Serializable> updatedLeaves = updatedLeavesPerXPath.get(fragmentEntity.getXpath());
final String mergedLeaves = mergeLeaves(updatedLeaves, fragmentEntity.getAttributes());
import com.fasterxml.jackson.databind.ObjectMapper
import org.hibernate.StaleStateException
+import org.onap.cps.api.exceptions.DataNodeNotFoundExceptionBatch
import org.onap.cps.ri.models.AnchorEntity
import org.onap.cps.ri.models.DataspaceEntity
import org.onap.cps.ri.models.FragmentEntity
def 'Batch update data node leaves and descendants: #scenario'(){
given: 'the fragment repository returns fragment entities related to the xpath inputs'
- mockFragmentRepository.findByAnchorAndXpathIn(_, [] as Set) >> []
mockFragmentRepository.findByAnchorAndXpathIn(_, ['/test/xpath'] as Set) >> [
new FragmentEntity(1, '/test/xpath', null, "{\"id\":\"testId\"}", anchorEntity, [] as Set)
]
})
where: 'the following Data Type is passed'
scenario | dataNodes | expectedSize || expectedFragmentEntities
- 'empty data node list' | [] | 0 || []
'one data node in list' | [new DataNode(xpath: '/test/xpath', leaves: ['id': 'testId'])] | 1 || [new FragmentEntity(xpath: '/test/xpath', attributes: '{"id":"testId"}', anchor: anchorEntity)]
'multiple data nodes' | [new DataNode(xpath: '/test/xpath1', leaves: ['id': 'newTestId1']), new DataNode(xpath: '/test/xpath2', leaves: ['id': 'newTestId2'])] | 2 || [new FragmentEntity(xpath: '/test/xpath2', attributes: '{"id":"newTestId2"}', anchor: anchorEntity), new FragmentEntity(xpath: '/test/xpath1', attributes: '{"id":"newTestId1"}', anchor: anchorEntity)]
}
+ def 'Batch update data node leaves and descendants fails when fragment entity is not found'() {
+ given: 'leaf nodes to update'
+ def leafNodes = ['/test/xpath': ['id': 'invalid-id']]
+ and: 'the fragment repository returns no fragment entities'
+ mockFragmentRepository.findByAnchorAndXpathIn(anchorEntity, ['/test/xpath'] as Set) >> []
+ and: 'the fragment repository returns no fragments for list nodes'
+ mockFragmentRepository.findListByAnchorAndXpath(anchorEntity, '/test/xpath') >> []
+ when: 'attempt to batch update data node leaves'
+ objectUnderTest.batchUpdateDataLeaves('dataspaceName', 'anchorName', leafNodes)
+ then: 'expected exception is thrown with correct message'
+ def thrown = thrown(DataNodeNotFoundExceptionBatch)
+ assert thrown.message == 'DataNode not found'
+ }
+
def 'Handling of StaleStateException (caused by concurrent updates) during update data nodes and descendants.'() {
given: 'the system can update one datanode and has two more datanodes that throw an exception while updating'
def dataNodes = createDataNodesAndMockRepositoryMethodSupportingThem([
restoreBookstoreDataAnchor(2)
}
+ def 'Update leaves on non existing data node'() {
+ given: 'JSON string with data of non existent data node'
+ def jsonDataForNonExistingDataNode = "{'books':{'lang':'English/French','price':100,'title':'Non-existing book'}}"
+ when: 'attempt to perform update'
+ objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonDataForNonExistingDataNode, now, ContentType.JSON)
+ then: 'expected exception is thrown'
+ thrown(DataNodeNotFoundExceptionBatch)
+ }
+
+ def 'Update leaves and descendants on non existing data node'() {
+ given: 'JSON string with data of non existent data node'
+ def jsonDataForNonExistingDataNodes = "{'categories':{'code':'xxx','books':{'lang':'English/French','price':100,'title':'Non-existing book'}}}"
+ when: 'attempt to perform update'
+ objectUnderTest.updateNodeLeavesAndExistingDescendantLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore", jsonDataForNonExistingDataNodes, now)
+ then: 'expected exception is thrown'
+ thrown(DataNodeNotFoundExceptionBatch)
+ }
+
def countDataNodesInBookstore() {
return countDataNodesInTree(objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', INCLUDE_ALL_DESCENDANTS))
}