Backend support for operation milestones with activities
[sdc.git] / catalog-be / src / test / java / org / openecomp / sdc / be / components / impl / InterfaceDefinitionHandlerTest.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 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  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.sdc.be.components.impl;
21
22 import static org.hamcrest.MatcherAssert.assertThat;
23 import static org.hamcrest.Matchers.aMapWithSize;
24 import static org.hamcrest.Matchers.containsInAnyOrder;
25 import static org.hamcrest.Matchers.equalTo;
26 import static org.hamcrest.Matchers.hasItems;
27 import static org.hamcrest.Matchers.hasSize;
28 import static org.junit.jupiter.api.Assertions.assertEquals;
29 import static org.junit.jupiter.api.Assertions.assertThrows;
30 import static org.junit.jupiter.api.Assertions.assertTrue;
31 import static org.junit.jupiter.api.Assertions.fail;
32 import static org.mockito.Mockito.lenient;
33 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT;
34 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION;
35 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED;
36 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.STATUS;
37 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE;
38
39 import com.google.gson.Gson;
40 import fj.data.Either;
41 import java.io.FileInputStream;
42 import java.io.FileNotFoundException;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
45 import java.util.Collections;
46 import java.util.HashMap;
47 import java.util.LinkedHashMap;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Map.Entry;
51 import java.util.Optional;
52 import java.util.stream.Collectors;
53 import org.apache.commons.collections.MapUtils;
54 import org.apache.commons.lang3.StringUtils;
55 import org.junit.jupiter.api.BeforeEach;
56 import org.junit.jupiter.api.Test;
57 import org.junit.jupiter.api.extension.ExtendWith;
58 import org.mockito.Mock;
59 import org.mockito.junit.jupiter.MockitoExtension;
60 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
61 import org.openecomp.sdc.be.config.ConfigurationManager;
62 import org.openecomp.sdc.be.dao.api.ActionStatus;
63 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
64 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
65 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
66 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
67 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
68 import org.openecomp.sdc.be.model.InterfaceDefinition;
69 import org.openecomp.sdc.common.api.ConfigurationSource;
70 import org.openecomp.sdc.common.impl.ExternalConfiguration;
71 import org.openecomp.sdc.common.impl.FSConfigurationSource;
72 import org.yaml.snakeyaml.Yaml;
73
74 @ExtendWith(MockitoExtension.class)
75 class InterfaceDefinitionHandlerTest {
76
77     private static final Path TEST_RESOURCE_PATH = Paths.get("src/test/resources/interfaceDefinition");
78     private static final String CREATE_OPERATION = "create";
79     private static final String DELETE_OPERATION = "delete";
80     private static final String START_OPERATION = "start";
81     private static final String STOP_OPERATION = "stop";
82     private static final String INTERFACE_TYPE = "tosca.interfaces.node.lifecycle.Standard";
83     static ConfigurationSource
84         configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), "src/test/resources/config/catalog-be");
85     static ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
86     @Mock
87     private InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
88     private InterfaceDefinitionHandler interfaceDefinitionHandler;
89     private InterfaceDefinition interfaceLifecyleStandard;
90
91     @BeforeEach
92     void setUp() {
93         interfaceDefinitionHandler = new InterfaceDefinitionHandler(interfaceOperationBusinessLogic);
94         mockAllInterfacesLifecycle();
95     }
96
97     private void mockAllInterfacesLifecycle() {
98         final Map<String, InterfaceDefinition> interfaceTypes = new HashMap<>();
99         interfaceLifecyleStandard = new InterfaceDefinition();
100         interfaceLifecyleStandard.setType(INTERFACE_TYPE);
101         final Map<String, OperationDataDefinition> operations = new HashMap<>();
102         operations.put(CREATE_OPERATION, new OperationDataDefinition());
103         operations.put(START_OPERATION, new OperationDataDefinition());
104         operations.put(STOP_OPERATION, new OperationDataDefinition());
105         operations.put(DELETE_OPERATION, new OperationDataDefinition());
106         interfaceLifecyleStandard.setOperations(operations);
107         interfaceTypes.put(INTERFACE_TYPE, interfaceLifecyleStandard);
108         lenient().when(interfaceOperationBusinessLogic.getAllInterfaceLifecycleTypes(StringUtils.EMPTY)).thenReturn(Either.left(interfaceTypes));
109     }
110
111     @Test
112     void testCreateWithLegacyOperationDeclarationSuccess() throws FileNotFoundException {
113         final Map<String, Object> load = loadYaml(Paths.get("interfaceDefinition-legacy.yaml"));
114         final InterfaceDefinition actualInterfaceDefinition = interfaceDefinitionHandler.create(load, StringUtils.EMPTY);
115         assertInterfaceDefinition(actualInterfaceDefinition);
116     }
117
118     @Test
119     void testCreateWithOperationSuccess() throws FileNotFoundException {
120         final Map<String, Object> load = loadYaml(Paths.get("interfaceDefinition-tosca1.3.yaml"));
121         final InterfaceDefinition actualInterfaceDefinition = interfaceDefinitionHandler.create(load, StringUtils.EMPTY);
122         assertInterfaceDefinition(actualInterfaceDefinition);
123     }
124
125     @Test
126     void testCreateWithOperationFailMilestones() throws FileNotFoundException {
127         final Map<String, Object> load = loadYaml(Paths.get("interfaceDefinitionInvalidMilestone-tosca1.3.yaml"));
128         final ByActionStatusComponentException actualException =
129             assertThrows(ByActionStatusComponentException.class, () -> interfaceDefinitionHandler.create(load, StringUtils.EMPTY));
130         assertEquals(ActionStatus.INVALID_OPERATION_MILESTONE, actualException.getActionStatus());
131         assertEquals(1, actualException.getParams().length);
132         assertEquals("on_failure", actualException.getParams()[0]);
133     }
134
135     private void assertInterfaceDefinition(final InterfaceDefinition actualInterfaceDefinition) {
136         interfaceLifecyleStandard.getOperations().keySet().forEach(operation ->
137             assertTrue(actualInterfaceDefinition.hasOperation(operation)));
138         assertThat("Interface type should be as expected", actualInterfaceDefinition.getType(),
139             equalTo(actualInterfaceDefinition.getType()));
140         assertThat("Interface should contain 2 inputs", actualInterfaceDefinition.getInputs(), aMapWithSize(2));
141         assertThat("Interface inputs should be as expected", actualInterfaceDefinition.getInputs().keySet(),
142             containsInAnyOrder("stringInput", "actionInput"));
143
144         final InputDataDefinition stringInput = actualInterfaceDefinition.getInputs().get("stringInput");
145         assertInput("string", "stringInput description", true, "defaultValue", "aStatus", stringInput);
146         final InputDataDefinition actionInput = actualInterfaceDefinition.getInputs().get("actionInput");
147         assertInput("org.openecomp.resource.datatypes.Action", null, false, null, null, actionInput);
148
149         final OperationDataDefinition createOperation = actualInterfaceDefinition.getOperations().get(CREATE_OPERATION);
150         assertOperation("'camunda/serviceSelect'", createOperation);
151
152         final OperationDataDefinition deleteOperation = actualInterfaceDefinition.getOperations().get(DELETE_OPERATION);
153         assertOperation("'camunda/serviceDeselect'", deleteOperation);
154
155         final Map<String, Map<String, Object>> startOperationExpectedInputMap = createStartOperationInputMap();
156         final OperationDataDefinition startOperation = actualInterfaceDefinition.getOperations().get(START_OPERATION);
157         assertOperation("'camunda/executeAction'", startOperationExpectedInputMap, startOperation);
158         final Map<String, Map<String, Object>> stopOperationExpectedInputMap = createStopOperationInputMap();
159         final OperationDataDefinition stopOperation = actualInterfaceDefinition.getOperations().get(STOP_OPERATION);
160         assertOperation("'camunda/executeAction'", stopOperationExpectedInputMap, stopOperation);
161     }
162
163     private Map<String, Map<String, Object>> createStopOperationInputMap() {
164         final Map<String, Map<String, Object>> stopOperationExpectedInputMap = new HashMap<>();
165         final Map<String, Object> actionInput = Map.of(
166             "type", "org.openecomp.resource.datatypes.Action"
167         );
168         stopOperationExpectedInputMap.put("action", actionInput);
169         return stopOperationExpectedInputMap;
170     }
171
172     private Map<String, Map<String, Object>> createStartOperationInputMap() {
173         final Map<String, Map<String, Object>> startOperationExpectedInputMap = new HashMap<>();
174         final Map<String, Object> actionInput = Map.of(
175             "type", "org.openecomp.resource.datatypes.Action"
176         );
177         startOperationExpectedInputMap.put("action", actionInput);
178         final Map<String, Object> stringInput = Map.of(
179             "type", "string",
180             "default", "this is a string"
181         );
182         startOperationExpectedInputMap.put("stringInput", stringInput);
183         final Map<String, Object> booleanInput = Map.of(
184             "type", "boolean",
185             "default", true
186         );
187         startOperationExpectedInputMap.put("booleanInput", booleanInput);
188         final Map<String, Object> integerInput = Map.of(
189             "type", "integer",
190             "description", "an integer",
191             "status", "supported",
192             "required", true,
193             "default", 11
194         );
195         startOperationExpectedInputMap.put("integerInput", integerInput);
196         final Map<String, Object> floatInput = Map.of(
197             "type", "float",
198             "required", false,
199             "default", 11.1
200         );
201         startOperationExpectedInputMap.put("floatInput", floatInput);
202
203         final LinkedHashMap<String, Object> complexInputDefault = new LinkedHashMap<>();
204         complexInputDefault.put("dsl_stability_profile", "dsl_stability_profile_value");
205         complexInputDefault.put("central_splitter", false);
206         complexInputDefault.put("service_restoration_sla", "service_restoration_sla_value");
207         complexInputDefault.put("battery_backup", true);
208         complexInputDefault.put("partner_priorty_assist", false);
209         final Map<String, Object> complexInput = Map.of(
210             "type", "onap.datatypes.partner.access_details",
211             "status", "experimental",
212             "default", complexInputDefault
213         );
214         startOperationExpectedInputMap.put("complexInput", complexInput);
215         return startOperationExpectedInputMap;
216     }
217
218     private void assertOperation(final String implementation, final OperationDataDefinition actualOperation) {
219         assertOperation(implementation, Collections.emptyMap(), actualOperation);
220     }
221
222     private void assertOperation(final String implementation, final Map<String, Map<String, Object>> inputNameTypeMap,
223                                  final OperationDataDefinition actualOperation) {
224         final ArtifactDataDefinition artifactDefinition = actualOperation.getImplementation();
225         assertThat("Implementation should be as expected", artifactDefinition.getArtifactName(), equalTo(implementation));
226         final ListDataDefinition<OperationInputDefinition> inputListDataDef = actualOperation.getInputs();
227         if (inputListDataDef == null) {
228             if (MapUtils.isNotEmpty(inputNameTypeMap)) {
229                 final String expectedInputNames = String.join(",", inputNameTypeMap.keySet());
230                 fail(String.format("No inputs were found, but some inputs are expected: %s", expectedInputNames));
231             }
232             return;
233         }
234
235         final String msgFormat = "Operation should have %s";
236         final List<OperationInputDefinition> inputList = inputListDataDef.getListToscaDataDefinition();
237         assertThat(String.format(msgFormat, "the expected quantity of inputs"), inputList, hasSize(inputNameTypeMap.size()));
238
239         final List<String> inputNames = inputList.stream()
240             .map(OperationInputDefinition::getName).collect(Collectors.toList());
241
242         assertThat(String.format(msgFormat, "the expected inputs"), inputNames,
243             hasItems(inputNameTypeMap.keySet().toArray(new String[0])));
244
245         for (final Entry<String, Map<String, Object>> inputEntry : inputNameTypeMap.entrySet()) {
246             final String expectedInputName = inputEntry.getKey();
247             final Optional<OperationInputDefinition> inputDefinitionOptional = inputList.stream()
248                 .filter(operationInputDefinition -> operationInputDefinition.getName().equals(expectedInputName)).findFirst();
249             assertTrue(inputDefinitionOptional.isPresent(), String.format("Input '%s' should be present", expectedInputName));
250             final OperationInputDefinition actualInputDefinition = inputDefinitionOptional.get();
251             final Map<String, Object> expectedInput = inputEntry.getValue();
252
253             assertEquals(expectedInput.get(STATUS.getElementName()), actualInputDefinition.getStatus(),
254                 String.format("%s attribute of input %s should be as expected", STATUS.getElementName(), expectedInputName)
255             );
256             assertEquals(expectedInput.get(TYPE.getElementName()), actualInputDefinition.getType(),
257                 String.format("%s attribute of input %s should be as expected", TYPE.getElementName(), expectedInputName)
258             );
259             assertEquals(expectedInput.get(DESCRIPTION.getElementName()), actualInputDefinition.getDescription(),
260                 String.format("%s attribute of input %s should be as expected", DESCRIPTION.getElementName(), expectedInputName)
261             );
262             final Object expectedRequired =
263                 expectedInput.get(REQUIRED.getElementName()) == null ? false : expectedInput.get(REQUIRED.getElementName());
264             assertEquals(expectedRequired, actualInputDefinition.getRequired(),
265                 String.format("%s attribute of input %s should be as expected", REQUIRED.getElementName(), expectedInputName)
266             );
267
268             String expectedJson = null;
269             if (expectedInput.get(DEFAULT.getElementName()) != null) {
270                 expectedJson = new Gson().toJson(expectedInput.get(DEFAULT.getElementName()));
271             }
272             assertEquals(expectedJson, actualInputDefinition.getToscaDefaultValue(),
273                 String.format("%s of input %s should be as expected", DEFAULT.getElementName(), expectedInputName)
274             );
275         }
276     }
277
278     private void assertInput(final String type, final String description, final Boolean required,
279                              final String defaultValue, final String status, final InputDataDefinition actualInput) {
280         assertThat("Input type should be as expected", type, equalTo(actualInput.getType()));
281         assertThat("Input description should be as expected", description, equalTo(actualInput.getDescription()));
282         assertThat("Input required should be as expected", required, equalTo(required != null && required));
283         assertThat("Input default should be as expected", defaultValue, equalTo(actualInput.getDefaultValue()));
284         assertThat("Input status should be as expected", status, equalTo(actualInput.getStatus()));
285     }
286
287     private Map<String, Object> loadYaml(final Path filePathFromResource) throws FileNotFoundException {
288         final Path filePath = Paths.get(TEST_RESOURCE_PATH.toString(), filePathFromResource.toString());
289         final FileInputStream fileInputStream = new FileInputStream(filePath.toString());
290         return new Yaml().load(fileInputStream);
291     }
292 }