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=id1/someChild=someId','some uri', 'class from uri', 'id from uri')
40 OperationDetailsFactory objectUnderTest = new OperationDetailsFactory(jsonObjectMapper)
42 def 'Build replace (~create) operation details with all properties where class name in body is #scenario.'() {
44 def resource = new ResourceOneOf(id: 'some resource id', objectClass: classNameInBody)
45 when: 'replace operation details are built'
46 def result = objectUnderTest.buildOperationDetails(CREATE, requestPathParameters, resource)
47 then: 'all details are correct'
48 assert result.parentFdn == '/parent=id1'
49 assert result.className == 'class from uri'
50 assert result.ClassInstances[0].id == 'id from uri'
52 scenario | classNameInBody
53 'populated' | 'class in body'
58 def 'Single patch operation with #patchOperationType checks correct operation type.'() {
59 given: 'a resource and single patch item'
60 def resource = new ResourceOneOf(id: 'some resource id')
61 def patchItem = new PatchItem(op: patchOperationType, 'path':'some uri', value: resource)
62 when: 'operation details is created'
63 def result = objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
64 then: 'it has the correct operation type (for Policy Executor check)'
65 assert result.operationType == expectedPolicyExecutorOperationType
66 where: 'following operations are used'
67 patchOperationType | expectedPolicyExecutorOperationType
73 def 'Build policy executor patch operation details with single replace operation and #scenario.'() {
75 def patchItem = new PatchItem(op: 'REPLACE', 'path':"some uri${suffix}", value: value)
76 when: 'patch operation details are checked'
77 def result = objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
78 then: 'Attribute value is correct'
79 result.ClassInstances[0].attributes == [attr1:456]
80 where: 'attributes are set using # or resource'
81 scenario | suffix | value
82 'set simple value using #' | '#/attributes/attr1' | 456
83 'set complex value using resource' | '' | [id:'id1', attributes:[attr1:456]]
86 def 'Build an attribute map with different depths of hierarchy with #scenario.'() {
87 given: 'a patch item with a path'
88 def patchItem = new PatchItem(op: 'REPLACE', 'path':path, value: 123)
89 when: 'transforming the attributes'
90 def hierarchyMap = objectUnderTest.createNestedMap(patchItem)
91 then: 'the map depth is equal to the expected number of attributes'
92 assert hierarchyMap.get(expectedAttributeName).toString() == expectedAttributeValue
93 where: 'simple and complex attributes are tested'
94 scenario | path || expectedAttributeName || expectedAttributeValue
95 'set a simple attribute' | 'myUriLdnFirstPart#/attributes/simpleAttribute' || 'simpleAttribute' || '123'
96 'set a simple attribute with a trailing /' | 'myUriLdnFirstPart#/attributes/simpleAttribute/' || 'simpleAttribute' || '123'
97 'set a complex attribute' | 'myUriLdnFirstPart#/attributes/complexAttribute/simpleAttribute' || 'complexAttribute' || '[simpleAttribute:123]'
100 def 'Attempt to Build Operation details with unsupported op (MOVE).'() {
102 def patchItem = new PatchItem(op: 'MOVE', 'path':'some uri')
103 when: 'a build is attempted with an unsupported op'
104 objectUnderTest.buildOperationDetails(requestPathParameters, patchItem)
105 then: 'the result is as expected (exception thrown)'
106 def exceptionThrown = thrown(ProvMnSException)
107 assert exceptionThrown.title == 'Unsupported Patch Operation Type: move'