Merge "Add memory usage to integration tests [UPDATED]"
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / functional / CpsModuleServiceIntegrationSpec.groovy
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2023 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the 'License');
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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
21 package org.onap.cps.integration.functional
22
23 import org.onap.cps.api.impl.CpsModuleServiceImpl
24 import org.onap.cps.integration.base.FunctionalSpecBase
25 import org.onap.cps.spi.CascadeDeleteAllowed
26 import org.onap.cps.spi.exceptions.AlreadyDefinedException
27 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
28 import org.onap.cps.spi.exceptions.ModelValidationException
29 import org.onap.cps.spi.exceptions.SchemaSetInUseException
30 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
31 import org.onap.cps.spi.model.ModuleDefinition
32 import org.onap.cps.spi.model.ModuleReference
33
34 class CpsModuleServiceIntegrationSpec extends FunctionalSpecBase {
35
36     CpsModuleServiceImpl objectUnderTest
37
38     private static def originalNumberOfModuleReferences = 1
39     private static def existingModuleReference = new ModuleReference('stores','2020-09-15')
40     static def NEW_RESOURCE_REVISION = '2023-05-10'
41     static def NEW_RESOURCE_CONTENT = 'module test_module {\n' +
42         '    yang-version 1.1;\n' +
43         '    namespace "org:onap:ccsdk:sample";\n' +
44         '\n' +
45         '    prefix book-store;\n' +
46         '\n' +
47         '    revision "2023-05-10" {\n' +
48         '        description\n' +
49         '        "Sample Model";\n' +
50         '    }' +
51         '}'
52
53     def newYangResourcesNameToContentMap = [:]
54     def moduleReferences = []
55
56     def setup() {
57         objectUnderTest = cpsModuleService
58     }
59
60     /*
61         C R E A T E   S C H E M A   S E T   U S E - C A S E S
62      */
63
64     def 'Create new schema set from yang resources with #scenario'() {
65         given: 'a new schema set with #numberOfModules modules'
66             populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfNewModules)
67         when: 'the new schema set is created'
68             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', newYangResourcesNameToContentMap)
69         then: 'the number of module references has increased by #expectedIncrease'
70             def yangResourceModuleReferences = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1)
71             originalNumberOfModuleReferences + numberOfNewModules == yangResourceModuleReferences.size()
72         cleanup:
73             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ 'newSchemaSet' ])
74         where: 'the following parameters are use'
75             scenario                       | numberOfNewModules
76             'two valid new modules'        | 2
77             'empty schema set'             | 0
78             'over max batch size #modules' | 101
79     }
80
81     def 'Create new schema set with recommended filename format but invalid yang'() {
82         given: 'a filename using RFC6020 recommended format (for coverage only)'
83             def fileName = 'test@2023-05-11.yang'
84         when: 'attempt to create a schema set with invalid Yang'
85             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', [(fileName) :'invalid yang'])
86         then: 'a model validation exception'
87             thrown(ModelValidationException)
88     }
89
90     def 'Create new schema set from modules with #scenario'() {
91         given: 'a new schema set with #numberOfNewModules modules'
92             populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfNewModules)
93         and: 'add existing module references (optional)'
94             moduleReferences.addAll(existingModuleReferences)
95         when: 'the new schema set is created'
96             def schemaSetName = "NewSchemaWith${numberOfNewModules}Modules"
97             objectUnderTest.createOrUpgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences)
98         and: 'associated with a new anchor'
99             cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, 'newAnchor')
100         then: 'the new anchor has the correct number of modules'
101             def yangResourceModuleReferences = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'newAnchor')
102             assert expectedNumberOfModulesForAnchor == yangResourceModuleReferences.size()
103         cleanup:
104             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ schemaSetName.toString() ])
105         where: 'the following module references are provided'
106             scenario                        | numberOfNewModules | existingModuleReferences                          || expectedNumberOfModulesForAnchor
107             'empty schema set'              | 0                  | [ ]                                               || 0
108             'one existing module'           | 0                  | [ existingModuleReference ]                       || 1
109             'two new modules'               | 2                  | [ ]                                               || 2
110             'two new modules, one existing' | 2                  | [ existingModuleReference ]                       || 3
111             'over max batch size #modules'  | 101                | [ ]                                               || 101
112             'two valid, one invalid module' | 2                  | [ new ModuleReference('NOT EXIST','IRRELEVANT') ] || 2
113     }
114
115     def 'Duplicate schema content.'() {
116         given: 'a map of yang resources'
117             populateNewYangResourcesNameToContentMapAndAllModuleReferences(1)
118         when: 'a new schema set is created'
119             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', newYangResourcesNameToContentMap)
120         then: 'the dataspace has one new module (reference)'
121             def numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size()
122             assert numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded == originalNumberOfModuleReferences + 1
123         when: 'a second new schema set is created'
124             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema2', newYangResourcesNameToContentMap)
125         then: 'the dataspace has no additional module (reference)'
126             assert numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded  == objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size()
127         cleanup:
128             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ 'newSchema1', 'newSchema2'])
129     }
130
131     def 'Create schema set error scenario: #scenario.'() {
132         when: 'attempt to store schema set #schemaSetName in dataspace #dataspaceName'
133             populateNewYangResourcesNameToContentMapAndAllModuleReferences(0)
134             objectUnderTest.createSchemaSet(dataspaceName, schemaSetName, newYangResourcesNameToContentMap)
135         then: 'an #expectedException is thrown'
136             thrown(expectedException)
137         where: 'the following data is used'
138             scenario                    | dataspaceName               | schemaSetName        || expectedException
139             'dataspace does not exist'  | 'unknown'                   | 'not-relevant'       || DataspaceNotFoundException
140             'schema set already exists' | FUNCTIONAL_TEST_DATASPACE_1 | BOOKSTORE_SCHEMA_SET || AlreadyDefinedException
141     }
142
143     /*
144         R E A D   S C H E M A   S E T   I N F O   U S E - C A S E S
145      */
146
147     def 'Retrieving module definitions by anchor.'() {
148         when: 'the module definitions for an anchor are retrieved'
149             def result = objectUnderTest.getModuleDefinitionsByAnchorName(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1)
150         then: 'the correct module definitions are returned'
151             result == [new ModuleDefinition('stores','2020-09-15','')]
152     }
153
154     def 'Retrieving yang resource module references by anchor.'() {
155         when: 'the yang resource module references for an anchor are retrieved'
156             def result = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1)
157         then: 'the correct module references are returned'
158             result == [ existingModuleReference ]
159     }
160
161     def 'Identifying new module references with #scenario'() {
162         when: 'identifyNewModuleReferences is called'
163             def result = objectUnderTest.identifyNewModuleReferences(moduleReferences)
164         then: 'the correct module references are returned'
165             assert result.size() == expectedResult.size()
166             assert result.containsAll(expectedResult)
167         where: 'the following data is used'
168             scenario                                | moduleReferences                                                       || expectedResult
169             'just new module references'            | [new ModuleReference('new1', 'r1'), new ModuleReference('new2', 'r1')] || [new ModuleReference('new1', 'r1'), new ModuleReference('new2', 'r1')]
170             'one new module,one existing reference' | [new ModuleReference('new1', 'r1'), existingModuleReference]           || [new ModuleReference('new1', 'r1')]
171             'no new module references'              | [existingModuleReference]                                              || []
172             'no module references'                  | []                                                                     || []
173             'module references collection is null'  | null                                                                   || []
174     }
175
176     def 'Retrieve schema set.'() {
177         when: 'a specific schema set is retreived'
178             def result = objectUnderTest.getSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET)
179         then: 'the result has the correct name and module(s)'
180             assert result.name == 'bookstoreSchemaSet'
181             assert result.moduleReferences == [ new ModuleReference('stores', '2020-09-15', 'org:onap:ccsdk:sample') ]
182     }
183
184     def 'Retrieve all schema sets.'() {
185         given: 'an extra schema set is stored'
186             populateNewYangResourcesNameToContentMapAndAllModuleReferences(1)
187             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', newYangResourcesNameToContentMap)
188         when: 'all schema sets are retrieved'
189             def result = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1)
190         then: 'the result contains all expected schema sets'
191             assert result.name == [ 'bookstoreSchemaSet', 'newSchema1' ]
192         cleanup:
193             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema1'])
194     }
195
196     /*
197         D E L E T E   S C H E M A   S E T   U S E - C A S E S
198      */
199
200     def 'Delete schema sets with(out) cascade.'() {
201         given: 'a schema set'
202             populateNewYangResourcesNameToContentMapAndAllModuleReferences(1)
203             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', newYangResourcesNameToContentMap)
204         and: 'optionally create anchor for the schema set'
205             if (associateWithAnchor) {
206                 cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', 'newAnchor')
207             }
208         when: 'attempt to delete the schema set'
209             try {
210                 objectUnderTest.deleteSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', cascadeDeleteAllowedOption)
211             }
212             catch (Exception e) {  // only accept correct exception when schema set cannot be deleted
213                 assert e instanceof SchemaSetInUseException && expectSchemaSetStillPresent
214             }
215         then: 'check if the dataspace still contains the new schema set or not'
216             def remainingSchemaSetNames = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).name
217             assert remainingSchemaSetNames.contains('newSchemaSet') == expectSchemaSetStillPresent
218         cleanup:
219             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet'])
220         where: 'the following options are used'
221             associateWithAnchor | cascadeDeleteAllowedOption                     || expectSchemaSetStillPresent
222             false               | CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED    || false
223             false               | CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED || false
224             true                | CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED    || false
225             true                | CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED || true
226     }
227
228     def 'Delete schema sets with shared resources.'() {
229         given: 'a new schema set'
230             populateNewYangResourcesNameToContentMapAndAllModuleReferences(1)
231             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet1', newYangResourcesNameToContentMap)
232         and: 'another schema set which shares one yang resource (module)'
233             populateNewYangResourcesNameToContentMapAndAllModuleReferences(2)
234             objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet2', newYangResourcesNameToContentMap)
235         when: 'all schema sets are retrieved'
236             def moduleRevisions = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).revision
237         then: 'both modules (revisions) are present'
238             assert moduleRevisions.containsAll(['2000-01-01', '2000-01-01'])
239         when: 'delete the second schema set that has two resources  one of which is a shared resource'
240             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet2'])
241         then: 'only the second schema set is deleted'
242             def remainingSchemaSetNames = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).name
243             assert remainingSchemaSetNames.contains('newSchemaSet1')
244             assert !remainingSchemaSetNames.contains('newSchemaSet2')
245         and: 'only the shared module (revision) remains'
246             def remainingModuleRevisions = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).revision
247             assert remainingModuleRevisions.contains('2000-01-01')
248             assert !remainingModuleRevisions.contains('2001-01-01')
249         cleanup:
250             objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet1'])
251     }
252
253     def 'Delete schema set error scenario: #scenario.'() {
254         when: 'attempt to delete a schema set where #scenario'
255             objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName, CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED)
256         then: 'an #expectedException is thrown'
257             thrown(expectedException)
258         where: 'the following data is used'
259             scenario                     | dataspaceName               | schemaSetName   || expectedException
260             'dataspace does not exist'   | 'unknown'                   | 'not-relevant'  || DataspaceNotFoundException
261             'schema set does not exists' | FUNCTIONAL_TEST_DATASPACE_1 | 'unknown'       || SchemaSetNotFoundException
262     }
263
264     /*
265         H E L P E R   M E T H O D S
266      */
267
268     def populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfModules) {
269         numberOfModules.times {
270             def uniqueName = 'name_' + it
271             def uniqueRevision = String.valueOf(2000 + it) + '-01-01'
272             moduleReferences.add(new ModuleReference(uniqueName, uniqueRevision))
273             def uniqueContent = NEW_RESOURCE_CONTENT.replace(NEW_RESOURCE_REVISION, uniqueRevision)
274             newYangResourcesNameToContentMap.put(uniqueRevision, uniqueContent)
275         }
276     }
277
278 }