-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.dao.DataIntegrityViolationException
-import org.springframework.test.context.jdbc.Sql
-import spock.lang.Unroll
-
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
-class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase {
-
- @Autowired
- CpsDataPersistenceService objectUnderTest
-
- static final String SET_DATA = '/data/fragment.sql'
- static final long ID_DATA_NODE_WITH_DESCENDANTS = 4001
- static final String XPATH_DATA_NODE_WITH_DESCENDANTS = '/parent-1'
- static final String XPATH_DATA_NODE_WITH_LEAVES = '/parent-100'
-
- static final DataNode newDataNode = new DataNodeBuilder().build()
- static DataNode existingDataNode
- static DataNode existingChildDataNode
-
- static Map<String, Map<String, Object>> expectedLeavesByXpathMap = [
- '/parent-100' : ["x": "y"],
- '/parent-100/child-001' : ["a": "b", "c": ["d", "e", "f"]],
- '/parent-100/child-002' : ["g": "h", "i": ["j", "k"]],
- '/parent-100/child-002/grand-child': ["l": "m", "n": ["o", "p"]]
- ]
-
- static {
- existingDataNode = createDataNodeTree(XPATH_DATA_NODE_WITH_DESCENDANTS)
- existingChildDataNode = createDataNodeTree('/parent-1/child-1')
- }
-
- @Sql([CLEAR_DATA, SET_DATA])
- def 'StoreDataNode with descendants.'() {
- when: 'a fragment with descendants is stored'
- def parentXpath = "/parent-new"
- def childXpath = "/parent-new/child-new"
- def grandChildXpath = "/parent-new/child-new/grandchild-new"
- objectUnderTest.storeDataNode(DATASPACE_NAME, ANCHOR_NAME1,
- createDataNodeTree(parentXpath, childXpath, grandChildXpath))
- then: 'it can be retrieved by its xpath'
- def parentFragment = getFragmentByXpath(DATASPACE_NAME, ANCHOR_NAME1, parentXpath)
- and: 'it contains the children'
- parentFragment.childFragments.size() == 1
- def childFragment = parentFragment.childFragments[0]
- childFragment.xpath == childXpath
- and: "and its children's children"
- childFragment.childFragments.size() == 1
- def grandchildFragment = childFragment.childFragments[0]
- grandchildFragment.xpath == grandChildXpath
- }
+import org.onap.cps.spi.repository.AnchorRepository
+import org.onap.cps.spi.repository.DataspaceRepository
+import org.onap.cps.spi.repository.FragmentRepository
+import org.onap.cps.spi.utils.SessionManager
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+class CpsDataPersistenceServiceSpec extends Specification {
+
+ def mockDataspaceRepository = Mock(DataspaceRepository)
+ def mockAnchorRepository = Mock(AnchorRepository)
+ def mockFragmentRepository = Mock(FragmentRepository)
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockSessionManager = Mock(SessionManager)
+
+ def objectUnderTest = new CpsDataPersistenceServiceImpl(
+ mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper,mockSessionManager)
+
+ def 'Handling of StaleStateException (caused by concurrent updates) during data node tree update.'() {
+
+ def parentXpath = '/parent-01'
+ def myDataspaceName = 'my-dataspace'
+ def myAnchorName = 'my-anchor'
+
+ given: 'data node object'
+ def submittedDataNode = new DataNodeBuilder()
+ .withXpath(parentXpath)
+ .withLeaves(['leaf-name': 'leaf-value'])
+ .build()
+ and: 'fragment to be updated'
+ mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> {
+ def fragmentEntity = new FragmentEntity()
+ fragmentEntity.setXpath(parentXpath)
+ fragmentEntity.setChildFragments(Collections.emptySet())
+ return fragmentEntity
+ }
+ and: 'data node is concurrently updated by another transaction'
+ mockFragmentRepository.save(_) >> { throw new StaleStateException("concurrent updates") }