b4a4c7e17dabe5509376dc2283f7b0ccf4d869ba
[cps.git] / cps-ri / src / test / groovy / org / onap / cps / spi / impl / CpsModulePersistenceServiceIntegrationSpec.groovy
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  Modifications Copyright (C) 2021 Bell Canada.
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
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an 'AS IS' BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20 package org.onap.cps.spi.impl
21
22 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED
23 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
24
25 import org.onap.cps.spi.CpsAdminPersistenceService
26 import org.onap.cps.spi.CpsModulePersistenceService
27 import org.onap.cps.spi.entities.YangResourceEntity
28 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
29 import org.onap.cps.spi.exceptions.AlreadyDefinedException
30 import org.onap.cps.spi.exceptions.SchemaSetInUseException
31 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
32 import org.onap.cps.spi.repository.AnchorRepository
33 import org.onap.cps.spi.repository.SchemaSetRepository
34 import org.springframework.beans.factory.annotation.Autowired
35 import org.springframework.test.context.jdbc.Sql
36
37 class CpsModulePersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
38
39     @Autowired
40     CpsModulePersistenceService objectUnderTest
41
42     @Autowired
43     AnchorRepository anchorRepository
44
45     @Autowired
46     SchemaSetRepository schemaSetRepository
47
48     @Autowired
49     CpsAdminPersistenceService cpsAdminPersistenceService
50
51     static final String SET_DATA = '/data/schemaset.sql'
52     static final String EXISTING_SCHEMA_SET_NAME = SCHEMA_SET_NAME1
53     static final String SCHEMA_SET_NAME_NO_ANCHORS = 'SCHEMA-SET-100'
54     static final String SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA = 'SCHEMA-SET-101'
55     static final String SCHEMA_SET_NAME_NEW = 'SCHEMA-SET-NEW'
56
57     static final Long NEW_RESOURCE_ABSTRACT_ID = 0L
58     static final String NEW_RESOURCE_NAME = 'some new resource'
59     static final String NEW_RESOURCE_CONTENT = 'some resource content'
60     static final String NEW_RESOURCE_CHECKSUM = '09002da02ee2683898d2c81c67f9e22cdbf8577d8c2de16c84d724e4ae44a0a6'
61
62     def newYangResourcesNameToContentMap = [(NEW_RESOURCE_NAME):NEW_RESOURCE_CONTENT]
63     def dataspaceEntity
64
65     def setup() {
66         dataspaceEntity = dataspaceRepository.getByName(DATASPACE_NAME)
67     }
68
69     @Sql([CLEAR_DATA, SET_DATA])
70     def 'Store schema set error scenario: #scenario.'() {
71         when: 'attempt to store schema set #schemaSetName in dataspace #dataspaceName'
72             objectUnderTest.storeSchemaSet(dataspaceName, schemaSetName, newYangResourcesNameToContentMap)
73         then: 'an #expectedException is thrown'
74             thrown(expectedException)
75         where: 'the following data is used'
76             scenario                    | dataspaceName  | schemaSetName            || expectedException
77             'dataspace does not exist'  | 'unknown'      | 'not-relevant'           || DataspaceNotFoundException
78             'schema set already exists' | DATASPACE_NAME | EXISTING_SCHEMA_SET_NAME || AlreadyDefinedException
79     }
80
81     @Sql([CLEAR_DATA, SET_DATA])
82     def 'Store new schema set.'() {
83         when: 'a new schemaset is stored'
84             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
85         then: 'the schema set is persisted correctly'
86             assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, NEW_RESOURCE_ABSTRACT_ID, NEW_RESOURCE_NAME,
87                     NEW_RESOURCE_CONTENT, NEW_RESOURCE_CHECKSUM)
88     }
89
90     @Sql([CLEAR_DATA, SET_DATA])
91     def 'Retrieving schema set (resources) by anchor.'() {
92         given: 'a new schema set is stored'
93             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
94         and: 'an anchor is created with that schema set'
95             cpsAdminPersistenceService.createAnchor(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, ANCHOR_NAME1)
96         when: 'the schema set resources for that anchor is retrieved'
97             def result = objectUnderTest.getYangSchemaSetResources(DATASPACE_NAME, ANCHOR_NAME1)
98         then: 'the correct resources are returned'
99              result == newYangResourcesNameToContentMap
100     }
101
102     @Sql([CLEAR_DATA, SET_DATA])
103     def 'Storing duplicate schema content.'() {
104         given: 'a new schema set with a resource with the same content as an existing resource'
105             def existingResourceContent = 'CONTENT-001'
106             def newYangResourcesNameToContentMap = [(NEW_RESOURCE_NAME):existingResourceContent]
107         when: 'the schema set with duplicate resource is stored'
108             objectUnderTest.storeSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NEW, newYangResourcesNameToContentMap)
109         then: 'the schema persisted (re)uses the existing id, name and has the same checksum'
110             def existingResourceId = 3001L
111             def existingResourceName = 'module1@2020-02-02.yang'
112             def existingResourceChecksum = 'e8bdda931099310de66532e08c3fafec391db29f55c81927b168f6aa8f81b73b'
113             assertSchemaSetPersisted(DATASPACE_NAME, SCHEMA_SET_NAME_NEW,
114                     existingResourceId, existingResourceName, existingResourceContent, existingResourceChecksum)
115     }
116
117     @Sql([CLEAR_DATA, SET_DATA])
118     def 'Delete schema set with cascade delete prohibited but no anchors using it'() {
119         when: 'a schema set is deleted with cascade-prohibited option'
120             objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS,
121                     CASCADE_DELETE_PROHIBITED)
122         then: 'the schema set has been deleted'
123             schemaSetRepository.findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_NO_ANCHORS).isPresent() == false
124         and: 'any orphaned (not used by any schema set anymore) yang resources are deleted'
125             def orphanedResourceId = 3100L
126             yangResourceRepository.findById(orphanedResourceId).isPresent() == false
127         and: 'any shared (still in use by other schema set) yang resources still persists'
128             def sharedResourceId = 3003L
129             yangResourceRepository.findById(sharedResourceId).isPresent()
130     }
131
132     @Sql([CLEAR_DATA, SET_DATA])
133     def 'Delete schema set with cascade allowed.'() {
134         when: 'a schema set is deleted with cascade-allowed option'
135             objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA,
136                     CASCADE_DELETE_ALLOWED)
137         then: 'the schema set has been deleted'
138             schemaSetRepository
139                     .findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA).isPresent() == false
140         and: 'the associated anchors are removed'
141             def associatedAnchorsIds = [ 6001, 6002 ]
142             associatedAnchorsIds.each {anchorRepository.findById(it).isPresent() == false }
143         and: 'the fragment(s) under those anchors are removed'
144             def fragmentUnderAnchor1Id = 7001L
145             fragmentRepository.findById(fragmentUnderAnchor1Id).isPresent() == false
146         and: 'the shared resources still persist'
147             def sharedResourceIds = [ 3003L, 3004L ]
148             sharedResourceIds.each {yangResourceRepository.findById(it).isPresent() }
149     }
150
151     @Sql([CLEAR_DATA, SET_DATA])
152     def 'Delete schema set error scenario: #scenario.'() {
153         when: 'attempt to delete a schema set where #scenario'
154             objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED)
155         then: 'an #expectedException is thrown'
156             thrown(expectedException)
157         where: 'the following data is used'
158             scenario                                   | dataspaceName  | schemaSetName                         || expectedException
159             'dataspace does not exist'                 | 'unknown'      | 'not-relevant'                        || DataspaceNotFoundException
160             'schema set does not exists'               | DATASPACE_NAME | 'unknown'                             || SchemaSetNotFoundException
161             'cascade prohibited but schema set in use' | DATASPACE_NAME | SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA || SchemaSetInUseException
162     }
163
164     def assertSchemaSetPersisted(expectedDataspaceName,
165                              expectedSchemaSetName,
166                              expectedYangResourceId,
167                              expectedYangResourceName,
168                              expectedYangResourceContent,
169                              expectedYangResourceChecksum) {
170         // assert the schema set is persisted
171         def schemaSetEntity = schemaSetRepository
172                 .findByDataspaceAndName(dataspaceEntity, expectedSchemaSetName).orElseThrow()
173         assert schemaSetEntity.name == expectedSchemaSetName
174         assert schemaSetEntity.dataspace.name == expectedDataspaceName
175
176         // assert the attached yang resource is persisted
177         def yangResourceEntities = schemaSetEntity.getYangResources()
178         yangResourceEntities.size() == 1
179
180         // assert the attached yang resource content
181         YangResourceEntity yangResourceEntity = yangResourceEntities.iterator().next()
182         assert yangResourceEntity.id != null
183         if (expectedYangResourceId != NEW_RESOURCE_ABSTRACT_ID) {
184             // existing resource with known id
185             assert yangResourceEntity.id == expectedYangResourceId
186         }
187         yangResourceEntity.name == expectedYangResourceName
188         yangResourceEntity.content == expectedYangResourceContent
189         yangResourceEntity.checksum == expectedYangResourceChecksum
190     }
191
192 }