import org.hibernate.StaleStateException
import org.onap.cps.spi.FetchDescendantsOption
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.exceptions.ConcurrencyException
import org.onap.cps.spi.exceptions.DataValidationException
def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository,
mockFragmentRepository, jsonObjectMapper, mockSessionManager))
+ def anchorEntity = new AnchorEntity(id: 123, dataspace: new DataspaceEntity(id: 1))
+
+ def setup() {
+ mockAnchorRepository.getByDataspaceAndName(_, _) >> anchorEntity
+ }
+
def 'Storing data nodes individually when batch operation fails'(){
given: 'two data nodes and supporting repository mock behavior'
def dataNode1 = createDataNodeAndMockRepositoryMethodSupportingIt('xpath1','OK')
when: 'trying to store data nodes'
objectUnderTest.storeDataNodes('dataSpaceName', 'anchorName', [dataNode1, dataNode2])
then: 'the two data nodes are saved individually'
- 2 * mockFragmentRepository.save(_);
+ 2 * mockFragmentRepository.save(_)
}
def 'Store single data node.'() {
def 'Handling of StaleStateException (caused by concurrent updates) during update data node and descendants.'() {
given: 'the fragment repository returns a fragment entity'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(*_) >> {
+ mockFragmentRepository.getByAnchorAndXpath(*_) >> {
def fragmentEntity = new FragmentEntity()
fragmentEntity.setChildFragments([new FragmentEntity()] as Set<FragmentEntity>)
return fragmentEntity
'/node1': 'OK',
'/node2': 'EXCEPTION',
'/node3': 'EXCEPTION'])
- and: 'db contains an anchor'
- mockAnchorRepository.getByDataspaceAndName(*_) >> new AnchorEntity(id:123)
and: 'the batch update will therefore also fail'
mockFragmentRepository.saveAll(*_) >> { throw new StaleStateException("concurrent updates") }
when: 'attempt batch update data nodes'
}
def 'Retrieving multiple data nodes.'() {
- given: 'db contains an anchor'
- def anchorEntity = new AnchorEntity(id:123)
- mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity
- and: 'fragment repository returns a collection of fragments'
+ given: 'fragment repository returns a collection of fragments'
def fragmentEntity1 = new FragmentEntity(xpath: '/xpath1', childFragments: [])
def fragmentEntity2 = new FragmentEntity(xpath: '/xpath2', childFragments: [])
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/xpath1', '/xpath2'] as Set<String>) >> [fragmentEntity1, fragmentEntity2]
def 'update data node leaves: #scenario'(){
given: 'A node exists for the given xpath'
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes: existingAttributes)
+ mockFragmentRepository.getByAnchorAndXpath(_, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes: existingAttributes)
when: 'the node leaves are updated'
objectUnderTest.updateDataLeaves('some-dataspace', 'some-anchor', '/some/xpath', newAttributes as Map<String, Serializable>)
then: 'the fragment entity saved has the original and new attributes'
}
def 'update data node and descendants: #scenario'(){
- given: 'mocked responses'
- mockAnchorRepository.getByDataspaceAndName(_, _) >> new AnchorEntity(id:123)
+ given: 'the fragment repository returns fragment entities related to the xpath inputs'
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, [] as Set) >> []
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, ['/test/xpath'] as Set) >> [new FragmentEntity(xpath: '/test/xpath', childFragments: [])]
when: 'replace data node tree'
def 'update data nodes and descendants'() {
given: 'the fragment repository returns fragment entities related to the xpath inputs'
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(_, ['/test/xpath1', '/test/xpath2'] as Set) >> [
- new FragmentEntity(xpath: '/test/xpath1', childFragments: []),
- new FragmentEntity(xpath: '/test/xpath2', childFragments: [])]
- and: 'db contains an anchor'
- mockAnchorRepository.getByDataspaceAndName(*_) >> new AnchorEntity(id:123)
+ new FragmentEntity(xpath: '/test/xpath1', childFragments: [], anchor: anchorEntity),
+ new FragmentEntity(xpath: '/test/xpath2', childFragments: [], anchor: anchorEntity)]
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 createDataNodeAndMockRepositoryMethodSupportingIt(xpath, scenario) {
def dataNode = new DataNodeBuilder().withXpath(xpath).build()
def fragmentEntity = new FragmentEntity(xpath: xpath, childFragments: [])
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
+ mockFragmentRepository.getByAnchorAndXpath(_, xpath) >> fragmentEntity
if ('EXCEPTION' == scenario) {
mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }
}
dataNodes.add(dataNode)
def fragmentEntity = new FragmentEntity(xpath: xpath, childFragments: [])
fragmentEntities.add(fragmentEntity)
- mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, xpath) >> fragmentEntity
+ mockFragmentRepository.getByAnchorAndXpath(_, xpath) >> fragmentEntity
if ('EXCEPTION' == scenario) {
mockFragmentRepository.save(fragmentEntity) >> { throw new StaleStateException("concurrent updates") }
}
}
def mockFragmentWithJson(json) {
- def anchorEntity = new AnchorEntity(id:123)
- mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity
def fragmentEntity = new FragmentEntity(xpath: '/parent-01', childFragments: [], attributes: json)
mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/parent-01'] as Set<String>) >> [fragmentEntity]
}