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
9 * 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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.ncmp.impl.data.policyexecutor
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
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
35 class OperationDetailsFactorySpec extends Specification {
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')
40 OperationDetailsFactory objectUnderTest = new OperationDetailsFactory(jsonObjectMapper)
42 def 'Build create operation details with all properties.'() {
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'
53 def 'Build replace (~create) operation details with all properties where class name in body is #scenario.'() {
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'
62 scenario | classNameInBody
63 'populated' | 'class in body'
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
83 def 'Build policy executor patch operation details with single replace operation and #scenario.'() {
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}'
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]'
110 def 'Attempt to Build Operation details with unsupported op (MOVE).'() {
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'