/*******************************************************************************
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package io.cloudslang.lang.systemtests;
import com.google.common.collect.Sets;
import io.cloudslang.lang.compiler.SlangSource;
import io.cloudslang.lang.compiler.SlangTextualKeys;
import io.cloudslang.lang.compiler.modeller.model.Executable;
import io.cloudslang.lang.compiler.modeller.model.Flow;
import io.cloudslang.lang.entities.CompilationArtifact;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.Output;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.bindings.values.ValueFactory;
import io.cloudslang.lang.entities.utils.ExpressionUtils;
import org.apache.commons.lang.StringUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Assert;
import org.junit.Test;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
/**
* @author Bonczidai Levente
* @since 3/18/2016
*/
public class BindingScopeTest extends SystemsTestsParent {
@Test
public void testStepPublishValues() throws Exception {
URL resource = getClass().getResource("/yaml/binding_scope_flow.sl");
URI operation = getClass().getResource("/yaml/binding_scope_op.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation));
CompilationArtifact compilationArtifact = slang.compile(SlangSource.fromFile(resource.toURI()), path);
Map<String, Value> userInputs = Collections.emptyMap();
Set<SystemProperty> systemProperties = Collections.emptySet();
// trigger ExecutionPlan
RuntimeInformation runtimeInformation = triggerWithData(compilationArtifact, userInputs, systemProperties);
Map<String, StepData> executionData = runtimeInformation.getSteps();
StepData stepData = executionData.get(FIRST_STEP_PATH);
Assert.assertNotNull("step data is null", stepData);
verifyStepPublishValues(stepData);
}
@Test
public void testInputMissing() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_missing_input.sl");
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = Collections.emptyMap();
Set<SystemProperty> systemProperties = Collections.emptySet();
exception.expect(RuntimeException.class);
exception.expectMessage(new BaseMatcher<String>() {
public void describeTo(Description description) {
}
public boolean matches(Object o) {
String message = o.toString();
return message.contains("Error running: 'check_weather_missing_input'") &&
message.contains("Error binding input: 'input_get_missing_input'") &&
message.contains("Error is: Error in running script expression: 'missing_input'") &&
message.contains("Exception is: name 'missing_input' is not defined");
}
});
triggerWithData(compilationArtifact, userInputs, systemProperties);
}
@Test
public void testInputWithDefaultValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_required_input_with_default.sl");
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("city", ValueFactory.create(""));
userInputs.put("input_with_default_value", ValueFactory.create(""));
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("default_value", steps.get(EXEC_START_PATH).getInputs().get("input_with_default_value"));
assertEquals("", steps.get(EXEC_START_PATH).getInputs().get("city"));
}
@Test
public void testInputNotRequiredNull() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_required_input_with_default.sl");
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("city", ValueFactory.create(null));
userInputs.put("input_with_default_value", ValueFactory.create(""));
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("default_value", steps.get(EXEC_START_PATH).getInputs().get("input_with_default_value"));
assertEquals(null, steps.get(EXEC_START_PATH).getInputs().get("city"));
}
@Test
public void testInputRequiredWithEmptyValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_input_required.sl");
final CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("city", ValueFactory.create(""));
Set<SystemProperty> systemProperties = Collections.emptySet();
exception.expect(RuntimeException.class);
exception.expectMessage(new BaseMatcher<String>() {
public void describeTo(Description description) {
}
public boolean matches(Object o) {
String message = o.toString();
return message.contains("Error running: 'check_weather_input_required'.") &&
message.contains("Input with name: 'city' is Required, but value is empty");
}
});
triggerWithData(compilationArtifact, userInputs, systemProperties);
}
@Test
public void testInputRequiredWithNullValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_input_required.sl");
final CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("city", ValueFactory.create(null));
Set<SystemProperty> systemProperties = Collections.emptySet();
exception.expect(RuntimeException.class);
exception.expectMessage(new BaseMatcher<String>() {
public void describeTo(Description description) {
}
public boolean matches(Object o) {
String message = o.toString();
return message.contains("Error running: 'check_weather_input_required'.") &&
message.contains("Input with name: 'city' is Required, but value is empty");
}
});
triggerWithData(compilationArtifact, userInputs, systemProperties);
}
@Test
public void testInputOptionalWithEmptyValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_optional_input_with_default.sl");
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("input_with_default_value", ValueFactory.create(""));
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("default_value", steps.get(EXEC_START_PATH).getInputs().get("input_with_default_value"));
}
@Test
public void testInputOptionalWithNullValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_optional_input_with_default.sl");
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), new HashSet<SlangSource>());
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("input_with_default_value", ValueFactory.create(null));
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("default_value", steps.get(EXEC_START_PATH).getInputs().get("input_with_default_value"));
}
@Test
public void testStepInputRequiredWithEmptyValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_flow.sl");
URI operation1 = getClass().getResource("/yaml/check_weather_required_input_with_default.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation1));
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), path);
Map<String, Value> userInputs = new HashMap<>();
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("weather thing default_value", steps.get(FIRST_STEP_PATH).getOutputs().get("kuku"));
}
@Test
public void testSensitiveInputAndOutputsWithAndWithoutDefault() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_flow_sensitive.sl");
URI operation1 = getClass().getResource("/yaml/check_weather_required_input_sensitive.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation1));
CompilationArtifact compilationArtifact = slang
.compile(SlangSource.fromFile(resource.toURI()), path);
Map<String, Value> userInputs = new HashMap<>();
userInputs.put("flow_input_sensitive", ValueFactory.create("sensitiveValue2", true));
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("********", steps.get(EXEC_START_PATH).getInputs().get("flow_input_sensitive"));
assertEquals("********", steps.get(EXEC_START_PATH).getInputs().get("flow_input_0"));
assertEquals("defaultValue", steps.get(EXEC_START_PATH).getInputs().get("flow_input_1"));
assertEquals("********", steps.get(EXEC_START_PATH).getOutputs().get("flow_output_0"));
assertEquals("weather thing default_value sensitiveValue",
steps.get(EXEC_START_PATH).getOutputs().get("flow_output_1"));
assertEquals("sensitiveValue", steps.get(FIRST_STEP_PATH).getInputs().get("input_with_sensitive_no_default"));
}
@Test
public void testSensitiveStepOutputs() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_flow_sensitive_outputs.sl");
URI operation1 = getClass().getResource("/yaml/check_weather_required_input_sensitive.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation1));
CompilationArtifact compilationArtifact = slang.compile(SlangSource.fromFile(resource.toURI()), path);
Map<String, Value> userInputs = new HashMap<>();
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("********", steps.get(EXEC_START_PATH).getOutputs().get("flow_output_0"));
assertEquals("********", steps.get(EXEC_START_PATH).getOutputs().get("flow_output_1"));
assertEquals("sensitive", steps.get(FIRST_STEP_PATH).getInputs().get("input_with_sensitive_no_default"));
}
@Test
public void testStepInputOptionalWithEmptyValue() throws Exception {
URL resource = getClass().getResource("/yaml/check_weather_flow_optional.sl");
URI operation1 = getClass().getResource("/yaml/check_weather_optional_input_with_default.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation1));
CompilationArtifact compilationArtifact = slang.compile(SlangSource.fromFile(resource.toURI()), path);
Map<String, Value> userInputs = new HashMap<>();
Set<SystemProperty> systemProperties = Collections.emptySet();
Map<String, StepData> steps = triggerWithData(compilationArtifact, userInputs, systemProperties).getSteps();
assertEquals("weather thing default_value", steps.get(FIRST_STEP_PATH).getOutputs().get("kuku"));
}
private void verifyStepPublishValues(StepData stepData) {
Map<String, Serializable> expectedPublishValues = new LinkedHashMap<>();
expectedPublishValues.put("step1_publish_1", "op_output_1_value op_input_1_step step_arg_1_value");
expectedPublishValues.put("step1_publish_2_conflict", "op_output_2_value");
Map<String, Serializable> actualPublishValues = stepData.getOutputs();
assertEquals("step publish values not as expected", expectedPublishValues, actualPublishValues);
}
@Test
public void testFlowContextInStepPublishSection() throws Exception {
URL resource = getClass().getResource("/yaml/binding_scope_flow_context_in_step_publish.sl");
URI operation = getClass().getResource("/yaml/binding_scope_op.sl").toURI();
Set<SlangSource> path = Sets.newHashSet(SlangSource.fromFile(operation));
// pre-validation - step expression uses flow var name
SlangSource flowSource = SlangSource.fromFile(resource.toURI());
Executable flowExecutable = slangCompiler.preCompile(flowSource);
String flowVarName = "flow_var";
assertEquals(
"Input name should be: " + flowVarName,
flowVarName,
flowExecutable.getInputs().get(0).getName()
);
@SuppressWarnings("unchecked")
List<Output> stepPublishValues = (List<Output>) ((Flow) flowExecutable)
.getWorkflow()
.getSteps()
.getFirst()
.getPostStepActionData()
.get(SlangTextualKeys.PUBLISH_KEY);
assertEquals(
"Step expression should contain: " + flowVarName,
flowVarName,
StringUtils.trim(ExpressionUtils.extractExpression(stepPublishValues.get(0).getValue().get()))
);
final CompilationArtifact compilationArtifact = slang.compile(flowSource, path);
final Map<String, Value> userInputs = Collections.emptyMap();
final Set<SystemProperty> systemProperties = Collections.emptySet();
exception.expect(RuntimeException.class);
exception.expectMessage("flow_var");
exception.expectMessage("not defined");
// trigger ExecutionPlan
triggerWithData(compilationArtifact, userInputs, systemProperties);
}
}