2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022 Bell Canada.
4 * Modifications Copyright (C) 2021-2023 Nordix Foundation.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the 'License');
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an 'AS IS' BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 package org.onap.cps.spi.impl
23 import org.hibernate.exception.ConstraintViolationException
24 import org.onap.cps.spi.CpsAdminPersistenceService
25 import org.onap.cps.spi.CpsModulePersistenceService
26 import org.onap.cps.spi.entities.DataspaceEntity
27 import org.onap.cps.spi.entities.SchemaSetEntity
28 import org.onap.cps.spi.exceptions.DuplicatedYangResourceException
29 import org.onap.cps.spi.model.ModuleReference
30 import org.onap.cps.spi.repository.DataspaceRepository
31 import org.onap.cps.spi.repository.ModuleReferenceRepository
32 import org.onap.cps.spi.repository.SchemaSetRepository
33 import org.onap.cps.spi.repository.YangResourceRepository
34 import org.spockframework.spring.SpringBean
35 import org.springframework.beans.factory.annotation.Autowired
36 import org.springframework.boot.test.context.SpringBootTest
37 import org.springframework.dao.DataIntegrityViolationException
38 import org.springframework.retry.annotation.EnableRetry
39 import spock.lang.Specification
41 import java.sql.SQLException
43 @SpringBootTest(classes=[CpsModulePersistenceServiceImpl])
45 class CpsModulePersistenceServiceConcurrencySpec extends Specification {
48 CpsModulePersistenceService objectUnderTest
51 DataspaceRepository dataspaceRepository = Mock()
54 YangResourceRepository yangResourceRepository = Mock()
57 SchemaSetRepository schemaSetRepository = Mock()
60 CpsAdminPersistenceService cpsAdminPersistenceService = Mock()
63 ModuleReferenceRepository moduleReferenceRepository = Mock()
65 def NEW_RESOURCE_NAME = 'some new resource'
66 def NEW_RESOURCE_CONTENT = 'module stores {\n' +
67 ' yang-version 1.1;\n' +
68 ' namespace "org:onap:ccsdk:sample";\n' +
71 def newYangResourcesNameToContentMap = [(NEW_RESOURCE_NAME):NEW_RESOURCE_CONTENT]
73 def yangResourceChecksum = 'b13faef573ed1374139d02c40d8ce09c80ea1dc70e63e464c1ed61568d48d539'
75 def yangResourceChecksumDbConstraint = 'yang_resource_checksum_key'
77 def sqlExceptionMessage = String.format('(checksum)=(%s)', yangResourceChecksum)
79 def checksumIntegrityException = new DataIntegrityViolationException("checksum integrity exception",
80 new ConstraintViolationException('', new SQLException(sqlExceptionMessage), yangResourceChecksumDbConstraint))
82 def 'Store new schema set, maximum retries.'() {
83 given: 'no pre-existing schemaset in database'
84 dataspaceRepository.getByName(_) >> new DataspaceEntity()
85 yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList()
86 when: 'a new schemaset is stored'
87 objectUnderTest.storeSchemaSet('some dataspace', 'some new schema set', newYangResourcesNameToContentMap)
88 then: 'a duplicated yang resource exception is thrown '
89 thrown(DuplicatedYangResourceException)
90 and: 'the system will attempt to save the data 5 times (because checksum integrity exception is thrown each time)'
91 5 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException }
94 def 'Store new schema set, succeed on third attempt.'() {
95 given: 'no pre-existing schemaset in database'
96 dataspaceRepository.getByName(_) >> new DataspaceEntity()
97 yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList()
98 when: 'a new schemaset is stored'
99 objectUnderTest.storeSchemaSet('some dataspace', 'some new schema set', newYangResourcesNameToContentMap)
100 then: 'no exception is thrown '
102 and: 'the system will attempt to save the data 2 times with checksum integrity exception but then succeed'
103 2 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException }
104 1 * yangResourceRepository.saveAll(_) >> []
107 def 'Store schema set using modules, maximum retries.'() {
108 given: 'map of new modules, a list of existing modules, module reference'
109 def mapOfNewModules = [newModule1: 'module newmodule { yang-version 1.1; revision "2021-10-12" { } }']
110 def moduleReferenceForExistingModule = new ModuleReference("test","2021-10-12")
111 def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
112 and: 'no pre-existing schemaset in database'
113 dataspaceRepository.getByName(_) >> new DataspaceEntity()
114 yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList()
115 when: 'a new schemaset is stored from a module'
116 objectUnderTest.storeSchemaSetFromModules('some dataspace', 'some new schema set' , mapOfNewModules, listOfExistingModulesModuleReference)
117 then: 'a duplicated yang resource exception is thrown '
118 thrown(DuplicatedYangResourceException)
119 and: 'the system will attempt to save the data 5 times (because checksum integrity exception is thrown each time)'
120 5 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException }
123 def 'Store schema set using modules, succeed on third attempt.'() {
124 given: 'map of new modules, a list of existing modules, module reference'
125 def mapOfNewModules = [newModule1: 'module newmodule { yang-version 1.1; revision "2021-10-12" { } }']
126 def moduleReferenceForExistingModule = new ModuleReference("test","2021-10-12")
127 def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
128 and: 'no pre-existing schemaset in database'
129 def dataspaceEntity = new DataspaceEntity()
130 dataspaceRepository.getByName(_) >> new DataspaceEntity()
131 yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList()
132 yangResourceRepository.getResourceIdsByModuleReferences(_) >> []
133 and: 'can retrieve schemaset details after storing it'
134 def schemaSetEntity = new SchemaSetEntity()
135 schemaSetRepository.getByDataspaceAndName(dataspaceEntity, 'new schema set') >> schemaSetEntity
136 when: 'a new schemaset is stored from a module'
137 objectUnderTest.storeSchemaSetFromModules('some dataspace', 'new schema set' , mapOfNewModules, listOfExistingModulesModuleReference)
138 then: 'no exception is thrown '
140 and: 'the system will attempt to save the data 2 times with checksum integrity exception but then succeed'
141 2 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException }
142 1 * yangResourceRepository.saveAll(_) >> []