aboutsummaryrefslogtreecommitdiffstats
path: root/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy
blob: f122b57634c6e37c167cf8b26a53123ac07f2af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 *  ============LICENSE_START=======================================================
 *  Copyright (C) 2023-2024 Nordix Foundation
 *  ================================================================================
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  SPDX-License-Identifier: Apache-2.0
 *  ============LICENSE_END=========================================================
 */

package org.onap.cps.ncmp.init

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.springframework.boot.SpringApplication
import org.slf4j.LoggerFactory
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Specification

class AbstractModelLoaderSpec extends Specification {

    def mockCpsDataspaceService = Mock(CpsDataspaceService)
    def mockCpsModuleService = Mock(CpsModuleService)
    def mockCpsDataService = Mock(CpsDataService)
    def mockCpsAnchorService = Mock(CpsAnchorService)
    def objectUnderTest = Spy(new TestModelLoader(mockCpsDataspaceService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService))

    def applicationContext = new AnnotationConfigApplicationContext()

    def yangResourceToContentMap
    def logger = (Logger) LoggerFactory.getLogger(AbstractModelLoader)
    def loggingListAppender

    void setup() {
        yangResourceToContentMap = objectUnderTest.createYangResourcesToContentMap('cm-data-subscriptions@2024-02-12.yang')
        logger.setLevel(Level.DEBUG)
        loggingListAppender = new ListAppender()
        logger.addAppender(loggingListAppender)
        loggingListAppender.start()
        applicationContext.refresh()
    }

    void cleanup() {
        ((Logger) LoggerFactory.getLogger(CmDataSubscriptionModelLoader.class)).detachAndStopAllAppenders()
        applicationContext.close()
    }

    def 'Application ready event'() {
        when: 'Application (ready) event is triggered'
            objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
        then: 'the onboard/upgrade method is executed'
            1 * objectUnderTest.onboardOrUpgradeModel()
    }

    def 'Application ready event with start up exception'() {
        given: 'a start up exception is thrown doing model onboarding'
            objectUnderTest.onboardOrUpgradeModel() >> { throw new NcmpStartUpException('test message','details are not logged') }
        when: 'Application (ready) event is triggered'
            objectUnderTest.onApplicationEvent(new ApplicationReadyEvent(new SpringApplication(), null, applicationContext, null))
        then: 'the exception message is logged'
            def logs = loggingListAppender.list.toString()
            assert logs.contains('test message')
    }

    def 'Wait for non-existing dataspace'() {
        when: 'wait for the dataspace'
            objectUnderTest.waitUntilDataspaceIsAvailable('some dataspace')
        then: 'a startup exception is thrown'
            def thrown = thrown(NcmpStartUpException)
            assert thrown.message.contains('Retrieval of NCMP dataspace failed')
    }

    def 'Create schema set.'() {
        when: 'creating a schema set'
            objectUnderTest.createSchemaSet('some dataspace','new name','cm-data-subscriptions@2024-02-12.yang')
        then: 'the operation is delegated to the admin service'
            1 * mockCpsModuleService.createSchemaSet('some dataspace','new name',_)
    }

    def 'Create schema set with already defined exception.'() {
        given: 'the module service throws an already defined exception'
            mockCpsModuleService.createSchemaSet(*_) >>  { throw AlreadyDefinedException.forSchemaSet('name','context',null) }
        when: 'attempt to create a schema set'
            objectUnderTest.createSchemaSet('some dataspace','new name','cm-data-subscriptions@2024-02-12.yang')
        then: 'the exception is ignored i.e. no exception thrown up'
            noExceptionThrown()
        and: 'the exception message is logged'
            def logs = loggingListAppender.list.toString()
            assert logs.contains('Creating new schema set failed as schema set already exists')
    }

    def 'Create schema set with non existing yang file.'() {
        when: 'attempt to create a schema set from a non existing file'
            objectUnderTest.createSchemaSet('some dataspace','some name','no such yang file')
        then: 'a startup exception with correct message and details is thrown'
            def thrown = thrown(NcmpStartUpException)
            assert thrown.message.contains('Creating schema set failed')
            assert thrown.details.contains('unable to read file')
    }

    def 'Delete unused schema sets.'() {
        when: 'several unused schemas are deleted '
            objectUnderTest.deleteUnusedSchemaSets('some dataspace','schema set 1', 'schema set 2')
        then: 'a request to delete each (without cascade) is delegated to the module service'
            1 * mockCpsModuleService.deleteSchemaSet('some dataspace', 'schema set 1', CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED)
            1 * mockCpsModuleService.deleteSchemaSet('some dataspace', 'schema set 2', CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED)

    }

