fr.ens.biologie.genomique.eoulsan.it.IT.java Source code

Java tutorial

Introduction

Here is the source code for fr.ens.biologie.genomique.eoulsan.it.IT.java

Source

/*
 *                  Eoulsan development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public License version 2.1 or
 * later and CeCILL-C. This should be distributed with the code.
 * If you do not have a copy, see:
 *
 *      http://www.gnu.org/licenses/lgpl-2.1.txt
 *      http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt
 *
 * Copyright for this code is held jointly by the Genomic platform
 * of the Institut de Biologie de l'cole normale suprieure and
 * the individual authors. These should be listed in @author doc
 * comments.
 *
 * For more information on the Eoulsan project and its aims,
 * or to join the Eoulsan Google group, visit the home page
 * at:
 *
 *      http://outils.genomique.biologie.ens.fr/eoulsan
 *
 */
package fr.ens.biologie.genomique.eoulsan.it;

import static com.google.common.io.Files.newReader;
import static fr.ens.biologie.genomique.eoulsan.EoulsanLogger.getLogger;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.COMMAND_TO_GENERATE_MANUALLY_CONF_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.COMMAND_TO_LAUNCH_APPLICATION_CONF_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.POSTTREATMENT_GLOBAL_SCRIPT_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.POST_TEST_SCRIPT_CONF_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.PRETREATMENT_GLOBAL_SCRIPT_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.PRE_TEST_SCRIPT_CONF_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.RUNTIME_IT_MAXIMUM_DEFAULT;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.SUCCESS_IT_DELETE_FILE_CONF_KEY;
import static fr.ens.biologie.genomique.eoulsan.it.ITFactory.evaluateExpressions;
import static fr.ens.biologie.genomique.eoulsan.it.ITSuite.createRelativeOrAbsoluteSymbolicLink;
import static fr.ens.biologie.genomique.eoulsan.util.FileUtils.checkExistingDirectoryFile;
import static fr.ens.biologie.genomique.eoulsan.util.FileUtils.checkExistingFile;
import static fr.ens.biologie.genomique.eoulsan.util.FileUtils.recursiveDelete;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.compress.utils.Charsets;
import org.testng.annotations.Test;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Stopwatch;

import fr.ens.biologie.genomique.eoulsan.EoulsanException;
import fr.ens.biologie.genomique.eoulsan.Globals;

/**
 * The class manage an integrated test for realize regression test on the
 * application used to generate data. It generate expected data directory or
 * data to test directory, in this case the comparison with expected data was
 * launch.
 * @author Sandrine Perrin
 * @since 2.0
 */
public class IT {

    public static final Splitter CMD_LINE_SPLITTER = Splitter.on(' ').trimResults().omitEmptyStrings();
    public static final String SEPARATOR = " ";

    /** Prefix for set environment variable in test configuration file. */
    static final String PREFIX_ENV_VAR = "env.var.";

    private static final List<String> PROPERTIES_TO_COMPILE = loadList();

    private static final String TEST_SOURCE_LINK_NAME = "test-source";
    private static final String ENV_FILENAME = "ENV";

    /** Variables. */
    private final Properties testConf;
    private final String testName;
    private final String description;
    private final File applicationPath;
    private final File testDataDirectory;
    private final File outputTestDirectory;
    private final File expectedTestDirectory;

    /** Patterns. */
    private final String fileToComparePatterns;
    private final String excludeToComparePatterns;
    private final String fileToRemovePatterns;
    /** Patterns to check file and compare size. */
    private final String checkExistenceFilePatterns;
    /** Patterns to check file not exist in test directory. */
    private final String checkAbsenceFilePatterns;

    private final boolean generateExpectedDirectoryTestData;
    private final boolean generateAllExpectedDirectoryTest;
    private final boolean generateNewExpectedDirectoryTests;
    // Case the expected data was generate manually (not with testing application)
    private final boolean manualGenerationExpectedData;

    // Instance
    private final ITResult itResult;
    private final List<String> environmentVariables;
    private final ITSuite itSuite;
    private final String checkLengthFilePatterns;

    // Compile the result comparison from all tests
    private ITOutput itOutput = null;
    private boolean isRemoveFileRequired;

    /**
     * Launch test execution, first generate data directory corresponding to the
     * arguments: expected data or data to test. If it is data to test then launch
     * comparison.
     * @throws Exception if an error occurs while execute script or comparison
     */
    @Test
    public final void launchTest() throws Exception {

        // Notify the suite of the beginning of the current test
        this.itSuite.notifyStartTest();

        // Init logger
        final Stopwatch timer = Stopwatch.createStarted();
        getLogger().info("Start test " + this.testName);
        getLogger().info("Test directory " + this.testDataDirectory.getAbsolutePath());
        getLogger().info("Output directory " + this.outputTestDirectory.getAbsolutePath());

        try {
            // Check data to generate
            if (!isDataNeededToBeGenerated()) {
                this.itResult.asNothingToDo();
                // Nothing to do
                return;
            }

            // Build output directory with source files
            buildOutputDirectory();

            // Launch scripts
            launchScriptsTest(this.itResult);

            // Treat result application directory
            this.itOutput = new ITOutput(this.outputTestDirectory, this.fileToComparePatterns,
                    this.excludeToComparePatterns, this.checkLengthFilePatterns, this.checkExistenceFilePatterns,
                    this.checkAbsenceFilePatterns, this.fileToRemovePatterns);

            if (this.generateExpectedDirectoryTestData) {
                this.itResult.asGeneratedData();

                // Build expected directory if necessary
                createExpectedDirectory();

                // Copy files corresponding to pattern in expected data directory
                this.itOutput.copyFiles(this.expectedTestDirectory);

            } else {

                // Case comparison between expected and output test directory
                final Set<ITOutputComparisonResult> results = this.itOutput.compareTo(new ITOutput(
                        this.expectedTestDirectory, this.fileToComparePatterns, this.excludeToComparePatterns,
                        this.checkLengthFilePatterns, this.checkExistenceFilePatterns,
                        this.checkAbsenceFilePatterns, this.fileToRemovePatterns));

                this.itResult.addComparisonsResults(results);

                // Check if at least on comparison fail, must throw an exception
                if (!this.itResult.isSuccess()) {
                    throw this.itResult.getException();
                }

            }

        } catch (final Throwable e) {

            this.itResult.setException(e);
            throw new Exception(this.itResult.createReportTestngMessage());

        } finally {

            if (this.itOutput != null) {
                // IT succeeded
                this.itOutput.deleteFileMatchingOnPattern(this.itResult, this.isRemoveFileRequired);
            }

            timer.stop();

            getLogger().info("End of test " + this.testName);

            // Set success on generate data in expected directory
            this.itResult.createReportFile(timer.elapsed(TimeUnit.MILLISECONDS));

            // Notify the suite of the end of the current test
            this.itSuite.notifyEndTest(this.itResult);

        }
    }

    /**
     * Load list with patterns which values are compiled between global
     * configuration file and test configuration file.
     * @return the list
     */
    private static List<String> loadList() {

        final List<String> l = new ArrayList<>();

        l.add(ITFactory.EXCLUDE_TO_COMPARE_PATTERNS_CONF_KEY);
        l.add(ITFactory.FILE_TO_COMPARE_PATTERNS_CONF_KEY);
        l.add(ITFactory.FILE_TO_REMOVE_CONF_KEY);
        l.add(ITFactory.CHECK_ABSENCE_FILE_PATTERNS_CONF_KEY);
        l.add(ITFactory.CHECK_EXISTENCE_FILE_PATTERNS_CONF_KEY);
        l.add(ITFactory.CHECK_LENGTH_FILE_PATTERNS_CONF_KEY);

        return Collections.unmodifiableList(l);
    }

    /**
     * Checks if the specific key of property is included in properties to compile
     * value between configuration file.
     * @param keyToFind the key to find.
     * @return true, if is key in compile properties otherwise false.
     */
    private boolean isKeyInCompileProperties(final String keyToFind) {

        for (String key : PROPERTIES_TO_COMPILE) {
            if (key.equals(keyToFind)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Launch all scripts defined for the test.
     * @throws Throwable if an error occurs while execute script or output
     *           directory is missing
     */
    private void launchScriptsTest(final ITResult itResult) throws Throwable {

        checkExistingDirectoryFile(this.outputTestDirectory, "output test directory");

        // Save environment variable process in file
        saveEnvironmentVariable();

        final ITCommandExecutor cmdExecutor = new ITCommandExecutor(this.testConf, this.outputTestDirectory,
                this.environmentVariables, getDurationMaxInMinutes());

        final boolean isApplicationCmdLine = true;

        // Generated test directory
        // Optional run pre-treatment global script, before specific of the test
        executeCommand(cmdExecutor, itResult, PRETREATMENT_GLOBAL_SCRIPT_KEY, "PRE_SCRIPT_GLOBAL",
                "global prescript");

        // Optional script, pre-treatment before launch application
        executeCommand(cmdExecutor, itResult, PRE_TEST_SCRIPT_CONF_KEY, "PRE_SCRIPT", "test prescript");

        // Execute application
        if (this.generateExpectedDirectoryTestData && this.manualGenerationExpectedData) {

            // Case generate expected data manually only it doesn't exists
            executeCommand(cmdExecutor, itResult, COMMAND_TO_GENERATE_MANUALLY_CONF_KEY, "",
                    "manual script to generate data", isApplicationCmdLine);

        } else {

            // Case execute testing application
            executeCommand(cmdExecutor, itResult, COMMAND_TO_LAUNCH_APPLICATION_CONF_KEY, "", "application",
                    isApplicationCmdLine);
        }
        // Optional script, post-treatment after execution application and before
        // comparison between directories
        executeCommand(cmdExecutor, itResult, POST_TEST_SCRIPT_CONF_KEY, "POST_SCRIPT", "test postscript");

        // Optional run post-treatment global script, after specific of the test
        executeCommand(cmdExecutor, itResult, POSTTREATMENT_GLOBAL_SCRIPT_KEY, "POST_SCRIPT_GLOBAL",
                "global postscript");
    }

    /**
     * Execute command to run command line.
     * @param cmdExecutor ITCommandExecutor object
     * @param itResult ItResult object
     * @param keyConf key configuration to retrieve command line
     * @param suffixFilename suffix filename for output standard and error file on
     *          execution process
     * @param desc description on command line
     * @throws Throwable if an error occurs during execution process
     */
    private void executeCommand(final ITCommandExecutor cmdExecutor, final ITResult itResult, final String keyConf,
            final String suffixFilename, final String desc) throws Throwable {

        executeCommand(cmdExecutor, itResult, keyConf, suffixFilename, desc, false);
    }

    /**
     * Execute command to run command line.
     * @param cmdExecutor ITCommandExecutor object
     * @param itResult ItResult object
     * @param keyConf key configuration to retrieve command line
     * @param suffixFilename suffix filename for output standard and error file on
     *          execution process
     * @param desc description on command line
     * @param isApplication true if application to run, otherwise false
     *          corresponding to annexes script
     * @throws Throwable if an error occurs during execution process
     */
    private void executeCommand(final ITCommandExecutor cmdExecutor, final ITResult itResult, final String keyConf,
            final String suffixFilename, final String desc, final boolean isApplication) throws Throwable {

        // Execute command line and save standard and error output in file
        final ITCommandResult cmdResult = cmdExecutor.executeCommand(keyConf, suffixFilename, desc, isApplication);

        if (cmdResult == null) {
            return;
        }

        // Save result of execution command line
        itResult.addCommandResult(cmdResult);

        if (cmdResult.isCaughtException()) {
            throw cmdResult.getException();
        }
    }

    /**
     * Save all environment variables in file.
     */
    private void saveEnvironmentVariable() {
        final File envFile = new File(this.outputTestDirectory, ENV_FILENAME);

        // Write in file
        if (!(this.environmentVariables == null || this.environmentVariables.size() == 0)) {
            // Convert to string
            final String envToString = Joiner.on("\n").join(this.environmentVariables);

            try {
                com.google.common.io.Files.write(envToString, envFile, Charsets.UTF_8);

            } catch (final IOException e) {
                getLogger().warning("Error while writing environment variables in file: " + e.getMessage());
            }
        }
    }

    /**
     * Extract all environment variables setting in test configuration file.
     * @return null if not found or an string array in the format name=value
     */
    private List<String> extractEnvironmentVariables() {

        final List<String> envp = new ArrayList<>();

        // Add environment properties
        for (final Map.Entry<String, String> e : System.getenv().entrySet()) {
            envp.add(e.getKey() + "=" + e.getValue());
        }

        // Add setting environment variables from configuration test
        for (final Object o : this.testConf.keySet()) {
            final String keyProperty = (String) o;

            // Add property if key start with prefix setenv.
            if (keyProperty.startsWith(PREFIX_ENV_VAR)) {
                final String keyEnvp = keyProperty.substring(PREFIX_ENV_VAR.length());
                final String valEnvp = this.testConf.getProperty(keyProperty);
                envp.add(keyEnvp + "=" + valEnvp);
            }
        }

        // No variable found, return null
        if (envp.isEmpty()) {
            return null;
        }

        // Convert to array
        return Collections.unmodifiableList(envp);
    }

    /**
     * Check the expected data or data to test must be generated.
     * @return true if data must be generated
     * @throws IOException if an error occurs while creating directory.
     */
    private boolean isDataNeededToBeGenerated() throws IOException {

        if (!this.generateExpectedDirectoryTestData) {
            // Command for generate data to test, in all case it is true
            return true;
        }

        // Command for generate expected data test
        if (this.manualGenerationExpectedData) {
            // non regenerated expected directory if already exists
            return !this.expectedTestDirectory.exists();
        }

        // Regenerate all expected data directory, remove if always exists
        if (this.generateAllExpectedDirectoryTest) {
            return true;
        }

        // Generate only missing expected data directory
        return this.generateNewExpectedDirectoryTests && !this.expectedTestDirectory.exists();

    }

    /**
     * Create expected data directory if the test demand generate expected data,
     * if it doesn't exist. In case generate all expected data directory needed,
     * replace by a new.
     * @throws IOException if an error occurs when creating directory.
     */
    private void createExpectedDirectory() throws IOException {

        // Skip if data to test to generate
        if (!this.generateExpectedDirectoryTestData) {
            return;
        }

        // Check already exists
        if ((this.manualGenerationExpectedData || this.generateNewExpectedDirectoryTests)
                && this.expectedTestDirectory.exists()) {
            // Nothing to do
            return;
        }

        // Regenerate existing expected data directory
        if (this.generateAllExpectedDirectoryTest && this.expectedTestDirectory.exists()) {
            // Remove existing directory
            recursiveDelete(this.expectedTestDirectory);
        }

        // New check existing directory
        if (!this.expectedTestDirectory.exists()) {
            // Create new expected data directory
            if (!this.expectedTestDirectory.mkdir()) {
                throw new IOException(this.testName + ": error while create expected data directory: "
                        + this.expectedTestDirectory.getAbsolutePath());
            }
        }
    }

    /**
     * Build output directory for test, add symbolic link to source files useful.
     * @throws IOException if an error occurs while create the files.
     */
    private void buildOutputDirectory() throws IOException {

        if (this.outputTestDirectory.exists()) {
            throw new IOException(
                    "Test output directory already exists " + this.outputTestDirectory.getAbsolutePath());
        }

        // Create analysis directory and temporary directory
        if (!new File(this.outputTestDirectory + "/tmp").mkdirs()) {
            throw new IOException("Cannot create analysis directory " + this.outputTestDirectory.getAbsolutePath());
        }

        // Check input test directory
        checkExistingDirectoryFile(this.testDataDirectory, "input test directory");

        // Create a symbolic link to the input directory
        final Path testSourcePath = Files.createSymbolicLink(
                new File(this.outputTestDirectory, TEST_SOURCE_LINK_NAME).toPath(),
                this.testDataDirectory.toPath());

        // Create a symbolic link for each file from input data test directory
        for (final File file : this.testDataDirectory.listFiles()) {
            // TODO validate if it should limited only file, not directory
            if (file.isFile()) {

                final Path target = new File(testSourcePath.toFile(), file.getName()).toPath();
                final Path linkPath = new File(this.outputTestDirectory, file.getName()).toPath();

                // Create relative symbolic link
                createRelativeOrAbsoluteSymbolicLink(linkPath, target);

            }
        }

    }

    //
    // Privates methods
    //

    /**
     * Create the expected data test directory.
     * @return expected data directory for the test
     * @throws EoulsanException if the existing directory is empty
     * @throws IOException if the source test directory doesn't exist
     */
    private File retrieveExpectedDirectory() throws EoulsanException, IOException {

        checkExistingDirectoryFile(this.testDataDirectory, "output data parent directory");

        // Find directory start with expected
        final File[] expectedDirectories = this.testDataDirectory.listFiles(new FileFilter() {

            @Override
            public boolean accept(final File pathname) {
                return pathname.getName().startsWith("expected");
            }
        });

        // Execute test, expected must be existing
        if (expectedDirectories.length == 0 && !this.generateExpectedDirectoryTestData) {
            throw new EoulsanException(this.testName + ": no expected directory found to launch test in "
                    + this.testDataDirectory.getAbsolutePath());
        }

        // No test directory found
        if (expectedDirectories.length == 0) {

            // Build expected directory name
            if (this.generateExpectedDirectoryTestData) {

                // Retrieve command line from test configuration
                final String cmdToGetApplicationVersion = this.testConf
                        .getProperty(ITFactory.COMMAND_TO_GET_APPLICATION_VERSION_CONF_KEY);

                final String versionExpectedApplication = this.itSuite
                        .retrieveVersionApplication(cmdToGetApplicationVersion, this.applicationPath);

                return new File(this.testDataDirectory, "/expected_"
                        + (this.manualGenerationExpectedData ? "UNKNOWN" : versionExpectedApplication));
            }
        }

        // One test directory found
        if (expectedDirectories.length > 1) {
            throw new EoulsanException(this.testName + ": more one expected directory found in "
                    + this.testDataDirectory.getAbsolutePath());
        }

        if (!expectedDirectories[0].isDirectory()) {
            throw new EoulsanException(
                    this.testName + ": no expected directory found in " + this.testDataDirectory.getAbsolutePath());
        }

        // Return expected data directory
        return expectedDirectories[0];

    }

    /**
     * Group exclude file patterns with default, global configuration and
     * configuration test.
     * @param valueConfigTests patterns from configuration file
     * @return exclude files patterns for tests
     */
    private String buildExcludePatterns(final String valueConfigTests) {

        if (valueConfigTests == null || valueConfigTests.equals("none")) {
            // Syntax **/filename
            return "**/" + IT.TEST_SOURCE_LINK_NAME + SEPARATOR + "**/" + ITFactory.TEST_CONFIGURATION_FILENAME;
        }

        return IT.TEST_SOURCE_LINK_NAME + SEPARATOR + ITFactory.TEST_CONFIGURATION_FILENAME + SEPARATOR
                + valueConfigTests;
    }

    /**
     * Retrieve properties for the test, compile specific configuration with
     * global.
     * @param globalsConf global configuration for tests
     * @return Properties content of configuration file
     * @throws IOException if an error occurs while reading the file.
     * @throws EoulsanException if an error occurs while evaluating value property
     */
    private Properties loadConfigurationFile(final Properties globalsConf) throws IOException, EoulsanException {

        final File testConfFile = new File(this.testDataDirectory, ITFactory.TEST_CONFIGURATION_FILENAME);

        checkExistingFile(testConfFile, "test configuration file");

        // Add global configuration
        final Properties props = new Properties();
        props.putAll(globalsConf);

        final BufferedReader br = newReader(testConfFile, Charsets.toCharset(Globals.DEFAULT_FILE_ENCODING));

        String line = null;

        while ((line = br.readLine()) != null) {
            // Skip commentary
            if (line.startsWith("#")) {
                continue;
            }

            final int pos = line.indexOf('=');
            if (pos == -1) {
                continue;
            }

            final String key = line.substring(0, pos).trim();

            // Evaluate value
            String value = evaluateExpressions(line.substring(pos + 1).trim(), true);

            // Key pattern : add value for test to values from
            // configuration general

            if (isKeyInCompileProperties(key) && props.containsKey(key)) {
                // Concatenate values
                value = props.getProperty(key) + SEPARATOR + value;
            }

            // Save parameter with value
            props.put(key, value);
        }
        br.close();

        return props;

    }

    /**
     * Extract pattern.
     * @param propertyKey the property key
     * @return the pattern form configuration
     */
    private String extractPattern(final String propertyKey) {

        final String patterns = this.testConf.getProperty(propertyKey);

        if (patterns == null || patterns.trim().isEmpty()) {
            return "none";
        }

        return patterns.trim();
    }

    //
    // Getter
    //

    /**
     * Gets the property from configuration test.
     * @param key the key
     * @return the property value
     */
    public String getProperty(final String key) {
        return this.testConf.getProperty(key);
    }

    /**
     * Gets the test name.
     * @return the test name
     */
    public String getTestName() {
        return this.testName;
    }

    /**
     * Gets the expected test directory.
     * @return the expected test directory
     */
    public File getExpectedTestDirectory() {
        return this.expectedTestDirectory;
    }

    /**
     * Gets the output test directory.
     * @return the output test directory
     */
    public File getOutputTestDirectory() {
        return this.outputTestDirectory;
    }

    @Override
    public String toString() {
        return this.description + ", files from pattern(s) " + this.fileToComparePatterns;
    }

    /**
     * Gets the file to compare patterns.
     * @return the file to compare patterns
     */
    public String getFileToComparePatterns() {
        return this.fileToComparePatterns;
    }

    /**
     * Gets the file to remove patterns.
     * @return the file to remove patterns
     */
    public String getFileToRemovePatterns() {
        return this.fileToRemovePatterns;
    }

    /**
     * Gets the exclude to compare patterns.
     * @return the exclude to compare patterns
     */
    public String getExcludeToComparePatterns() {
        return this.excludeToComparePatterns;
    }

    /**
     * Gets the check existence file patterns.
     * @return the check existence file patterns
     */
    public String getCheckExistenceFilePatterns() {
        return this.checkExistenceFilePatterns;
    }

    /**
     * Gets the check length file patterns.
     * @return the check length file patterns
     */
    public String getCheckLengthFilePatterns() {
        return this.checkLengthFilePatterns;
    }

    /**
     * Gets the count files to check content.
     * @return the count files to check content
     */
    public int getCountFilesToCheckContent() {
        return (this.itOutput == null ? 0 : this.itOutput.getCountFilesToCheckContent());
    }

    /**
     * Gets the count files to check length.
     * @return the count files to check length
     */
    public int getCountFilesToCheckLength() {
        return (this.itOutput == null ? 0 : this.itOutput.getCountFilesToCheckLength());
    }

    /**
     * Gets the count files to check existence.
     * @return the count files to check existence
     */
    public int getCountFilesToCheckExistence() {
        return (this.itOutput == null ? 0 : this.itOutput.getCountFilesToCheckExistence());
    }

    /**
     * Gets the count files to compare.
     * @return the count files to compare
     */
    public int getCountFilesToCompare() {
        return (this.itOutput == null ? 0 : this.itOutput.getCountFilesToCompare());
    }

    /**
     * Gets the count files to remove.
     * @return the count files to remove
     */
    public int getCountFilesToRemove() {
        return (this.itOutput == null ? 0 : this.itOutput.getCountFilesToRemove());
    }

    /**
     * Gets the IT output.
     * @return the IT output
     */
    public ITOutput getITOutput() {
        return this.itOutput;
    }

    public int getDurationMaxInMinutes() {
        final String value = getProperty(ITFactory.RUNTIME_IT_MAXIMUM_KEY);

        try {

            return Integer.parseInt(value);

        } catch (Exception e) {
            getLogger().severe("Duration set in configuration invalid " + value + ". Use default value "
                    + RUNTIME_IT_MAXIMUM_DEFAULT);

            return RUNTIME_IT_MAXIMUM_DEFAULT;
        }

    }

    //
    // Constructor
    //

    /**
     * Public constructor.
     * @param itSuite the it suite
     * @param globalsConf global configuration for tests
     * @param applicationPath path to the application to test
     * @param testsDataDirectory file with the test configuration
     * @param outputTestsDirectory output test directory with result execute
     *          application
     * @param testName test name
     * @throws IOException if an error occurs while reading the configuration
     *           file.
     * @throws EoulsanException if an error occurs while search expected directory
     *           of the test.
     */
    public IT(final ITSuite itSuite, final Properties globalsConf, final File applicationPath,
            final File testsDataDirectory, final File outputTestsDirectory, final String testName)
            throws IOException, EoulsanException {

        checkExistingDirectoryFile(testsDataDirectory, "tests data directory");
        checkExistingDirectoryFile(outputTestsDirectory, "output tests directory");
        checkExistingDirectoryFile(applicationPath, "application path");

        this.itSuite = itSuite;
        this.applicationPath = applicationPath;
        this.testName = testName;

        // Test data directory contains test configuration file and expected
        // directory
        this.testDataDirectory = new File(testsDataDirectory, this.testName);

        // Output directory on execution integration test
        this.outputTestDirectory = new File(outputTestsDirectory, this.testName);

        // Load properties configuration, added to globals configuration
        this.testConf = loadConfigurationFile(globalsConf);

        // Extract environment variables, after loading configuration
        this.environmentVariables = extractEnvironmentVariables();

        // Init integration tests result
        this.itResult = new ITResult(this);

        // Remove file matching on pattern if IT succeeded
        this.isRemoveFileRequired = Boolean
                .parseBoolean(this.testConf.getProperty(SUCCESS_IT_DELETE_FILE_CONF_KEY));

        // Extract properties on action: generate expected data directory
        this.generateAllExpectedDirectoryTest = this.itSuite.isGenerateAllExpectedDirectoryTest();

        this.generateNewExpectedDirectoryTests = this.itSuite.isGenerateNewExpectedDirectoryTests();

        this.generateExpectedDirectoryTestData = this.generateAllExpectedDirectoryTest
                || this.generateNewExpectedDirectoryTests;

        this.manualGenerationExpectedData = Boolean
                .parseBoolean(this.testConf.getProperty(ITFactory.MANUAL_GENERATION_EXPECTED_DATA_CONF_KEY));

        this.expectedTestDirectory = retrieveExpectedDirectory();

        // Extract all patterns define
        this.fileToComparePatterns = extractPattern(ITFactory.FILE_TO_COMPARE_PATTERNS_CONF_KEY);

        // Extract all patterns define
        this.fileToRemovePatterns = extractPattern(ITFactory.FILE_TO_REMOVE_CONF_KEY);

        this.excludeToComparePatterns = buildExcludePatterns(
                extractPattern(ITFactory.EXCLUDE_TO_COMPARE_PATTERNS_CONF_KEY));

        this.checkExistenceFilePatterns = extractPattern(ITFactory.CHECK_EXISTENCE_FILE_PATTERNS_CONF_KEY);

        this.checkLengthFilePatterns = extractPattern(ITFactory.CHECK_LENGTH_FILE_PATTERNS_CONF_KEY);

        this.checkAbsenceFilePatterns = this.testConf.getProperty(ITFactory.CHECK_ABSENCE_FILE_PATTERNS_CONF_KEY);

        // Check not define, use test name
        if (this.testConf.containsKey(ITFactory.DESCRIPTION_CONF_KEY)) {
            this.description = this.testConf.getProperty(ITFactory.DESCRIPTION_CONF_KEY) + ", action: "
                    + this.itSuite.getActionType();
        } else {
            this.description = this.testName + ", action: " + this.itSuite.getActionType();
        }
    }

}