/*******************************************************************************
* (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.Lists;
import com.google.common.collect.Sets;
import io.cloudslang.lang.compiler.SlangSource;
import io.cloudslang.lang.entities.CompilationArtifact;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.values.Value;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import static com.google.common.collect.Sets.newHashSet;
import static io.cloudslang.lang.compiler.SlangSource.fromFile;
/**
* Date: 3/25/2015
*
* @author Bonczidai Levente
*/
public class ParallelLoopFlowsTest extends SystemsTestsParent {
private static final String BRANCH_MESSAGE = "branch ";
private static final String BRANCH_RESULTS_LIST_PUBLISH_VALUE = "branch_results_list";
private static final String CUSTOM_RESULT = "CUSTOM";
private static final String SUCCESS_RESULT = "SUCCESS";
private static final String BRANCH_RESULT_OUTPUT_VALUE = "should_be_overridden";
@Test
public void testFlowWithParallelLoop() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/simple_parallel_loop.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation = triggerWithData(fromFile(resource), path);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
}
@Test
public void testFlowWithSensitiveInputParallelLoop() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/sensitive_input_parallel_loop.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation =
triggerWithData(fromFile(resource), path, getSystemProperties());
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
List<String> expectedNameOutputs = verifyBranchPublishValues(branchesData);
verifyPublishValues(runtimeInformation, expectedNameOutputs);
}
@Test
public void testFlowWithSensitiveOutputParallelLoop() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/sensitive_output_parallel_loop.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation =
triggerWithData(fromFile(resource), path, getSystemProperties());
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
List<String> expectedNameOutputs = verifyBranchPublishValues(branchesData);
verifyPublishValues(runtimeInformation, expectedNameOutputs);
}
@Test
public void testFlowWithParallelLoopPublish() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/parallel_loop_publish.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation = triggerWithData(
fromFile(resource),
path,
getSystemProperties()
);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
List<String> expectedNameOutputs = verifyBranchPublishValues(branchesData);
verifyPublishValues(runtimeInformation, expectedNameOutputs);
}
@Test
public void testFlowBranchResults() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/parallel_loop_branch_result.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation = triggerWithData(
fromFile(resource),
path,
getSystemProperties()
);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
verifyBranchPublishValues(branchesData);
verifyPublishValuesBranchResultsCase(
runtimeInformation,
Lists.newArrayList(SUCCESS_RESULT, SUCCESS_RESULT, SUCCESS_RESULT)
);
}
@Test
public void testFlowBranchResultsOutputCollision() throws Exception {
URI resource = getClass()
.getResource("/yaml/loops/parallel_loop/parallel_loop_branch_result_output_collision.sl").toURI();
URI operation1 = getClass()
.getResource("/yaml/loops/parallel_loop/print_branch_with_result_output_collision.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
RuntimeInformation runtimeInformation = triggerWithData(
fromFile(resource),
path,
getSystemProperties()
);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
verifyBranchPublishValuesBranchResultsCase(branchesData);
verifyPublishValuesBranchResultsCase(
runtimeInformation,
Lists.newArrayList(CUSTOM_RESULT, CUSTOM_RESULT, CUSTOM_RESULT)
);
}
@Test
public void testFlowWithParallelLoopNavigate() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/parallel_loop_navigate.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
URI operation2 = getClass().getResource("/yaml/loops/parallel_loop/print_list.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1), fromFile(operation2));
RuntimeInformation runtimeInformation = triggerWithData(fromFile(resource), path);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
verifyNavigation(runtimeInformation);
}
@Test
public void testFlowWithParallelLoopPublishNavigate() throws Exception {
URI resource = getClass().getResource("/yaml/loops/parallel_loop/parallel_loop_publish_navigate.sl").toURI();
URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
URI operation2 = getClass().getResource("/yaml/loops/parallel_loop/print_list.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1), fromFile(operation2));
RuntimeInformation runtimeInformation = triggerWithData(
fromFile(resource),
path,
getSystemProperties()
);
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
List<String> expectedNameOutputs = verifyBranchPublishValues(branchesData);
verifyPublishValues(runtimeInformation, expectedNameOutputs);
verifyNavigation(runtimeInformation);
}
@Test
public void testFlowContextInPublishSectionNotReachable() throws Exception {
final URI resource = getClass()
.getResource("/yaml/loops/parallel_loop/parallel_loop_publish_flow_context.sl").toURI();
final URI operation1 = getClass()
.getResource("/yaml/loops/parallel_loop/print_branch.sl").toURI();
final Set<SlangSource> path = newHashSet(fromFile(operation1));
exception.expect(RuntimeException.class);
exception.expectMessage("flow_var");
exception.expectMessage("not defined");
triggerWithData(fromFile(resource), path);
}
@Test
public void testFlowWithInlineMapLoops() throws Exception {
final URI resource = getClass()
.getResource("/yaml/loops/parallel_loop/parallel_loop_with_inline_map.sl").toURI();
final URI operation1 = getClass().getResource("/yaml/loops/parallel_loop/print_branch_map.sl").toURI();
Set<SlangSource> path = newHashSet(fromFile(operation1));
final CompilationArtifact compilationArtifact = slang.compile(fromFile(resource), path);
Map<String, Value> userInputs = new HashMap<>();
RuntimeInformation runtimeInformation = triggerWithData(compilationArtifact, userInputs, getSystemProperties());
List<StepData> branchesData = extractParallelLoopData(runtimeInformation);
Assert.assertEquals("incorrect number of branches", 3, branchesData.size());
List<String> expectedNameOutputs = verifyBranchPublishValues(branchesData);
verifyPublishValues(runtimeInformation, expectedNameOutputs);
}
private Set<SystemProperty> getSystemProperties() {
return newHashSet(new SystemProperty("loop", "parallel.prop1", "publish_value"));
}
private RuntimeInformation triggerWithData(
SlangSource resource,
Set<SlangSource> path,
Set<SystemProperty> systemProperties) {
CompilationArtifact compilationArtifact = slang.compile(resource, path);
Map<String, Value> userInputs = new HashMap<>();
return triggerWithData(compilationArtifact, userInputs, systemProperties);
}
private RuntimeInformation triggerWithData(SlangSource resource, Set<SlangSource> path) {
return triggerWithData(resource, path, new HashSet<SystemProperty>());
}
private List<StepData> extractParallelLoopData(RuntimeInformation runtimeInformation) {
Map<String, List<StepData>> branchesByPath = runtimeInformation.getBranchesByPath();
Assert.assertTrue("parallel loop data not found", branchesByPath.containsKey(BRANCH_FIRST_STEP_PATH));
List<StepData> stepDataList = new ArrayList<>();
for (List<StepData> list : branchesByPath.values()) {
stepDataList.add(list.get(0));
}
return stepDataList;
}
private <T> boolean containsSameElementsWithoutOrdering(List<T> firstList, List<T> secondList) {
return firstList.containsAll(secondList) && secondList.containsAll(firstList);
}
private List<String> verifyBranchPublishValues(List<StepData> branchesData) {
// publish
List<String> actualNameOutputsOfBranches = Lists.newArrayList();
List<String> actualNumberOutputsOfBranches = Lists.newArrayList();
for (StepData branchData : branchesData) {
Map<String, Serializable> outputs = branchData.getOutputs();
Assert.assertTrue(outputs.containsKey("name"));
Assert.assertTrue(outputs.containsKey("int_output"));
actualNameOutputsOfBranches.add((String) outputs.get("name"));
actualNumberOutputsOfBranches.add((String) outputs.get("int_output"));
}
List<String> expectedNameOutputs = Lists.newArrayList();
List<String> expectedNumberOutputs = Lists.newArrayList();
for (int i = 1; i < 4; i++) {
expectedNameOutputs.add(BRANCH_MESSAGE + i);
expectedNumberOutputs.add(Integer.toString(i));
}
Assert.assertTrue(
"branch publish values not as expected",
containsSameElementsWithoutOrdering(expectedNameOutputs, actualNameOutputsOfBranches)
);
Assert.assertTrue(
"branch publish values not as expected",
containsSameElementsWithoutOrdering(expectedNumberOutputs, actualNumberOutputsOfBranches)
);
return expectedNameOutputs;
}
private void verifyBranchPublishValuesBranchResultsCase(List<StepData> branchesData) {
// publish
List<String> actualBranchResultOutputs = Lists.newArrayList();
for (StepData branchData : branchesData) {
Map<String, Serializable> outputs = branchData.getOutputs();
Assert.assertTrue(outputs.containsKey("branch_result"));
actualBranchResultOutputs.add((String) outputs.get("branch_result"));
}
List<String> expectedBranchResultOutputs = Lists.newArrayList(
BRANCH_RESULT_OUTPUT_VALUE,
BRANCH_RESULT_OUTPUT_VALUE,
BRANCH_RESULT_OUTPUT_VALUE
);
Assert.assertEquals(expectedBranchResultOutputs, actualBranchResultOutputs);
}
private void verifyPublishValues(RuntimeInformation runtimeInformation, List<String> expectedNameOutputs) {
// publish
Map<String, StepData> parallelLoopSteps = runtimeInformation.getParallelSteps();
StepData parallelLoopStep = parallelLoopSteps.get(FIRST_STEP_PATH);
Map<String, Serializable> publishValues = parallelLoopStep.getOutputs();
Assert.assertTrue("publish name not found in parallel loop outputs", publishValues.containsKey("name_list"));
@SuppressWarnings("unchecked")
String actualPublishNames = (String) publishValues.get("name_list");
ArrayList<String> actualPublishNameList = getArrayListFromString(actualPublishNames);
Assert.assertTrue(
"publish value does not have the expected value",
containsSameElementsWithoutOrdering(Lists.newArrayList(actualPublishNameList), expectedNameOutputs)
);
Assert.assertEquals(
"Publish value not bound correctly from system property",
"publish_value",
publishValues.get("from_sp")
);
}
private ArrayList<String> getArrayListFromString(String actualPublishNames) {
String[] actualArray = actualPublishNames.replaceAll("'", "")
.replaceAll("\\[", "").replaceAll("]", "").split(",");
ArrayList<String> actualPublishNameList = new ArrayList<>();
for (String s : actualArray) {
actualPublishNameList.add(s.trim());
}
return actualPublishNameList;
}
private void verifyPublishValuesBranchResultsCase(
RuntimeInformation runtimeInformation,
List<String> publishValue) {
Map<String, StepData> parallelLoopSteps = runtimeInformation.getParallelSteps();
StepData parallelLoopStep = parallelLoopSteps.get(FIRST_STEP_PATH);
Map<String, Serializable> publishValues = parallelLoopStep.getOutputs();
Assert.assertTrue(publishValues.containsKey(BRANCH_RESULTS_LIST_PUBLISH_VALUE));
@SuppressWarnings("unchecked")
String actualBranchResultsPublishValue = (String) publishValues.get(BRANCH_RESULTS_LIST_PUBLISH_VALUE);
Assert.assertEquals(
publishValue,
getArrayListFromString(actualBranchResultsPublishValue)
);
}
private void verifyNavigation(RuntimeInformation runtimeInformation) {
Map<String, StepData> stepsData = runtimeInformation.getSteps();
StepData stepAfterParallelLoop = stepsData.get(SECOND_STEP_KEY);
Assert.assertEquals("navigation not as expected", "print_list", stepAfterParallelLoop.getName());
}
}