    def 'Delete unused schema sets with exception.'() {
        given: 'deleting the first schemaset causes an exception'
            mockCpsModuleService.deleteSchemaSet(_, 'schema set 1', _) >> { throw new RuntimeException('test message')}
        when: 'several unused schemas are deleted '
            objectUnderTest.deleteUnusedSchemaSets('some dataspace','schema set 1', 'schema set 2')
        then: 'the exception message is logged'
            def logs = loggingListAppender.list.toString()
            assert logs.contains('Deleting schema set failed')
            assert logs.contains('test message')
        and: 'the second schema set is still deleted'
            1 * mockCpsModuleService.deleteSchemaSet('some dataspace', 'schema set 2', CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED)
    }

    def 'Create anchor.'() {
        when: 'creating an anchor'
            objectUnderTest.createAnchor('some dataspace','some schema set','new name')
        then: 'the operation is delegated to the admin service'
            1 * mockCpsAnchorService.createAnchor('some dataspace','some schema set', 'new name')
    }

    def 'Create anchor with already defined exception.'() {
        given: 'the admin service throws an already defined exception'
            mockCpsAnchorService.createAnchor(*_)>>  { throw AlreadyDefinedException.forAnchor('name','context',null) }
        when: 'attempt to create anchor'
            objectUnderTest.createAnchor('some dataspace','some schema set','new name')
        then: 'the exception is ignored i.e. no exception thrown up'
            noExceptionThrown()
        and: 'the exception message is logged'
            def logs = loggingListAppender.list.toString()
            assert logs.contains('Creating new anchor failed as anchor already exists')
    }

    def 'Create anchor with any other exception.'() {
        given: 'the admin service throws a exception'
            mockCpsAnchorService.createAnchor(*_)>>  { throw new RuntimeException('test message') }
        when: 'attempt to create anchor'
            objectUnderTest.createAnchor('some dataspace','some schema set','new name')
        then: 'a startup exception with correct message and details is thrown'
            def thrown = thrown(NcmpStartUpException)
            assert thrown.message.contains('Creating anchor failed')
            assert thrown.details.contains('test message')
    }

    def 'Create top level node.'() {
        when: 'top level node is created'
            objectUnderTest.createTopLevelDataNode('dataspace','anchor','new node')
        then: 'the correct json is saved using the data service'
            1 * mockCpsDataService.saveData('dataspace','anchor', '{"new node":{}}',_)
    }

    def 'Create top level node with already defined exception.'() {
        given: 'the data service throws an Already Defined exception'
            mockCpsDataService.saveData(*_) >> { throw AlreadyDefinedException.forDataNodes([], 'some context') }
        when: 'attempt to create top level node'
            objectUnderTest.createTopLevelDataNode('dataspace','anchor','new node')
        then: 'the exception is ignored i.e. no exception thrown up'
            noExceptionThrown()
        and: 'the exception message is logged'
            def logs = loggingListAppender.list.toString()
            assert logs.contains('failed as data node already exists')
    }

    def 'Create top level node with any other exception.'() {
        given: 'the data service throws an exception'
            mockCpsDataService.saveData(*_) >> { throw new RuntimeException('test message') }
        when: 'attempt to create top level node'
            objectUnderTest.createTopLevelDataNode('dataspace','anchor','new node')
        then: 'a startup exception with correct message and details is thrown'
            def thrown = thrown(NcmpStartUpException)
            assert thrown.message.contains('Creating data node failed')
            assert thrown.details.contains('test message')
    }

    def 'Update anchor schema set.'() {
        when: 'a schema set for an anchor is updated'
            objectUnderTest.updateAnchorSchemaSet('some dataspace', 'anchor', 'new schema set')
        then: 'the request is delegated to the admin service'
            1 * mockCpsAnchorService.updateAnchorSchemaSet('some dataspace', 'anchor', 'new schema set')
    }

    def 'Update anchor schema set with exception.'() {
        given: 'the admin service throws an exception'
            mockCpsAnchorService.updateAnchorSchemaSet(*_) >> { throw new RuntimeException('test message') }
        when: 'a schema set for an anchor is updated'
            objectUnderTest.updateAnchorSchemaSet('some dataspace', 'anchor', 'new schema set')
        then: 'a startup exception with correct message and details is thrown'
            def thrown = thrown(NcmpStartUpException)
            assert thrown.message.contains('Updating schema set failed')
            assert thrown.details.contains('test message')
    }

    class TestModelLoader extends AbstractModelLoader {

        TestModelLoader(final CpsDataspaceService cpsDataspaceService,
                        final CpsModuleService cpsModuleService,
                        final CpsAnchorService cpsAnchorService,
                        final CpsDataService cpsDataService) {
            super(cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService)
            super.maximumAttemptCount = 2
            super.retryTimeMs = 1
        }

        @Override
        void onboardOrUpgradeModel() { }
    }

}