io.cloudslang.lang.tools.build.SlangBuildMain 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 com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import io.cloudslang.lang.api.Slang;
import io.cloudslang.lang.commons.services.api.UserConfigurationService;
import io.cloudslang.lang.commons.services.impl.UserConfigurationServiceImpl;
import io.cloudslang.lang.logging.LoggingService;
import io.cloudslang.lang.logging.LoggingServiceImpl;
import io.cloudslang.lang.tools.build.commands.ApplicationArgs;
import io.cloudslang.lang.tools.build.tester.IRunTestResults;
import io.cloudslang.lang.tools.build.tester.TestRun;
import io.cloudslang.lang.tools.build.tester.parallel.report.SlangTestCaseRunReportGeneratorService;
import io.cloudslang.lang.tools.build.tester.parse.SlangTestCase;
import io.cloudslang.lang.tools.build.tester.runconfiguration.TestRunInfoService;
import io.cloudslang.score.events.ScoreEvent;
import io.cloudslang.score.events.ScoreEventListener;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import static io.cloudslang.lang.tools.build.ArgumentProcessorUtils.getBooleanFromPropertiesWithDefault;
import static io.cloudslang.lang.tools.build.ArgumentProcessorUtils.getEnumInstanceFromPropertiesWithDefault;
import static io.cloudslang.lang.tools.build.ArgumentProcessorUtils.getIntFromPropertiesWithDefaultAndRange;
import static io.cloudslang.lang.tools.build.ArgumentProcessorUtils.getListForPrint;
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;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_COVERAGE;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_PARALLEL_THREAD_COUNT;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_SUITES_PARALLEL;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_SUITES_RUN_UNSPECIFIED;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_SUITES_SEQUENTIAL;
import static io.cloudslang.lang.tools.build.SlangBuildMain.RunConfigurationProperties.TEST_SUITES_TO_RUN;
import static io.cloudslang.lang.tools.build.tester.SlangTestRunner.MAX_TIME_PER_TESTCASE_IN_MINUTES;
import static io.cloudslang.lang.tools.build.tester.SlangTestRunner.TEST_CASE_TIMEOUT_IN_MINUTES_KEY;
import static io.cloudslang.lang.tools.build.tester.parallel.services.ParallelTestCaseExecutorService.SLANG_TEST_RUNNER_THREAD_COUNT;
import static java.lang.Integer.parseInt;
import static java.lang.String.format;
import static java.lang.String.valueOf;
import static java.lang.System.getProperty;
import static java.lang.System.setProperty;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.isRegularFile;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.Paths.get;
import static java.util.Locale.ENGLISH;
import static org.apache.commons.collections4.ListUtils.removeAll;
import static org.apache.commons.collections4.ListUtils.union;
import static org.apache.commons.collections4.MapUtils.isNotEmpty;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.logging.log4j.Level.ERROR;
import static org.apache.logging.log4j.Level.INFO;
public class SlangBuildMain {
public static final String DEFAULT_TESTS = "default";
private static final String TEST_CASE_REPORT_LOCATION = "cloudslang.test.case.report.location";
private static final String CONTENT_DIR = File.separator + "content";
private static final String TEST_DIR = File.separator + "test";
private static final Logger log = LogManager.getLogger(SlangBuildMain.class);
private static final int MAX_THREADS_TEST_RUNNER = 32;
private static final String MESSAGE_NOT_SCHEDULED_FOR_RUN_RULES = "Rules '%s' defined in '%s' key " +
"are not scheduled for run.";
private static final String MESSAGE_TEST_SUITES_WITH_UNSPECIFIED_MAPPING = "Test suites '%s' have " +
"unspecified mapping. They will run in '%s' mode.";
private static final String PROPERTIES_FILE_EXTENSION = "properties";
private static final String DID_NOT_DETECT_RUN_CONFIGURATION_PROPERTIES_FILE = "Did not detect run " +
"configuration properties file at path '%s'. " +
"Check that the path you are using is an absolute path. " +
"Check that the path separator is '\\\\' for Windows, or '/' for Linux.";
private static final String NEW_LINE = System.lineSeparator();
private static final String MESSAGE_BOTH_PARALLEL_AND_SEQUENTIAL_EXECUTION = "The '%s' suites are configured for " +
"both parallel and sequential execution." +
" Each test suite must have only one execution mode (parallel or sequential).";
private static final String MESSAGE_ERROR_LOADING_SMART_MODE_CONFIG_FILE = "Error loading smart " +
"mode configuration file:";
private static final String LOG4J_CONFIGURATION_KEY = "log4j.configurationFile";
private static final String LOG4J_ERROR_PREFIX = "log4j: error loading log4j properties file.";
private static final String LOG4J_ERROR_SUFFIX = "Using default configuration.";
private static final String APP_HOME_KEY = "app.home";
// This class is a used in the interaction with the run configuration property file
static class RunConfigurationProperties {
static final String TEST_COVERAGE = "test.coverage";
static final String TEST_PARALLEL_THREAD_COUNT = "test.parallel.thread.count";
static final String TEST_SUITES_TO_RUN = "test.suites.active";
static final String TEST_SUITES_PARALLEL = "test.suites.parallel";
static final String TEST_SUITES_SEQUENTIAL = "test.suites.sequential";
static final String TEST_SUITES_RUN_UNSPECIFIED = "test.suites.run.mode.unspecified";
}
// The possible ways to execute a test case
public enum TestCaseRunMode {
PARALLEL,
SEQUENTIAL
}
// The typical configuration on how to configure the run of all tests as a bulk
public enum BulkRunMode {
ALL_PARALLEL,
ALL_SEQUENTIAL,
POSSIBLY_MIXED
}
// The possible ways to run tests: everything or the tests affected by current changelist
public enum BuildMode {
BASIC,
CHANGED
}
public static void main(String[] args) {
loadUserProperties();
configureLog4j();
ApplicationArgs appArgs = new ApplicationArgs();
parseArgs(args, appArgs);
String projectPath = parseProjectPathArg(appArgs);
final String contentPath = defaultIfEmpty(appArgs.getContentRoot(), projectPath + CONTENT_DIR);
final String testsPath = defaultIfEmpty(appArgs.getTestRoot(), projectPath + TEST_DIR);
List testSuites = parseTestSuites(appArgs);
boolean shouldPrintCoverageData = appArgs.shouldOutputCoverage();
boolean runTestsInParallel = appArgs.isParallel();
int threadCount = parseThreadCountArg(appArgs, runTestsInParallel);
String testCaseTimeout = parseTestTimeout(appArgs);
setProperty(TEST_CASE_TIMEOUT_IN_MINUTES_KEY, valueOf(testCaseTimeout));
final boolean shouldValidateDescription = appArgs.shouldValidateDescription();
final boolean shouldValidateCheckstyle = appArgs.shouldValidateCheckstyle();
String runConfigPath = FilenameUtils.normalize(appArgs.getRunConfigPath());
BuildMode buildMode = null;
Set changedFiles = null;
try {
String smartModePath = appArgs.getChangesOnlyConfigPath();
if (StringUtils.isEmpty(smartModePath)) {
buildMode = BuildMode.BASIC;
changedFiles = new HashSet<>();
printBuildModeInfo(buildMode);
} else {
buildMode = BuildMode.CHANGED;
changedFiles = readChangedFilesFromSource(smartModePath);
printBuildModeInfo(buildMode);
}
} catch (Exception ex) {
log.error("Exception: " + ex.getMessage());
System.exit(1);
}
// Override with the values from the file if configured
List testSuitesParallel = new ArrayList<>();
List testSuitesSequential = new ArrayList<>();
BulkRunMode bulkRunMode = runTestsInParallel ? ALL_PARALLEL : ALL_SEQUENTIAL;
TestCaseRunMode unspecifiedTestSuiteRunMode = runTestsInParallel ?
TestCaseRunMode.PARALLEL : TestCaseRunMode.SEQUENTIAL;
if (get(runConfigPath).isAbsolute() && isRegularFile(get(runConfigPath), NOFOLLOW_LINKS) &&
equalsIgnoreCase(PROPERTIES_FILE_EXTENSION, FilenameUtils.getExtension(runConfigPath))) {
Properties runConfigurationProperties = ArgumentProcessorUtils.getPropertiesFromFile(runConfigPath);
shouldPrintCoverageData = getBooleanFromPropertiesWithDefault(TEST_COVERAGE, shouldPrintCoverageData,
runConfigurationProperties);
threadCount = getIntFromPropertiesWithDefaultAndRange(TEST_PARALLEL_THREAD_COUNT,
Runtime.getRuntime().availableProcessors(),
runConfigurationProperties, 1, MAX_THREADS_TEST_RUNNER + 1);
testSuites = getTestSuitesForKey(runConfigurationProperties, TEST_SUITES_TO_RUN);
testSuitesParallel = getTestSuitesForKey(runConfigurationProperties, TEST_SUITES_PARALLEL);
testSuitesSequential = getTestSuitesForKey(runConfigurationProperties, TEST_SUITES_SEQUENTIAL);
addErrorIfSameTestSuiteIsInBothParallelOrSequential(testSuitesParallel, testSuitesSequential);
unspecifiedTestSuiteRunMode = getEnumInstanceFromPropertiesWithDefault(TEST_SUITES_RUN_UNSPECIFIED,
unspecifiedTestSuiteRunMode, runConfigurationProperties);
addWarningsForMisconfiguredTestSuites(unspecifiedTestSuiteRunMode, testSuites,
testSuitesSequential, testSuitesParallel);
bulkRunMode = POSSIBLY_MIXED;
} else { // Warn when file is misconfigured, relative path, file does not exist or is not a properties file
log.info(format(DID_NOT_DETECT_RUN_CONFIGURATION_PROPERTIES_FILE, runConfigPath));
}
String testCaseReportLocation = getProperty(TEST_CASE_REPORT_LOCATION);
if (StringUtils.isBlank(testCaseReportLocation)) {
log.info("Test case report location property [" + TEST_CASE_REPORT_LOCATION +
"] is not defined. Report will be skipped.");
}
// Setting thread count for visibility in ParallelTestCaseExecutorService
setProperty(SLANG_TEST_RUNNER_THREAD_COUNT, valueOf(threadCount));
log.info(NEW_LINE + "------------------------------------------------------------");
log.info("Building project: " + projectPath);
log.info("Content root is at: " + contentPath);
log.info("Test root is at: " + testsPath);
log.info("Active test suites are: " + getListForPrint(testSuites));
log.info("Parallel run mode is configured for test suites: " +
getListForPrint(testSuitesParallel));
log.info("Sequential run mode is configured for test suites: " +
getListForPrint(testSuitesSequential));
log.info("Default run mode '" + unspecifiedTestSuiteRunMode.name().toLowerCase() +
"' is configured for test suites: " +
getListForPrint(getDefaultRunModeTestSuites(testSuites, testSuitesParallel, testSuitesSequential)));
log.info("Bulk run mode for tests: " + getBulkModeForPrint(bulkRunMode));
log.info("Print coverage data: " + valueOf(shouldPrintCoverageData));
log.info("Validate description: " + valueOf(shouldValidateDescription));
log.info("Validate checkstyle: " + valueOf(shouldValidateCheckstyle));
log.info("Thread count: " + threadCount);
log.info("Test case timeout in minutes: " + (isEmpty(testCaseTimeout) ?
valueOf(MAX_TIME_PER_TESTCASE_IN_MINUTES) : testCaseTimeout));
log.info(NEW_LINE + "Loading...");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/testRunnerContext.xml");
context.registerShutdownHook();
SlangBuilder slangBuilder = context.getBean(SlangBuilder.class);
LoggingService loggingService = context.getBean(LoggingServiceImpl.class);
Slang slang = context.getBean(Slang.class);
try {
updateTestSuiteMappings(context.getBean(TestRunInfoService.class), testSuitesParallel,
testSuitesSequential, testSuites, unspecifiedTestSuiteRunMode);
registerEventHandlers(slang);
List exceptions = new ArrayList<>();
SlangBuildResults buildResults =
slangBuilder.buildSlangContent(projectPath, contentPath, testsPath, testSuites,
shouldValidateDescription, shouldValidateCheckstyle, bulkRunMode, buildMode, changedFiles);
exceptions.addAll(buildResults.getCompilationExceptions());
if (exceptions.size() > 0) {
logErrors(exceptions, projectPath, loggingService);
}
IRunTestResults runTestsResults = buildResults.getRunTestsResults();
Map skippedTests = runTestsResults.getSkippedTests();
if (isNotEmpty(skippedTests)) {
printSkippedTestsSummary(skippedTests, loggingService);
}
printPassedTests(runTestsResults, loggingService);
if (shouldPrintCoverageData) {
printTestCoverageData(runTestsResults, loggingService);
}
if (isNotEmpty(runTestsResults.getFailedTests())) {
printBuildFailureSummary(projectPath, runTestsResults, loggingService);
} else {
printBuildSuccessSummary(contentPath, buildResults, runTestsResults, loggingService);
}
loggingService.waitForAllLogTasksToFinish();
generateTestCaseReport(
context.getBean(SlangTestCaseRunReportGeneratorService.class),
runTestsResults,
testCaseReportLocation
);
System.exit(isNotEmpty(runTestsResults.getFailedTests()) ? 1 : 0);
} catch (Throwable e) {
logErrorsPrefix(loggingService);
loggingService.logEvent(ERROR, "Exception: " + e.getMessage());
logErrorsSuffix(projectPath, loggingService);
loggingService.waitForAllLogTasksToFinish();
System.exit(1);
}
}
private static void configureLog4j() {
String configFilename = System.getProperty(LOG4J_CONFIGURATION_KEY);
String errorMessage = null;
try {
if (StringUtils.isEmpty(configFilename)) {
errorMessage = "Config file name is empty.";
} else {
String normalizedPath = FilenameUtils.normalize(configFilename);
if (normalizedPath == null) {
errorMessage = "Normalized config file path is null.";
} else if (!isUnderAppHome(normalizedPath, getNormalizedApplicationHome())) {
errorMessage = "Normalized config file path[" + normalizedPath + "] " +
"is not under application home directory";
} else {
if (!isRegularFile(get(normalizedPath), NOFOLLOW_LINKS)) {
errorMessage = "Normalized config file path[" + normalizedPath + "]" +
" does not lead to a regular file.";
} else {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
context.setConfigLocation(new File(normalizedPath).toURI());
}
}
}
} catch (RuntimeException ex) {
errorMessage = ex.getMessage();
}
if (StringUtils.isNotEmpty(errorMessage)) {
System.out.printf("%s%n\t%s%n\t%s%n", LOG4J_ERROR_PREFIX, errorMessage, LOG4J_ERROR_SUFFIX);
}
}
private static boolean isUnderAppHome(String normalizedFilePath, String normalizedAppHome) {
return normalizedFilePath.startsWith(normalizedAppHome);
}
private static String getNormalizedApplicationHome() {
String appHome = System.getProperty(APP_HOME_KEY);
if (StringUtils.isEmpty(appHome)) {
throw new RuntimeException(APP_HOME_KEY + " system property is empty");
}
String normalizedAppHome = FilenameUtils.normalize(appHome);
if (normalizedAppHome == null) {
throw new RuntimeException("Normalized app home path is null.");
}
return normalizedAppHome;
}
private static void printBuildModeInfo(BuildMode buildMode) {
log.info("Build mode set to: " + buildMode);
}
private static Set readChangedFilesFromSource(String filePath) throws IOException {
String normalizedPath = FilenameUtils.normalize(filePath);
if (!get(normalizedPath).isAbsolute()) {
throw new RuntimeException(MESSAGE_ERROR_LOADING_SMART_MODE_CONFIG_FILE +
" Path[" + normalizedPath + "] is not an absolute path.");
}
if (!isRegularFile(get(normalizedPath), NOFOLLOW_LINKS)) {
throw new RuntimeException(MESSAGE_ERROR_LOADING_SMART_MODE_CONFIG_FILE +
" Path[" + normalizedPath + "] does not lead to a regular file.");
}
return ArgumentProcessorUtils.loadChangedItems(normalizedPath);
}
private static void addErrorIfSameTestSuiteIsInBothParallelOrSequential(List testSuitesParallel,
List testSuitesSequential) {
final List intersection = ListUtils.intersection(testSuitesParallel, testSuitesSequential);
if (!intersection.isEmpty()) {
final String message = String.format(MESSAGE_BOTH_PARALLEL_AND_SEQUENTIAL_EXECUTION,
getListForPrint(intersection));
log.error(message);
throw new IllegalStateException();
}
}
/**
* @param bulkRunMode the mode to configure the run of all tests
* @return String friendly version for print to the log or console
*/
private static String getBulkModeForPrint(final BulkRunMode bulkRunMode) {
return bulkRunMode.toString().replace("_", " ").toLowerCase(ENGLISH);
}
/**
* @param testRunInfoService the service responsible for managing run information
* @param parallelSuites the suite names to be executed in parallel
* @param sequentialSuites the suite names to be executed in sequential manner
* @param activeSuites the suite names that are active
* @param unspecifiedTestSuiteRunMode the default run mode for suites that don't explicitly mention a run mode.
*/
private static void updateTestSuiteMappings(final TestRunInfoService testRunInfoService,
final List parallelSuites,
final List sequentialSuites, final List activeSuites,
final TestCaseRunMode unspecifiedTestSuiteRunMode) {
testRunInfoService.setRunModeForTestSuites(parallelSuites, TestCaseRunMode.PARALLEL);
testRunInfoService.setRunModeForTestSuites(sequentialSuites, TestCaseRunMode.SEQUENTIAL);
testRunInfoService.setRunModeForTestSuites(
getDefaultRunModeTestSuites(activeSuites, parallelSuites, sequentialSuites),
unspecifiedTestSuiteRunMode);
}
/**
* @param activeSuites the suite names that are active
* @param parallelSuites the suite names to be executed in parallel
* @param sequentialSuites the suite names to be executed in sequential manner
* @return
*/
private static List getDefaultRunModeTestSuites(final List activeSuites,
final List parallelSuites,
final List sequentialSuites) {
return removeAll(new ArrayList<>(activeSuites), union(parallelSuites, sequentialSuites));
}
/**
* @param unspecifiedTestSuiteRunMode the default run mode for suites that don't explicitly mention a run mode.
* @param activeSuites the suite names that are active
* @param sequentialSuites the suite names to be executed in sequential manner
* @param parallelSuites the suite names to be executed in parallel
*/
private static void addWarningsForMisconfiguredTestSuites(final TestCaseRunMode unspecifiedTestSuiteRunMode,
final List activeSuites,
final List sequentialSuites,
final List parallelSuites) {
addWarningForSubsetOfRules(activeSuites, sequentialSuites, TEST_SUITES_SEQUENTIAL);
addWarningForSubsetOfRules(activeSuites, parallelSuites, TEST_SUITES_PARALLEL);
addInformativeNoteForUnspecifiedRules(unspecifiedTestSuiteRunMode, activeSuites,
sequentialSuites, parallelSuites);
}
/**
* Displays an informative message in case there is at least one test suite left for default run mode.
*
* @param unspecifiedTestSuiteRunMode the default run mode for suites that don't explicitly mention a run mode.
* @param activeSuites the suite names that are active
* @param sequentialSuites the suite names to be executed in sequential manner
* @param parallelSuites the suite names to be executed in parallel
*/
private static void addInformativeNoteForUnspecifiedRules(final TestCaseRunMode unspecifiedTestSuiteRunMode,
final List activeSuites,
final List sequentialSuites,
final List parallelSuites) {
List union = union(sequentialSuites, parallelSuites);
if (!union.containsAll(activeSuites)) {
List copy = new ArrayList<>(activeSuites);
copy.removeAll(union);
log.info(format(MESSAGE_TEST_SUITES_WITH_UNSPECIFIED_MAPPING,
getListForPrint(copy), unspecifiedTestSuiteRunMode.name()));
}
}
/**
* Displays a warning message for test suites that have rules defined for sequential or parallel execution
* but are not in active test suites.
*
* @param testSuites suite names contained in 'container' suites
* @param testSuitesContained suite names contained in 'contained' suites
* @param key run configuration property key
*/
private static void addWarningForSubsetOfRules(List testSuites, List testSuitesContained,
String key) {
List intersectWithContained = ListUtils.intersection(testSuites, testSuitesContained);
if (intersectWithContained.size() != testSuitesContained.size()) {
List notScheduledForRun = new ArrayList<>(testSuitesContained);
notScheduledForRun.removeAll(intersectWithContained);
log.warn(format(MESSAGE_NOT_SCHEDULED_FOR_RUN_RULES, getListForPrint(notScheduledForRun), key));
}
}
/**
* Returns the names of the suites from the run configuration java.util.Properties object at a certain key.
*
* @param runConfigurationProperties
* @param key
* @return
*/
private static List getTestSuitesForKey(Properties runConfigurationProperties, String key) {
final String valueList = runConfigurationProperties.getProperty(key);
return ArgumentProcessorUtils.parseTestSuitesToList(valueList);
}
private static void logErrors(List exceptions, String projectPath,
final LoggingService loggingService) {
logErrorsPrefix(loggingService);
for (RuntimeException runtimeException : exceptions) {
loggingService.logEvent(ERROR, "Exception: " + runtimeException.getMessage());
}
logErrorsSuffix(projectPath, loggingService);
loggingService.waitForAllLogTasksToFinish();
System.exit(1);
}
private static void logErrorsSuffix(String projectPath, final LoggingService loggingService) {
loggingService.logEvent(ERROR, "FAILURE: Validation of slang files for project: \"" +
projectPath + "\" failed.");
loggingService.logEvent(ERROR, "------------------------------------------------------------");
loggingService.logEvent(ERROR, "");
}
private static void logErrorsPrefix(final LoggingService loggingService) {
loggingService.logEvent(ERROR, "");
loggingService.logEvent(ERROR, "------------------------------------------------------------");
}
private static void generateTestCaseReport(
SlangTestCaseRunReportGeneratorService reportGeneratorService,
IRunTestResults runTestsResults,
String testCaseReportLocation) throws IOException {
if (StringUtils.isNotBlank(testCaseReportLocation)) {
Path reportDirectoryPath = get(testCaseReportLocation);
if (!exists(reportDirectoryPath)) {
createDirectories(reportDirectoryPath);
}
reportGeneratorService.generateReport(runTestsResults, reportDirectoryPath.toString());
}
}
@SuppressWarnings("Duplicates")
private static void loadUserProperties() {
try {
UserConfigurationService userConfigurationService = new UserConfigurationServiceImpl();
userConfigurationService.loadUserProperties();
} catch (Exception ex) {
System.out.println("Error occurred while loading user configuration: " + ex.getMessage());
ex.printStackTrace();
}
}
private static void parseArgs(String[] args, ApplicationArgs appArgs) {
try {
JCommander commander = new JCommander(appArgs, args);
if (appArgs.isHelp()) {
commander.usage();
System.exit(0);
}
} catch (ParameterException e) {
System.out.println(e.getMessage());
System.out.println("You can use '--help' for usage");
System.exit(1);
}
}
private static List parseTestSuites(ApplicationArgs appArgs) {
final List testSuitesArg = ListUtils.defaultIfNull(appArgs.getTestSuites(), new ArrayList());
return ArgumentProcessorUtils.parseTestSuitesToList(testSuitesArg);
}
private static String parseTestTimeout(ApplicationArgs appArgs) {
Map dynamicArgs = appArgs.getDynamicParams();
return dynamicArgs.get(TEST_CASE_TIMEOUT_IN_MINUTES_KEY);
}
private static int parseThreadCountArg(ApplicationArgs appArgs, boolean isParallel) {
if (!isParallel) {
return 1;
} else {
int defaultThreadCount = Runtime.getRuntime().availableProcessors();
String threadCountErrorMessage = format("Thread count is misconfigured. The thread count value must be a " +
"positive integer less than or equal to %d. Using %d threads.",
MAX_THREADS_TEST_RUNNER, defaultThreadCount);
try {
String stringThreadCount = appArgs.getThreadCount();
if (stringThreadCount != null) {
int threadCount = parseInt(stringThreadCount);
if ((threadCount > 0) && (threadCount <= MAX_THREADS_TEST_RUNNER)) {
return threadCount;
} else {
log.warn(threadCountErrorMessage);
}
}
} catch (NumberFormatException nfEx) {
log.warn(threadCountErrorMessage);
}
return defaultThreadCount;
}
}
private static void printBuildSuccessSummary(String contentPath, SlangBuildResults buildResults,
IRunTestResults runTestsResults,
final LoggingService loggingService) {
loggingService.logEvent(INFO, "");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "BUILD SUCCESS");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "Found " + buildResults.getNumberOfCompiledSources() +
" slang files under directory: \"" + contentPath + "\" and all are valid.");
printNumberOfPassedAndSkippedTests(runTestsResults, loggingService);
loggingService.logEvent(INFO, "");
}
private static void printNumberOfPassedAndSkippedTests(IRunTestResults runTestsResults,
final LoggingService loggingService) {
loggingService.logEvent(INFO, runTestsResults.getPassedTests().size() + " test cases passed");
Map skippedTests = runTestsResults.getSkippedTests();
if (skippedTests.size() > 0) {
loggingService.logEvent(INFO, skippedTests.size() + " test cases skipped");
}
}
private static void printPassedTests(IRunTestResults runTestsResults, final LoggingService loggingService) {
if (runTestsResults.getPassedTests().size() > 0) {
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "Following " + runTestsResults.getPassedTests().size() +
" test cases passed:");
for (Map.Entry passedTest : runTestsResults.getPassedTests().entrySet()) {
String testCaseReference = SlangTestCase.generateTestCaseReference(passedTest.getValue().getTestCase());
loggingService.logEvent(INFO, "- " + testCaseReference.replaceAll("\n", "\n\t"));
}
}
}
private static void printBuildFailureSummary(String projectPath, IRunTestResults runTestsResults,
final LoggingService loggingService) {
printNumberOfPassedAndSkippedTests(runTestsResults, loggingService);
final Map failedTests = runTestsResults.getFailedTests();
logErrorsPrefix(loggingService);
loggingService.logEvent(ERROR, "BUILD FAILURE");
loggingService.logEvent(ERROR, "------------------------------------------------------------");
loggingService.logEvent(ERROR, "CloudSlang build for repository: \"" + projectPath +
"\" failed due to failed tests.");
loggingService.logEvent(ERROR, "Following " + failedTests.size() + " tests failed:");
for (Map.Entry failedTest : failedTests.entrySet()) {
String failureMessage = failedTest.getValue().getMessage();
loggingService.logEvent(ERROR, "- " + failureMessage.replaceAll("\n", "\n\t"));
}
loggingService.logEvent(ERROR, "");
}
private static void printSkippedTestsSummary(Map skippedTests,
final LoggingService loggingService) {
loggingService.logEvent(INFO, "");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "Following " + skippedTests.size() + " tests were skipped:");
for (Map.Entry skippedTest : skippedTests.entrySet()) {
String message = skippedTest.getValue().getMessage();
loggingService.logEvent(INFO, "- " + message.replaceAll("\n", "\n\t"));
}
}
private static void printTestCoverageData(IRunTestResults runTestsResults, final LoggingService loggingService) {
printCoveredExecutables(runTestsResults.getCoveredExecutables(), loggingService);
printUncoveredExecutables(runTestsResults.getUncoveredExecutables(), loggingService);
int coveredExecutablesSize = runTestsResults.getCoveredExecutables().size();
int uncoveredExecutablesSize = runTestsResults.getUncoveredExecutables().size();
int totalNumberOfExecutables = coveredExecutablesSize + uncoveredExecutablesSize;
double coveragePercentage = (double) coveredExecutablesSize / (double) totalNumberOfExecutables * 100;
loggingService.logEvent(INFO, "");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, ((int) coveragePercentage) + "% of the content has tests");
loggingService.logEvent(INFO, "Out of " + totalNumberOfExecutables + " executables, " +
coveredExecutablesSize + " executables have tests");
}
private static void printCoveredExecutables(Set coveredExecutables, final LoggingService loggingService) {
loggingService.logEvent(INFO, "");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "Following " + coveredExecutables.size() + " executables have tests:");
for (String executable : coveredExecutables) {
loggingService.logEvent(INFO, "- " + executable);
}
}
private static void printUncoveredExecutables(Set uncoveredExecutables,
final LoggingService loggingService) {
loggingService.logEvent(INFO, "");
loggingService.logEvent(INFO, "------------------------------------------------------------");
loggingService.logEvent(INFO, "Following " + uncoveredExecutables.size() +
" executables do not have tests:");
for (String executable : uncoveredExecutables) {
loggingService.logEvent(INFO, "- " + executable);
}
}
private static String parseProjectPathArg(ApplicationArgs args) {
String repositoryPath;
if (args.getProjectRoot() != null) {
repositoryPath = args.getProjectRoot();
// if only one parameter was passed, we treat it as the project root
// i.e. './cslang-builder some/path/to/project'
} else if (args.getParameters().size() == 1) {
repositoryPath = args.getParameters().get(0);
} else {
repositoryPath = System.getProperty("user.dir");
}
repositoryPath = FilenameUtils.separatorsToSystem(repositoryPath);
Validate.isTrue(new File(repositoryPath).isDirectory(),
"Directory path argument \'" + repositoryPath + "\' does not lead to a directory");
return repositoryPath;
}
private static void registerEventHandlers(Slang slang) {
slang.subscribeOnAllEvents(new ScoreEventListener() {
@Override
public synchronized void onEvent(ScoreEvent event) {
logEvent(event);
}
});
}
private static void logEvent(ScoreEvent event) {
log.debug(("Event received: " + event.getEventType() + " Data is: " + event.getData()));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy