1c41b4293caa0944e0f2d11b3b52f204ed0cb0c4
[cps.git] /
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
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.ncmp.impl.data.policyexecutor
22
23 import com.fasterxml.jackson.databind.ObjectMapper
24 import org.onap.cps.ncmp.api.exceptions.ProvMnSException
25 import org.onap.cps.ncmp.impl.provmns.RequestParameters
26 import org.onap.cps.ncmp.impl.provmns.model.PatchItem
27 import org.onap.cps.ncmp.impl.provmns.model.ResourceOneOf
28 import org.onap.cps.utils.JsonObjectMapper
29 import spock.lang.Specification
30
31 import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
32 import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE
33 import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE
34
35 class OperationDetailsFactorySpec extends Specification {
36
37     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
38     def requestPathParameters = new RequestParameters('some method', '/parent=1/child=2','some uri', 'class in uri', 'id in uri')
39
40     OperationDetailsFactory objectUnderTest = new OperationDetailsFactory(jsonObjectMapper)
41
42     def 'Build create operation details with all properties.'() {
43         given: 'a resource'
44             def resource = new ResourceOneOf(id: 'id in resource', objectClass: 'class in resource')
45         when: 'create operation details are built'
46             def result = objectUnderTest.buildOperationDetails(CREATE, requestPathParameters, resource)
47         then: 'all details are correct'
48             assert result.targetIdentifier == '/parent=1'
49             assert result.changeRequest.keySet()[0] == 'class in uri'
50             assert result.changeRequest['class in uri'][0].id == 'id in uri'
51     }
52
53     def 'Build replace (~create) operation details with all properties where class name in body is #scenario.'() {
54         given: 'a resource'
55             def resource = new ResourceOneOf(id: 'some resource id', objectClass: classNameInBody)
56         when: 'replace operation details are built'
57             def result = objectUnderTest.buildOperationDetails(CREATE, requestPathParameters, resource)
58         then: 'all details are correct'
59             assert result.targetIdentifier == '/parent=1'
60             assert result.changeRequest.keySet()[0] == 'class in uri'
61         where:
62             scenario    | classNameInBody
63             'populated' | 'class in body'
64             'empty'     | ''
65             'null'      | null
66     }
67
68     def 'Single patch operation with #patchOperationType checks correct operation type.'() {
69         given: 'a resource and single patch item'
70             def resource = new ResourceOneOf(id: 'some resource id')
71             def patchItem = new PatchItem(op: patchOperationType, 'path':'some uri', value: resource)
72         when: 'operation details is created'
73             def result = objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
74         then: 'it has the correct operation type (for Policy Executor check)'
75             assert result.operation() == expectedPolicyExecutorOperationType.operationName
76         where: 'following operations are used'
77             patchOperationType | expectedPolicyExecutorOperationType
78             'ADD'              | CREATE
79             'REPLACE'          | UPDATE
80             'REMOVE'           | DELETE
81     }
82
83     def 'Build policy executor patch operation details with single replace operation and #scenario.'() {
84         given: 'a patchItem'
85             def patchItem = new PatchItem(op: 'REPLACE', 'path':"some uri${suffix}", value: value)
86         when: 'patch operation details are checked'
87             def result = objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
88         then: 'Attribute Value in operation is correct'
89             result.changeRequest.values()[0].attributes[0] == expectedAttributesValueInOperation
90         where: 'attributes are set using # or resource'
91             scenario                            | suffix               | value                          || expectedAttributesValueInOperation
92             'set simple value using #'          | '#/attributes/attr1' | 1                              || [attr1:1]
93             'set complex value using resource'  | ''                   | '{"attr1":"abc","attr2":123}'  || '{"attr1":"abc","attr2":123}'
94     }
95
96     def 'Build an attribute map with different depths of hierarchy with #scenario.'() {
97         given: 'a patch item with a path'
98             def patchItem = new PatchItem(op: 'REPLACE', 'path':path, value: 123)
99         when: 'transforming the attributes'
100             def hierarchyMap = objectUnderTest.createNestedMap(patchItem)
101         then: 'the map depth is equal to the expected number of attributes'
102             assert hierarchyMap.get(expectedAttributeName).toString() == expectedAttributeValue
103         where: 'simple and complex attributes are tested'
104             scenario                                   | path                                                             || expectedAttributeName || expectedAttributeValue
105             'set a simple attribute'                   | 'myUriLdnFirstPart#/attributes/simpleAttribute'                  || 'simpleAttribute'     || '123'
106             'set a simple attribute with a trailing /' | 'myUriLdnFirstPart#/attributes/simpleAttribute/'                 || 'simpleAttribute'     || '123'
107             'set a complex attribute'                  | 'myUriLdnFirstPart#/attributes/complexAttribute/simpleAttribute' || 'complexAttribute'    || '[simpleAttribute:123]'
108     }
109
110     def 'Attempt to Build Operation details with unsupported op (MOVE).'() {
111         given: 'a patchItem'
112             def patchItem = new PatchItem(op: 'MOVE', 'path':'some uri')
113         when: 'a build is attempted with an unsupported op'
114             objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
115         then: 'the result is as expected (exception thrown)'
116             def exceptionThrown = thrown(ProvMnSException)
117             assert exceptionThrown.title == 'Unsupported Patch Operation Type: move'
118     }
119
120 }