io.cloudslang.lang.tools.build.SlangBuilder Maven / Gradle / Ivy
/*******************************************************************************
* (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.tools.build;
import io.cloudslang.lang.compiler.modeller.model.Executable;
import io.cloudslang.lang.entities.CompilationArtifact;
import io.cloudslang.lang.logging.LoggingService;
import io.cloudslang.lang.tools.build.SlangBuildMain.BulkRunMode;
import io.cloudslang.lang.tools.build.constants.Messages;
import io.cloudslang.lang.tools.build.tester.IRunTestResults;
import io.cloudslang.lang.tools.build.tester.RunTestsResults;
import io.cloudslang.lang.tools.build.tester.SlangTestRunner;
import io.cloudslang.lang.tools.build.tester.SlangTestRunner.TestCaseRunState;
import io.cloudslang.lang.tools.build.tester.parallel.report.ThreadSafeRunTestResults;
import io.cloudslang.lang.tools.build.tester.parse.SlangTestCase;
import io.cloudslang.lang.tools.build.tester.runconfiguration.BuildModeConfig;
import io.cloudslang.lang.tools.build.verifier.CompileResult;
import io.cloudslang.lang.tools.build.verifier.PreCompileResult;
import io.cloudslang.lang.tools.build.verifier.SlangContentVerifier;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.cloudslang.lang.tools.build.SlangBuildMain.BulkRunMode.ALL_PARALLEL;
import static io.cloudslang.lang.tools.build.SlangBuildMain.BulkRunMode.ALL_SEQUENTIAL;
import static io.cloudslang.lang.tools.build.SlangBuildMain.BulkRunMode.POSSIBLY_MIXED;
/*
* Created by stoneo on 2/9/2015.
*/
/**
* Verifies all files with extensions: .sl, .sl.yaml or .sl.yml in a given directory are valid
*/
@Component
public class SlangBuilder {
private static final String UNSUPPORTED_BULK_RUN_MODE = "Unsupported bulk run mode '%s'.";
@Autowired
private SlangContentVerifier slangContentVerifier;
@Autowired
private SlangTestRunner slangTestRunner;
@Autowired
private LoggingService loggingService;
public SlangBuildResults buildSlangContent(
String projectPath,
String contentPath,
String testsPath,
List testSuits,
boolean shouldValidateDescription,
boolean shouldValidateCheckstyle,
BulkRunMode bulkRunMode,
SlangBuildMain.BuildMode buildMode,
Set changedFiles) {
String projectName = FilenameUtils.getName(projectPath);
loggingService.logEvent(Level.INFO, "");
loggingService.logEvent(Level.INFO, "------------------------------------------------------------");
loggingService.logEvent(Level.INFO, "Building project: " + projectName);
loggingService.logEvent(Level.INFO, "------------------------------------------------------------");
loggingService.logEvent(Level.INFO, "");
loggingService.logEvent(Level.INFO, "--- compiling sources ---");
PreCompileResult preCompileResult =
slangContentVerifier.createModelsAndValidate(contentPath,
shouldValidateDescription, shouldValidateCheckstyle);
Map slangModels = preCompileResult.getResults();
List exceptions = new ArrayList<>(preCompileResult.getExceptions());
CompileResult compileResult = compileModels(slangModels);
exceptions.addAll(compileResult.getExceptions());
IRunTestResults runTestsResults = new RunTestsResults();
if (compileResult.getExceptions().size() == 0 &&
StringUtils.isNotBlank(testsPath) && new File(testsPath).isDirectory()) {
runTestsResults =
runTests(slangModels, projectPath, testsPath, testSuits, bulkRunMode, buildMode, changedFiles);
}
exceptions.addAll(runTestsResults.getExceptions());
return new SlangBuildResults(compileResult.getResults().size(), runTestsResults, exceptions);
}
/**
* Compiles all CloudSlang models
*
* @return the number of valid CloudSlang files in the given directory
*/
private CompileResult compileModels(Map slangModels) {
CompileResult compileResult = slangContentVerifier.compileSlangModels(slangModels);
Map compiledSlangFiles = compileResult.getResults();
if (compiledSlangFiles.size() != slangModels.size()) {
compileResult.addException(new RuntimeException("Some Slang files were not compiled.\n" +
"Found: " + slangModels.size() + " slang models, but managed to compile only: " +
compiledSlangFiles.size()));
}
loggingService.logEvent(Level.INFO, "Successfully finished Compilation of: " +
compiledSlangFiles.size() + " Slang files");
return compileResult;
}
IRunTestResults runTests(
Map contentSlangModels,
String projectPath,
String testsPath,
List testSuites,
BulkRunMode bulkRunMode,
SlangBuildMain.BuildMode buildMode,
Set changedFiles) {
loggingService.logEvent(Level.INFO, "");
loggingService.logEvent(Level.INFO, "--- compiling tests sources ---");
// Compile all slang test flows under the test directory
PreCompileResult preCompileResult = slangContentVerifier.createModelsAndValidate(testsPath, false, false);
Map testFlowModels = preCompileResult.getResults();
// Add also all of the slang models of the content in order to allow for compilation of the test flows
Map allTestedFlowModels = new HashMap<>(testFlowModels);
allTestedFlowModels.putAll(contentSlangModels);
// Compiling all the test flows
CompileResult compileResult = slangContentVerifier.compileSlangModels(allTestedFlowModels);
final Map compiledFlows =
compileResult.getResults();
Set allTestedFlowsFqn = mapExecutablesToFullyQualifiedName(allTestedFlowModels.values());
Map testCases = slangTestRunner.createTestCases(testsPath, allTestedFlowsFqn);
loggingService.logEvent(Level.INFO, "");
loggingService.logEvent(Level.INFO, "--- running tests ---");
loggingService.logEvent(Level.INFO, "Found " + testCases.size() + " tests");
IRunTestResults runTestsResults;
BuildModeConfig buildModeConfig = createBuildModeConfig(buildMode, changedFiles, allTestedFlowModels);
runTestsResults =
processRunTests(projectPath, testSuites, bulkRunMode, compiledFlows, testCases, buildModeConfig);
runTestsResults.addExceptions(preCompileResult.getExceptions());
runTestsResults.addExceptions(compileResult.getExceptions());
addCoverageDataToRunTestsResults(contentSlangModels, testFlowModels, testCases, runTestsResults);
return runTestsResults;
}
private BuildModeConfig createBuildModeConfig(SlangBuildMain.BuildMode buildMode, Set changedFiles,
Map allTestedFlowModels) {
BuildModeConfig buildModeConfig;
switch (buildMode) {
case BASIC:
buildModeConfig = BuildModeConfig.createBasicBuildModeConfig();
break;
case CHANGED:
buildModeConfig = BuildModeConfig.createChangedBuildModeConfig(changedFiles, allTestedFlowModels);
break;
default:
throw new NotImplementedException(Messages.UNKNOWN_BUILD_MODE);
}
return buildModeConfig;
}
IRunTestResults processRunTests(
String projectPath,
List testSuites,
BulkRunMode bulkRunMode,
Map compiledFlows,
Map testCases,
BuildModeConfig buildModeConfig) {
IRunTestResults runTestsResults;
if (bulkRunMode == ALL_PARALLEL) { // Run All tests in parallel
ThreadSafeRunTestResults parallelRunTestResults = new ThreadSafeRunTestResults();
Map> testCaseRunState =
slangTestRunner.splitTestCasesByRunState(bulkRunMode, testCases, testSuites,
parallelRunTestResults, buildModeConfig);
slangTestRunner.runTestsParallel(projectPath, testCaseRunState.get(TestCaseRunState.PARALLEL),
compiledFlows, parallelRunTestResults);
runTestsResults = parallelRunTestResults;
} else if (bulkRunMode == ALL_SEQUENTIAL) { // Run all tests sequentially
RunTestsResults sequentialRunTestResults = new RunTestsResults();
Map> testCaseRunState =
slangTestRunner.splitTestCasesByRunState(bulkRunMode, testCases, testSuites,
sequentialRunTestResults, buildModeConfig);
slangTestRunner.runTestsSequential(projectPath, testCaseRunState.get(TestCaseRunState.SEQUENTIAL),
compiledFlows, sequentialRunTestResults);
runTestsResults = sequentialRunTestResults;
} else if (bulkRunMode == POSSIBLY_MIXED) { // Run some tests in parallel and rest of tests sequentially
ThreadSafeRunTestResults mixedTestResults = new ThreadSafeRunTestResults();
Map> testCaseRunState =
slangTestRunner.splitTestCasesByRunState(bulkRunMode, testCases, testSuites,
mixedTestResults, buildModeConfig);
slangTestRunner.runTestsSequential(projectPath, testCaseRunState.get(TestCaseRunState.SEQUENTIAL),
compiledFlows, mixedTestResults);
slangTestRunner.runTestsParallel(projectPath, testCaseRunState.get(TestCaseRunState.PARALLEL),
compiledFlows, mixedTestResults);
runTestsResults = mixedTestResults;
} else {
throw new IllegalStateException(String
.format(UNSUPPORTED_BULK_RUN_MODE, (bulkRunMode == null) ? null : bulkRunMode.toString()));
}
return runTestsResults;
}
private Set mapExecutablesToFullyQualifiedName(Collection executables) {
Set fullyQualifiedNames = new HashSet<>();
for (Executable executable : executables) {
fullyQualifiedNames.add(executable.getId());
}
return fullyQualifiedNames;
}
void addCoverageDataToRunTestsResults(Map contentSlangModels,
Map testFlowModels,
Map testCases, IRunTestResults runTestsResults) {
Set coveredContent = new HashSet<>();
Set uncoveredContent = new HashSet<>();
// Add to the covered content set all the dependencies of the test flows
for (SlangTestCase testCase : testCases.values()) {
String testFlowPath = testCase.getTestFlowPath();
Executable testFlowModel;
if (testFlowModels.containsKey(testFlowPath)) {
testFlowModel = testFlowModels.get(testFlowPath);
} else {
testFlowModel = contentSlangModels.get(testFlowPath);
}
if (testFlowModel == null) {
continue;
}
addAllDependenciesToCoveredContent(coveredContent,
testFlowModel.getExecutableDependencies(), contentSlangModels);
}
Set contentExecutablesNames = contentSlangModels.keySet();
// Add to the covered content set also all the direct test case's test flows,
// which are part of the tested content
for (SlangTestCase testCase : testCases.values()) {
String testFlowPath = testCase.getTestFlowPath();
// Add the test flow only if it part of the content, and not of the test flows
if (contentExecutablesNames.contains(testFlowPath)) {
coveredContent.add(testFlowPath);
}
}
// Create the uncovered content set from the content which does not appear in the covered set
for (String contentModelName : contentExecutablesNames) {
if (!coveredContent.contains(contentModelName)) {
uncoveredContent.add(contentModelName);
}
}
runTestsResults.addCoveredExecutables(coveredContent);
runTestsResults.addUncoveredExecutables(uncoveredContent);
}
/**
* Collect recursively all the dependencies of an executable
*
* @param allDependencies
* @param directDependencies
* @param contentSlangModels
*/
private void addAllDependenciesToCoveredContent(Set allDependencies, Set directDependencies,
Map contentSlangModels) {
for (String dependency : directDependencies) {
if (allDependencies.contains(dependency)) {
continue;
}
allDependencies.add(dependency);
Executable executable = contentSlangModels.get(dependency);
// Executable will be null in case of a dependecy which is a test flow (and not patr of the content)
if (executable != null) {
addAllDependenciesToCoveredContent(allDependencies,
executable.getExecutableDependencies(), contentSlangModels);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy