3 * ============LICENSE_START=======================================================
4 * Copyright (C) 2022 Nordix Foundation.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.openecomp.sdc.be.components.impl.validation;
24 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.mockito.Mockito.never;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
32 import fj.data.Either;
33 import java.util.HashMap;
34 import java.util.List;
36 import java.util.Map.Entry;
37 import java.util.stream.Stream;
38 import org.apache.commons.collections4.CollectionUtils;
39 import org.apache.commons.collections4.MapUtils;
40 import org.junit.jupiter.api.BeforeAll;
41 import org.junit.jupiter.api.BeforeEach;
42 import org.junit.jupiter.api.Test;
43 import org.junit.jupiter.params.ParameterizedTest;
44 import org.junit.jupiter.params.provider.Arguments;
45 import org.junit.jupiter.params.provider.MethodSource;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
49 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
50 import org.openecomp.sdc.be.components.impl.exceptions.ToscaFunctionExceptionSupplier;
51 import org.openecomp.sdc.be.components.impl.exceptions.ToscaGetFunctionExceptionSupplier;
52 import org.openecomp.sdc.be.config.ConfigurationManager;
53 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
54 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
55 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
56 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
57 import org.openecomp.sdc.be.model.Component;
58 import org.openecomp.sdc.be.model.ComponentInstance;
59 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
60 import org.openecomp.sdc.be.model.DataTypeDefinition;
61 import org.openecomp.sdc.be.model.InputDefinition;
62 import org.openecomp.sdc.be.model.LifecycleStateEnum;
63 import org.openecomp.sdc.be.model.PropertyDefinition;
64 import org.openecomp.sdc.be.model.Service;
65 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
66 import org.openecomp.sdc.common.api.ConfigurationSource;
67 import org.openecomp.sdc.common.impl.ExternalConfiguration;
68 import org.openecomp.sdc.common.impl.FSConfigurationSource;
70 class ToscaFunctionValidatorImplTest {
73 private ApplicationDataTypeCache applicationDataTypeCache;
75 private ToscaFunctionValidatorImpl toscaFunctionValidator;
78 static void beforeAll() {
82 private static void initConfig() {
83 final ConfigurationSource configurationSource = new FSConfigurationSource(
84 ExternalConfiguration.getChangeListener(),
85 "src/test/resources/config/catalog-be"
87 new ConfigurationManager(configurationSource);
92 MockitoAnnotations.openMocks(this);
93 toscaFunctionValidator = new ToscaFunctionValidatorImpl(applicationDataTypeCache);
97 void testToscaGetFunctionValidation() {
98 final String containerComponentId = "containerComponentId";
99 final String containerComponentName = "containerComponentName";
100 final String resourceInstanceId = "resourceInstanceId";
101 final String inputName = "myInputToGet";
102 final String inputId = String.format("%s.%s", containerComponentId, inputName);
103 final String schemaType = "string";
104 //creating instance list of string property with get_input value
105 final ComponentInstanceProperty propertyGetInput = new ComponentInstanceProperty();
106 propertyGetInput.setName("getInputProperty");
107 propertyGetInput.setPropertyId(String.format("%s.%s", containerComponentId, "getInputProperty"));
108 propertyGetInput.setValue(String.format("get_input: [\"%s\"]", inputName));
109 propertyGetInput.setType("list");
110 final SchemaDefinition listStringPropertySchema = createSchema(schemaType);
111 propertyGetInput.setSchema(listStringPropertySchema);
112 propertyGetInput.setToscaFunction(
113 createGetToscaFunction(inputName, inputId, List.of(propertyGetInput.getName()), PropertySource.SELF, ToscaGetFunctionType.GET_INPUT,
114 containerComponentId, containerComponentName)
116 //creating instance map of string property with get_input value to a second level property:
117 // get_input: ["property1", "subProperty1", "subProperty2"]
118 final String getPropertyPropertyName = "getPropertyProperty";
119 final List<String> containerPropertyPath = List.of("property1", "subProperty1", "subProperty2");
120 final String containerPropertyId = String.format("%s.%s", containerComponentId, containerPropertyPath.get(0));
121 final String mapToscaType = "map";
122 final ComponentInstanceProperty propertyGetProperty = createComponentInstanceProperty(
123 String.format("%s.%s", containerComponentId, getPropertyPropertyName),
124 getPropertyPropertyName,
127 String.format("\"get_property\": [\"%s\", \"%s\"]", PropertySource.SELF, String.join("\", \"", containerPropertyPath)),
128 createGetToscaFunction(containerPropertyPath.get(containerPropertyPath.size() - 1), containerPropertyId,
129 containerPropertyPath, PropertySource.SELF, ToscaGetFunctionType.GET_PROPERTY, containerComponentId, containerComponentName)
132 //creating component that has the instance properties
133 final Component component = new Service();
134 component.setUniqueId(containerComponentId);
135 component.setName(containerComponentName);
136 //adding instance properties to the component
137 final List<ComponentInstanceProperty> resourceInstanceProperties = List.of(propertyGetInput, propertyGetProperty);
138 final Map<String, List<ComponentInstanceProperty>> componentInstanceProps = new HashMap<>();
139 componentInstanceProps.put(resourceInstanceId, resourceInstanceProperties);
140 component.setComponentInstancesProperties(componentInstanceProps);
142 //creating component input that will be gotten by the get_input instance property
143 final var inputDefinition = new InputDefinition();
144 inputDefinition.setName(inputName);
145 inputDefinition.setUniqueId(inputId);
146 inputDefinition.setType(propertyGetInput.getType());
147 inputDefinition.setSchema(listStringPropertySchema);
148 component.setInputs(List.of(inputDefinition));
150 //creating component property that contains the sub property that will be gotten by the get_property instance property
151 final var propertyDefinition = new PropertyDefinition();
152 propertyDefinition.setName(containerPropertyPath.get(0));
153 propertyDefinition.setUniqueId(containerPropertyId);
154 final String property1Type = "property1.datatype";
155 propertyDefinition.setType(property1Type);
156 component.setProperties(List.of(propertyDefinition));
157 //creating resource instance to be added to the component
158 final ComponentInstance resourceInstance = createComponentInstance("resourceInstance", resourceInstanceId);
159 component.setComponentInstances(List.of(resourceInstance));
161 //creating data types for "map", and sub properties
162 final Map<String, DataTypeDefinition> allDataTypesMap = new HashMap<>();
163 allDataTypesMap.put(mapToscaType, new DataTypeDefinition());
165 final String subProperty1Type = "subProperty1.datatype";
166 allDataTypesMap.put(property1Type, createDataType(property1Type, Map.of(containerPropertyPath.get(1), subProperty1Type)));
168 final var subProperty2Property = new PropertyDefinition();
169 subProperty2Property.setName(containerPropertyPath.get(2));
170 subProperty2Property.setType(propertyGetProperty.getType());
171 subProperty2Property.setSchema(propertyGetProperty.getSchema());
172 allDataTypesMap.put(subProperty1Type, createDataType(subProperty1Type, List.of(subProperty2Property)));
174 when(applicationDataTypeCache.getAll(component.getModel())).thenReturn(Either.left(allDataTypesMap));
176 assertDoesNotThrow(() -> toscaFunctionValidator.validate(propertyGetProperty, component));
177 verify(applicationDataTypeCache).getAll(component.getModel());
181 void testToscaGetPropertyOnInstanceValidation() {
182 final String userId = "userId";
183 final String containerComponentId = "containerComponentId";
184 final String containerComponentName = "containerComponentName";
185 final String instanceUniqueId = String.format("%s.%s", containerComponentId, "instanceId");
187 final List<String> parentPropertyPath = List.of("property1");
188 final String containerPropertyId = String.format("%s.%s", containerComponentId, parentPropertyPath.get(0));
189 final ComponentInstanceProperty getPropertyOnInstanceProperty = createComponentInstanceProperty(
190 String.format("%s.%s", containerComponentId, "getPropertyOnInstanceProperty"),
191 "getPropertyOnInstanceProperty",
194 String.format("\"get_property\": [\"%s\", \"%s\"]", PropertySource.INSTANCE, parentPropertyPath.get(0)),
195 createGetToscaFunction(parentPropertyPath.get(0), containerPropertyId, parentPropertyPath, PropertySource.INSTANCE,
196 ToscaGetFunctionType.GET_PROPERTY, instanceUniqueId, containerComponentName)
199 //creating component that has the instance properties
200 final Component component = new Service();
201 component.setUniqueId(containerComponentId);
202 component.setName(containerComponentName);
203 component.setLastUpdaterUserId(userId);
204 component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
205 //adding instance properties to the component
206 final List<ComponentInstanceProperty> resourceInstanceProperties = List.of(getPropertyOnInstanceProperty);
207 final Map<String, List<ComponentInstanceProperty>> componentInstanceProps = new HashMap<>();
208 componentInstanceProps.put(instanceUniqueId, resourceInstanceProperties);
209 component.setComponentInstancesProperties(componentInstanceProps);
211 //creating resource property that will be get
212 final var propertyDefinition = new PropertyDefinition();
213 propertyDefinition.setName(parentPropertyPath.get(0));
214 propertyDefinition.setUniqueId(containerPropertyId);
215 final String property1Type = "string";
216 propertyDefinition.setType(property1Type);
217 //creating resource instance to be added to the component
218 final ComponentInstance resourceInstance = createComponentInstance("resourceInstance", instanceUniqueId);
219 resourceInstance.setProperties(List.of(propertyDefinition));
220 component.setComponentInstances(List.of(resourceInstance));
222 assertDoesNotThrow(() -> toscaFunctionValidator.validate(getPropertyOnInstanceProperty, component));
223 verify(applicationDataTypeCache, never()).getAll(component.getModel());
227 @MethodSource("getToscaFunctionForValidation")
228 void validateToscaGetFunctionFailures(final ToscaGetFunctionDataDefinition toscaGetFunction,
229 final ByActionStatusComponentException expectedException) {
230 final ComponentInstanceProperty propertyGetInput = new ComponentInstanceProperty();
231 propertyGetInput.setName("anyName");
232 propertyGetInput.setToscaFunction(toscaGetFunction);
233 final Component component = new Service();
234 final ComponentException actualException = assertThrows(ComponentException.class,
235 () -> toscaFunctionValidator.validate(propertyGetInput, component));
236 assertEquals(expectedException.getActionStatus(), actualException.getActionStatus());
237 assertArrayEquals(expectedException.getParams(), actualException.getParams());
241 void validate_propertyNotFoundTest() {
243 final String containerComponentId = "containerComponentId";
244 final String containerComponentName = "containerComponentName";
245 final String inputName = "myInputToGet";
246 final String inputId = String.format("%s.%s", containerComponentId, inputName);
247 final String propertyName = "getInputProperty";
248 final String propertyId = String.format("%s.%s", containerComponentId, propertyName);
249 final String propertyType = "string";
250 final ComponentInstanceProperty propertyGetInput = createComponentInstanceProperty(
255 String.format("get_input: [\"%s\"]", inputName),
256 createGetToscaFunction(inputName, inputId, List.of(propertyName), PropertySource.SELF, ToscaGetFunctionType.GET_INPUT,
257 containerComponentId, containerComponentName)
260 final Component component = new Service();
261 final InputDefinition inputDefinition = new InputDefinition();
262 inputDefinition.setUniqueId(inputId + "1");
263 component.setInputs(List.of(inputDefinition));
266 final ByActionStatusComponentException actualException = assertThrows(ByActionStatusComponentException.class,
267 () -> toscaFunctionValidator.validate(propertyGetInput, component));
269 final ByActionStatusComponentException expectedException =
270 ToscaGetFunctionExceptionSupplier
271 .propertyNotFoundOnTarget(inputName, PropertySource.SELF, ToscaGetFunctionType.GET_INPUT)
273 assertEquals(expectedException.getActionStatus(), actualException.getActionStatus());
274 assertArrayEquals(expectedException.getParams(), actualException.getParams());
278 void validate_schemaDivergeTest() {
280 final String containerComponentId = "containerComponentId";
281 final String containerComponentName = "containerComponentName";
282 final String inputName = "myInputToGet";
283 final String inputId = String.format("%s.%s", containerComponentId, inputName);
284 final String propertyName = "getInputProperty";
285 final String propertyId = String.format("%s.%s", containerComponentId, propertyName);
286 final String propertyType = "list";
287 final ComponentInstanceProperty propertyGetInput = createComponentInstanceProperty(
292 String.format("get_input: [\"%s\"]", inputName),
293 createGetToscaFunction(inputName, inputId, List.of(propertyName), PropertySource.SELF, ToscaGetFunctionType.GET_INPUT,
294 containerComponentId, containerComponentName)
297 final Component component = new Service();
298 component.setUniqueId(containerComponentId);
299 component.setName(containerComponentName);
301 var inputDefinition = new InputDefinition();
302 inputDefinition.setName(inputName);
303 inputDefinition.setUniqueId(inputId);
304 inputDefinition.setType(propertyType);
305 inputDefinition.setSchema(createSchema("integer"));
306 component.setInputs(List.of(inputDefinition));
309 final ByActionStatusComponentException actualException = assertThrows(ByActionStatusComponentException.class,
310 () -> toscaFunctionValidator.validate(propertyGetInput, component));
312 final ByActionStatusComponentException expectedException =
313 ToscaGetFunctionExceptionSupplier
314 .propertySchemaDiverge(propertyGetInput.getToscaFunction().getType(), inputDefinition.getSchemaType(),
315 propertyGetInput.getSchemaType())
317 assertEquals(expectedException.getActionStatus(), actualException.getActionStatus());
318 assertArrayEquals(expectedException.getParams(), actualException.getParams());
322 void validate_propertyTypeDivergeTest() {
324 final String containerComponentId = "containerComponentId";
325 final String containerComponentName = "containerComponentName";
326 final String inputName = "myInputToGet";
327 final String inputId = String.format("%s.%s", containerComponentId, inputName);
328 final String propertyName = "getInputProperty";
329 final String propertyId = String.format("%s.%s", containerComponentId, propertyName);
330 final String propertyType = "string";
332 final ComponentInstanceProperty propertyGetInput = createComponentInstanceProperty(
337 String.format("get_input: [\"%s\"]", inputName),
338 createGetToscaFunction(inputName, inputId, List.of(propertyName), PropertySource.SELF, ToscaGetFunctionType.GET_INPUT,
339 containerComponentId, containerComponentName)
342 final Component component = new Service();
343 component.setName(containerComponentName);
344 component.setUniqueId(containerComponentId);
346 var inputDefinition = new InputDefinition();
347 inputDefinition.setName(inputName);
348 inputDefinition.setUniqueId(inputId);
349 inputDefinition.setType("integer");
350 component.setInputs(List.of(inputDefinition));
353 final ByActionStatusComponentException actualException = assertThrows(ByActionStatusComponentException.class,
354 () -> toscaFunctionValidator.validate(propertyGetInput, component));
356 final ByActionStatusComponentException expectedException =
357 ToscaGetFunctionExceptionSupplier
358 .propertyTypeDiverge(propertyGetInput.getToscaFunction().getType(), inputDefinition.getType(), propertyGetInput.getType())
360 assertEquals(expectedException.getActionStatus(), actualException.getActionStatus());
361 assertArrayEquals(expectedException.getParams(), actualException.getParams());
364 private static Stream<Arguments> getToscaFunctionForValidation() {
365 final var toscaGetFunction1 = new ToscaGetFunctionDataDefinition();
366 final ByActionStatusComponentException expectedResponse1 = ToscaFunctionExceptionSupplier
367 .missingFunctionType().get();
369 final var toscaGetFunction2 = new ToscaGetFunctionDataDefinition();
370 toscaGetFunction2.setFunctionType(ToscaGetFunctionType.GET_INPUT);
371 final ByActionStatusComponentException expectedResponse2 = ToscaGetFunctionExceptionSupplier
372 .targetPropertySourceNotFound(toscaGetFunction2.getFunctionType()).get();
374 final var toscaGetFunction3 = new ToscaGetFunctionDataDefinition();
375 toscaGetFunction3.setFunctionType(ToscaGetFunctionType.GET_INPUT);
376 toscaGetFunction3.setPropertySource(PropertySource.SELF);
377 final ByActionStatusComponentException expectedResponse3 = ToscaGetFunctionExceptionSupplier
378 .targetSourcePathNotFound(toscaGetFunction3.getFunctionType()).get();
380 final var toscaGetFunction4 = new ToscaGetFunctionDataDefinition();
381 toscaGetFunction4.setFunctionType(ToscaGetFunctionType.GET_INPUT);
382 toscaGetFunction4.setPropertySource(PropertySource.SELF);
383 toscaGetFunction4.setPropertyPathFromSource(List.of("sourcePath"));
384 final ByActionStatusComponentException expectedResponse4 = ToscaGetFunctionExceptionSupplier
385 .sourceNameNotFound(toscaGetFunction4.getPropertySource()).get();
387 final var toscaGetFunction5 = new ToscaGetFunctionDataDefinition();
388 toscaGetFunction5.setFunctionType(ToscaGetFunctionType.GET_INPUT);
389 toscaGetFunction5.setPropertySource(PropertySource.SELF);
390 toscaGetFunction5.setPropertyPathFromSource(List.of("sourcePath"));
391 toscaGetFunction5.setSourceName("sourceName");
392 final ByActionStatusComponentException expectedResponse5 = ToscaGetFunctionExceptionSupplier
393 .sourceIdNotFound(toscaGetFunction5.getPropertySource()).get();
395 final var toscaGetFunction6 = new ToscaGetFunctionDataDefinition();
396 toscaGetFunction6.setFunctionType(ToscaGetFunctionType.GET_PROPERTY);
397 toscaGetFunction6.setPropertySource(PropertySource.SELF);
398 toscaGetFunction6.setPropertyPathFromSource(List.of("sourcePath"));
399 toscaGetFunction6.setSourceName("sourceName");
400 toscaGetFunction6.setSourceUniqueId("sourceUniqueId");
401 final ByActionStatusComponentException expectedResponse6 = ToscaGetFunctionExceptionSupplier
402 .propertyNameNotFound(toscaGetFunction6.getPropertySource()).get();
404 final var toscaGetFunction7 = new ToscaGetFunctionDataDefinition();
405 toscaGetFunction7.setFunctionType(ToscaGetFunctionType.GET_PROPERTY);
406 toscaGetFunction7.setPropertySource(PropertySource.SELF);
407 toscaGetFunction7.setPropertyPathFromSource(List.of("sourcePath"));
408 toscaGetFunction7.setSourceName("sourceName");
409 toscaGetFunction7.setSourceUniqueId("sourceUniqueId");
410 toscaGetFunction7.setPropertyName("propertyName");
411 final ByActionStatusComponentException expectedResponse7 = ToscaGetFunctionExceptionSupplier
412 .propertyIdNotFound(toscaGetFunction7.getPropertySource()).get();
415 Arguments.of(toscaGetFunction1, expectedResponse1),
416 Arguments.of(toscaGetFunction2, expectedResponse2),
417 Arguments.of(toscaGetFunction3, expectedResponse3),
418 Arguments.of(toscaGetFunction4, expectedResponse4),
419 Arguments.of(toscaGetFunction5, expectedResponse5),
420 Arguments.of(toscaGetFunction6, expectedResponse6),
421 Arguments.of(toscaGetFunction7, expectedResponse7)
425 private ComponentInstanceProperty createComponentInstanceProperty(final String uniqueId, final String name, final String type,
426 final String schemaType, final String value,
427 final ToscaGetFunctionDataDefinition toscaGetFunction) {
428 final var componentInstanceProperty = new ComponentInstanceProperty();
429 componentInstanceProperty.setName(name);
430 componentInstanceProperty.setUniqueId(uniqueId);
431 componentInstanceProperty.setType(type);
432 componentInstanceProperty.setValue(value);
433 if (schemaType != null) {
434 final SchemaDefinition schemaDefinition = createSchema(schemaType);
435 componentInstanceProperty.setSchema(schemaDefinition);
437 if (toscaGetFunction != null) {
438 componentInstanceProperty.setToscaFunction(toscaGetFunction);
441 return componentInstanceProperty;
444 private SchemaDefinition createSchema(final String schemaType) {
445 final var schemaDefinition = new SchemaDefinition();
446 final var schemaProperty = new PropertyDefinition();
447 schemaProperty.setType(schemaType);
448 schemaDefinition.setProperty(schemaProperty);
449 return schemaDefinition;
452 private ToscaGetFunctionDataDefinition createGetToscaFunction(final String propertyName, final String propertyUniqueId,
453 final List<String> propertyPathFromSource,
454 final PropertySource propertySource, final ToscaGetFunctionType functionType,
455 final String sourceUniqueId,
456 final String sourceName) {
457 final var toscaGetFunction = new ToscaGetFunctionDataDefinition();
458 toscaGetFunction.setFunctionType(functionType);
459 toscaGetFunction.setPropertyUniqueId(propertyUniqueId);
460 toscaGetFunction.setPropertyName(propertyName);
461 toscaGetFunction.setPropertyPathFromSource(propertyPathFromSource);
462 toscaGetFunction.setPropertySource(propertySource);
463 toscaGetFunction.setSourceName(sourceName);
464 toscaGetFunction.setSourceUniqueId(sourceUniqueId);
465 return toscaGetFunction;
468 private DataTypeDefinition createDataType(final String name, final Map<String, String> propertyNameAndTypeMap) {
469 final var dataTypeDefinition = new DataTypeDefinition();
470 dataTypeDefinition.setName(name);
471 if (MapUtils.isNotEmpty(propertyNameAndTypeMap)) {
472 for (final Entry<String, String> propertyEntry : propertyNameAndTypeMap.entrySet()) {
473 final var propertyDefinition = new PropertyDefinition();
474 propertyDefinition.setName(propertyEntry.getKey());
475 propertyDefinition.setType(propertyEntry.getValue());
476 dataTypeDefinition.setProperties(List.of(propertyDefinition));
479 return dataTypeDefinition;
482 private DataTypeDefinition createDataType(final String name, final List<PropertyDefinition> propertyList) {
483 final var dataTypeDefinition = new DataTypeDefinition();
484 dataTypeDefinition.setName(name);
485 if (CollectionUtils.isNotEmpty(propertyList)) {
486 dataTypeDefinition.setProperties(propertyList);
488 return dataTypeDefinition;
491 private ComponentInstance createComponentInstance(String name, String uniqueId) {
492 ComponentInstance componentInstance = new ComponentInstance();
493 componentInstance.setName(name);
494 componentInstance.setUniqueId(uniqueId);
495 return componentInstance;