io.cloudslang.lang.systemtests.EventDataTest.java Source code

Java tutorial

Introduction

Here is the source code for io.cloudslang.lang.systemtests.EventDataTest.java

Source

/*******************************************************************************
 * (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.entities.CompilationArtifact;
import io.cloudslang.lang.entities.ScoreLangConstants;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.values.SensitiveValue;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.bindings.values.ValueFactory;
import io.cloudslang.lang.entities.properties.EventVerbosityLevel;
import io.cloudslang.lang.runtime.events.LanguageEventData;
import io.cloudslang.score.events.ScoreEvent;
import org.apache.commons.collections4.MapUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static io.cloudslang.lang.compiler.SlangSource.fromFile;
import static io.cloudslang.lang.entities.properties.SlangSystemPropertyConstant.CSLANG_RUNTIME_EVENTS_VERBOSITY;
import static org.junit.Assert.fail;

public class EventDataTest extends SystemsTestsParent {
    private static final long DEFAULT_TIMEOUT = 60000;
    private static final Set<SystemProperty> EMPTY_SP_SET = Collections.emptySet();
    private static final String SENSITIVE_VALUE_STRING = "sensitive_value";

    private static final Map<String, Serializable> CONTEXT_USER_INPUTS;
    private static final Map<String, Serializable> CONTEXT_FLOW_01;
    private static final Map<String, Serializable> CONTEXT_FLOW_02;
    private static final Map<String, Serializable> CONTEXT_FLOW_03;
    private static final Map<String, Serializable> CONTEXT_OPERATION_01;
    private static final Map<String, Serializable> CONTEXT_STEP_PUBLISH_01;
    private static final Map<String, Serializable> CONTEXT_BRANCH_END_01;
    private static final Map<String, Serializable> CONTEXT_BRANCH_END_02;
    private static final Map<String, Serializable> CONTEXT_BRANCH_END_03;

    static {
        CONTEXT_USER_INPUTS = new HashMap<>();
        CONTEXT_USER_INPUTS.put("flow01_input01", "xyz");
        CONTEXT_USER_INPUTS.put("flow01_input03", SensitiveValue.SENSITIVE_VALUE_MASK);

        CONTEXT_FLOW_01 = new HashMap<>();
        CONTEXT_FLOW_01.putAll(CONTEXT_USER_INPUTS);
        CONTEXT_FLOW_01.put("flow01_input02", "abc");

        CONTEXT_OPERATION_01 = new HashMap<>();
        CONTEXT_OPERATION_01.put("op01_input_01", "def");
        CONTEXT_OPERATION_01.put("op01_input_03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_OPERATION_01.put("op01_input_02", "abc");

        CONTEXT_FLOW_02 = new HashMap<>();
        CONTEXT_FLOW_02.put("flow01_input01", "xyz");
        CONTEXT_FLOW_02.put("flow01_input02", "abc");
        CONTEXT_FLOW_02.put("flow01_input03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_FLOW_02.put("parallel_loop_output", "efg");
        CONTEXT_FLOW_02.put("step01_publish_01", "def");
        CONTEXT_FLOW_02.put("step01_publish_02", "out02");
        CONTEXT_FLOW_02.put("step01_publish_03", SensitiveValue.SENSITIVE_VALUE_MASK);

        CONTEXT_FLOW_03 = new HashMap<>();
        CONTEXT_FLOW_03.put("flow01_input01", "xyz");
        CONTEXT_FLOW_03.put("flow01_input02", "abc");
        CONTEXT_FLOW_03.put("flow01_input03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_FLOW_03.put("step01_publish_01", "def");
        CONTEXT_FLOW_03.put("step01_publish_02", "out02");
        CONTEXT_FLOW_03.put("step01_publish_03", SensitiveValue.SENSITIVE_VALUE_MASK);

        CONTEXT_STEP_PUBLISH_01 = new HashMap<>();
        CONTEXT_STEP_PUBLISH_01.put("op01_input_01", "def");
        CONTEXT_STEP_PUBLISH_01.put("op01_input_02", "abc");
        CONTEXT_STEP_PUBLISH_01.put("op01_input_03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_STEP_PUBLISH_01.put("op01_output_01", "def");
        CONTEXT_STEP_PUBLISH_01.put("op01_output_02", "out02");
        CONTEXT_STEP_PUBLISH_01.put("op01_output_03", SensitiveValue.SENSITIVE_VALUE_MASK);

        CONTEXT_BRANCH_END_01 = new HashMap<>();
        CONTEXT_BRANCH_END_01.put("flow01_input01", "xyz");
        CONTEXT_BRANCH_END_01.put("flow01_input02", "abc");
        CONTEXT_BRANCH_END_01.put("flow01_input03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_BRANCH_END_01.put("step01_publish_01", "def");
        CONTEXT_BRANCH_END_01.put("step01_publish_02", "out02");
        CONTEXT_BRANCH_END_01.put("step01_publish_03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_BRANCH_END_01.put("op01_output_01", "1");
        CONTEXT_BRANCH_END_01.put("op01_output_02", "out02");
        CONTEXT_BRANCH_END_01.put("op01_output_03", SensitiveValue.SENSITIVE_VALUE_MASK);
        CONTEXT_BRANCH_END_01.put("x", "1");

        CONTEXT_BRANCH_END_02 = new HashMap<>(CONTEXT_BRANCH_END_01);
        CONTEXT_BRANCH_END_02.put("op01_output_01", "2");
        CONTEXT_BRANCH_END_02.put("x", "2");
        CONTEXT_BRANCH_END_03 = new HashMap<>(CONTEXT_BRANCH_END_02);
        CONTEXT_BRANCH_END_03.put("op01_output_01", "3");
        CONTEXT_BRANCH_END_03.put("x", "3");
    }

    @After
    public void tearDown() throws Exception {
        // do not store context in events
        System.setProperty(CSLANG_RUNTIME_EVENTS_VERBOSITY.getValue(), EventVerbosityLevel.DEFAULT.getValue());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testEventDataNoContext() throws Exception {
        // do not store context in events
        System.setProperty(CSLANG_RUNTIME_EVENTS_VERBOSITY.getValue(), EventVerbosityLevel.DEFAULT.getValue());

        Map<String, Value> inputs = new HashMap<>();
        inputs.put("flow01_input01", ValueFactory.create("xyz"));
        inputs.put("flow01_input03", ValueFactory.create(SENSITIVE_VALUE_STRING, true));

        List<ScoreEvent> events = compileAndRunExecutable(inputs, EMPTY_SP_SET);

        for (ScoreEvent scoreEvent : events) {
            LanguageEventData eventDataAsMap = getData(scoreEvent);
            if (eventDataAsMap.keySet().contains(LanguageEventData.CONTEXT)) {
                fail("Context key should not be in event data");
            }
        }
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testEventDataWithContext() throws Exception {
        // store context in events
        System.setProperty(CSLANG_RUNTIME_EVENTS_VERBOSITY.getValue(), EventVerbosityLevel.ALL.getValue());

        Map<String, Value> inputs = new HashMap<>();
        inputs.put("flow01_input01", ValueFactory.create("xyz"));
        inputs.put("flow01_input03", ValueFactory.create(SENSITIVE_VALUE_STRING, true));

        List<ScoreEvent> events = compileAndRunExecutable(inputs, EMPTY_SP_SET);
        Map<String, List<LanguageEventData>> eventDataByPath = groupByPath(events);

        validateEventData(eventDataByPath, "0", ScoreLangConstants.EVENT_INPUT_START, CONTEXT_USER_INPUTS);
        validateEventData(eventDataByPath, "0", ScoreLangConstants.EVENT_INPUT_END, CONTEXT_USER_INPUTS);
        validateEventData(eventDataByPath, "0", ScoreLangConstants.EVENT_OUTPUT_END, CONTEXT_FLOW_02);
        validateEventData(eventDataByPath, "0", ScoreLangConstants.EVENT_EXECUTION_FINISHED, CONTEXT_FLOW_02);

        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_STEP_START, CONTEXT_FLOW_01);
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_ARGUMENT_START, CONTEXT_FLOW_01);
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_ARGUMENT_END, CONTEXT_FLOW_01);
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_ACTION_START, CONTEXT_OPERATION_01);
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_ACTION_END, CONTEXT_OPERATION_01);
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_OUTPUT_START, CONTEXT_OPERATION_01);
        // subflow outputs validation
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_OUTPUT_END, CONTEXT_OPERATION_01);
        // step publish validation
        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_OUTPUT_END, CONTEXT_STEP_PUBLISH_01, 1);

        // parallel loop
        validateEventData(eventDataByPath, "0.1", ScoreLangConstants.EVENT_SPLIT_BRANCHES, CONTEXT_FLOW_03);
        validateEventData(eventDataByPath, "0.1.0", ScoreLangConstants.EVENT_BRANCH_START, CONTEXT_FLOW_03);
        validateEventData(eventDataByPath, "0.1.0", ScoreLangConstants.EVENT_BRANCH_END, CONTEXT_BRANCH_END_01);
        validateEventData(eventDataByPath, "0.1.1", ScoreLangConstants.EVENT_BRANCH_END, CONTEXT_BRANCH_END_02);
        validateEventData(eventDataByPath, "0.1.2", ScoreLangConstants.EVENT_BRANCH_END, CONTEXT_BRANCH_END_03);
        validateEventData(eventDataByPath, "0.1", ScoreLangConstants.EVENT_JOIN_BRANCHES_START,
                Collections.<String, Serializable>emptyMap());
        validateEventData(eventDataByPath, "0.1", ScoreLangConstants.EVENT_JOIN_BRANCHES_END,
                Collections.<String, Serializable>emptyMap());

        validateSensitiveDataNotReveiledInContext(events);
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testEventDataWithException() throws Exception {
        // store context in events
        System.setProperty(CSLANG_RUNTIME_EVENTS_VERBOSITY.getValue(), EventVerbosityLevel.ALL.getValue());

        Map<String, Value> inputs = new HashMap<>();
        inputs.put("flow01_input01", ValueFactory.create("xyz"));
        inputs.put("flow01_input03", ValueFactory.create(SENSITIVE_VALUE_STRING, true));

        List<ScoreEvent> events = compileAndRunExecutableWithException(inputs, EMPTY_SP_SET);
        Map<String, List<LanguageEventData>> eventDataByPath = groupByPath(events);

        validateEventData(eventDataByPath, "0.0", ScoreLangConstants.EVENT_ACTION_ERROR, CONTEXT_OPERATION_01);
        validateEventData(eventDataByPath, "0.0.0", ScoreLangConstants.SLANG_EXECUTION_EXCEPTION,
                CONTEXT_OPERATION_01);

        validateSensitiveDataNotReveiledInContext(events);
    }

    private void validateSensitiveDataNotReveiledInContext(List<ScoreEvent> events) {
        for (ScoreEvent scoreEvent : events) {
            LanguageEventData eventDataAsMap = getData(scoreEvent);
            Map<String, Serializable> context = eventDataAsMap.getContext();
            if (MapUtils.isNotEmpty(context)) {
                for (Serializable value : context.values()) {
                    if (value.toString().contains(SENSITIVE_VALUE_STRING)) {
                        fail(SENSITIVE_VALUE_STRING + " string should not be in event data");
                    }
                }
            }
        }
    }

    private void validateEventData(Map<String, List<LanguageEventData>> eventDataByPath, String path,
            String eventType, Map<String, Serializable> expectedContext, int skipEventsCounter) {
        List<LanguageEventData> eventsForPath = eventDataByPath.get(path);
        // select first event with type - in general we should not rely on event order
        // but in this case the group by path is a good enough exception factor
        LanguageEventData actualEventData = null;
        for (LanguageEventData data : eventsForPath) {
            if (eventType.equals(data.getEventType())) {
                if (skipEventsCounter-- <= 0) {
                    actualEventData = data;
                    break;
                }
            }
        }
        Assert.assertNotNull("Event data not found", actualEventData);
        Assert.assertEquals("Event data not as expected", expectedContext, actualEventData.getContext());
    }

    private void validateEventData(Map<String, List<LanguageEventData>> eventDataByPath, String path,
            String eventType, Map<String, Serializable> expectedContext) {
        validateEventData(eventDataByPath, path, eventType, expectedContext, 0);
    }

    private Map<String, List<LanguageEventData>> groupByPath(List<ScoreEvent> events) {
        Map<String, List<LanguageEventData>> result = new HashMap<>();
        for (ScoreEvent scoreEvent : events) {
            LanguageEventData eventData = getData(scoreEvent);
            String path = eventData.getPath();
            List<LanguageEventData> eventsForPath = result.get(path);
            if (eventsForPath == null) {
                eventsForPath = new ArrayList<>();
            }
            eventsForPath.add(eventData);
            result.put(path, eventsForPath);
        }
        return result;
    }

    private LanguageEventData getData(ScoreEvent scoreEvent) {
        Serializable eventData = scoreEvent.getData();
        @SuppressWarnings("unchecked")
        LanguageEventData eventDataAsMap = (LanguageEventData) eventData;
        return eventDataAsMap;
    }

    private List<ScoreEvent> compileAndRunExecutable(Map<String, Value> inputs,
            Set<SystemProperty> systemProperties) throws Exception {
        URI flow = getClass().getResource("/yaml/events/flow01.sl").toURI();
        URI operations1 = getClass().getResource("/yaml/events/op01.sl").toURI();
        Set<SlangSource> dependencies = Sets.newHashSet(fromFile(operations1));
        CompilationArtifact compilationArtifact = slang.compile(fromFile(flow), dependencies);

        List<ScoreEvent> events = runAndCollectAllEvents(compilationArtifact, inputs, systemProperties);

        Assert.assertFalse(CollectionUtils.isEmpty(events));
        for (ScoreEvent scoreEvent : events) {
            if (ScoreLangConstants.EVENT_EXECUTION_FINISHED.equals(scoreEvent.getEventType())) {
                return events;
            }
        }
        fail("Finished event not received.");

        return events;
    }

    private List<ScoreEvent> compileAndRunExecutableWithException(Map<String, Value> inputs,
            Set<SystemProperty> systemProperties) throws Exception {
        URI flow = getClass().getResource("/yaml/events/flow02.sl").toURI();
        URI operations1 = getClass().getResource("/yaml/events/op02.sl").toURI();
        Set<SlangSource> dependencies = Sets.newHashSet(fromFile(operations1));
        CompilationArtifact compilationArtifact = slang.compile(fromFile(flow), dependencies);

        List<ScoreEvent> events = runAndCollectAllEvents(compilationArtifact, inputs, systemProperties);

        Assert.assertFalse(CollectionUtils.isEmpty(events));

        for (ScoreEvent scoreEvent : events) {
            if (ScoreLangConstants.SLANG_EXECUTION_EXCEPTION.equals(scoreEvent.getEventType())) {
                return events;
            }
        }
        fail("Exception event not received.");
        return events;
    }

}