/**
 * Copyright (c) 2010-2012 EBM WebSourcing, 2012-2015 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see <http://www.gnu.org/licenses/>
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.log.handler;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Properties;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.SimpleFormatter;

import org.junit.Test;
import org.ow2.petals.commons.log.PetalsExecutionContext;

import com.ebmwebsourcing.easycommons.lang.UncheckedException;
import com.ebmwebsourcing.easycommons.thread.ExecutionContext;
import com.ebmwebsourcing.easycommons.thread.TestThread;

public class PetalsFileHandlerTest extends AbstractTestPetalsFileHandler {

    /**
     * Check the loading of the logging configuration against a default standard
     * configuration using only relative paths, except for 'basedir'.
     */
    @Test
    public void testConfigurationWithAllPropertiesCorrectlySetAsRelativePaths() throws Exception {

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());

        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is = Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream("logConf.properties");
            try {
                assertNotNull("Log file configuration not found", is);
                manager.readConfiguration(is);
            } finally {
                is.close();
            }
            final PrintStream standardConsoleError = System.err;

            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("Configuration error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }

    }

    /**
     * Check the loading of the logging configuration against a default standard
     * configuration overridden with a not absolute base dir
     */
    @Test
    public void testConfigurationWithAllPropertiesCorrectlySetWithARelativeBaseDir()
            throws Exception {

        // Generate the log conf file
        final String relativeBaseDir = "relative" + File.separator + "base" + File.separator
                + "dir";
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, relativeBaseDir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertFalse("No configuration error occurs", error.isEmpty());
                assertTrue("Unexpected error message", error.contains(relativeBaseDir));
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(temporaryRootDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
                assertEquals(new File(temporaryRootDir, FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }

    }

    /**
     * Check the loading of the logging configuration against a default standard
     * configuration overridden with an absolute flow sub dir
     */
    @Test
    public void testConfigurationWithAllPropertiesCorrectlySetWithAnAbsoluteFlowSubDir()
            throws Exception {

        // Generate the log conf file
        final File absoluteFlowSubDir = this.tempFolder.newFolder("flowsSubDir");
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.FLOW_LOG_SUBDIR_PROPERTY_NAME,
                        absoluteFlowSubDir.getCanonicalPath());
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("Configuration error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(absoluteFlowSubDir.getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }

    }

    /**
     * Check the use of the default configuration
     * 
     * @throws Exception
     */
    @Test
    public void testDefaultConfiguration() throws Exception {
        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());

        final PrintStream standardConsoleError = System.err;
        try {
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));

            final PetalsFileHandler pfh = new PetalsFileHandler();
            final String error = errBAIS.toString();
            assertTrue("Configuration error occurs", error.isEmpty());
            assertSame(Level.INFO, pfh.getLevel());
            assertEquals(temporaryRootDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
            assertEquals(new File(temporaryRootDir, PetalsFileHandler.DEFAULT_FLOW_LOG_SUBDIR).getCanonicalPath(),
                    pfh.flowsSubdir.getCanonicalPath());
            assertEquals(PetalsFileHandler.DEFAULT_LOGFILENAME, pfh.logfilename);
            assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
        } finally {
            System.setErr(standardConsoleError);
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check a configuration with an empty log file name
     */
    @Test
    public void testConstructionWithEmptyLogFilename() throws Exception {
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.LOGFILENAME_PROPERTY_NAME, "");
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("Configuration error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(PetalsFileHandler.DEFAULT_LOGFILENAME, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check a configuration with an log file name containing directory
     */
    @Test
    public void testConstructionWithFileSeparatorInLogFilename() throws Exception {
        final String logFilename = "test" + File.separator + "filename";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.LOGFILENAME_PROPERTY_NAME, logFilename);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertFalse("No error occurs", error.isEmpty());
                assertEquals("Unexpected error",
                        PetalsFileHandler.ERROR_LOGFILENAME_WITH_SEPARATOR, error.trim());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(PetalsFileHandler.DEFAULT_LOGFILENAME, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check a configuration with a loop in property definition of basedir
     */
    @Test
    public void testConstructionWithLoopPropertyInBasedir() throws Exception {

        final String loopPropertyName = "test.loop1";
        final String basedir = "baseDirTest" + File.separator + "${" + loopPropertyName + "}";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, basedir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        System.setProperty(loopPropertyName, "testBaseDir/${" + loopPropertyName + "}");
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertFalse("No error occurs", error.isEmpty());
                assertTrue("Unexpected error", error.contains(loopPropertyName));
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(temporaryRootDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
                assertEquals(new File(temporaryRootDir, FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
            System.clearProperty(loopPropertyName);
        }
    }

    /**
     * Check a configuration with a resolvable property in definition of basedir
     */
    @Test
    public void testConstructionWithResolvablePropertyInBasedir() throws Exception {

        final String resolvablePropertyName = "test.resolvable";
        final String resolvablePropertyValue = "testBaseDirValue";
        final String basedir = PetalsFileHandler.DEFAULT_BASEDIR + File.separator + "${"
                + resolvablePropertyName + "}";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, basedir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        System.setProperty(resolvablePropertyName, resolvablePropertyValue);
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, resolvablePropertyValue).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, resolvablePropertyValue),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
            System.clearProperty(resolvablePropertyName);
        }
    }

    /**
     * Check a configuration with a resolvable property in definition of basedir
     */
    @Test
    public void testConstructionWithUnresolvedPropertyInBasedir() throws Exception {

        final String unresolvablePropertyName = "test.unresolvable";
        final String unresolvablePlaceholder = "${" + unresolvablePropertyName + "}";
        final String basedir = PetalsFileHandler.DEFAULT_BASEDIR + File.separator
                + unresolvablePlaceholder;
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, basedir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, unresolvablePlaceholder).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, unresolvablePlaceholder),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check a configuration with a loop in property definition of flows sub dir
     */
    @Test
    public void testConstructionWithLoopPropertyInFlowsSubdir() throws Exception {

        final String loopPropertyName = "test.loop1";
        final String flowsSubdir = "flowsSubDirTest" + File.separator + "${" + loopPropertyName
                + "}";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.FLOW_LOG_SUBDIR_PROPERTY_NAME, flowsSubdir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        System.setProperty(loopPropertyName, "testBaseDir/${" + loopPropertyName + "}");
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertFalse("No error occurs", error.isEmpty());
                assertTrue("Unexpected error", error.contains(loopPropertyName));
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE),
                        PetalsFileHandler.DEFAULT_FLOW_LOG_SUBDIR).getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
            System.clearProperty(loopPropertyName);
        }
    }

    /**
     * Check a configuration with a resolvable property in definition of flows
     * subdir
     */
    @Test
    public void testConstructionWithResolvablePropertyInFlowsSubdir() throws Exception {

        final String resolvablePropertyName = "test.resolvable";
        final String resolvablePropertyValue = "testFlowsSubDir";
        final String flowsSubdir = "${" + resolvablePropertyName + "}";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.FLOW_LOG_SUBDIR_PROPERTY_NAME, flowsSubdir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        System.setProperty(resolvablePropertyName, resolvablePropertyValue);
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(
                        new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE), resolvablePropertyValue)
                                .getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
            System.clearProperty(resolvablePropertyName);
        }
    }

    /**
     * Check a configuration with a resolvable property in definition of the
     * flows subdir
     */
    @Test
    public void testConstructionWithUnresolvedPropertyInFlowsSubdir() throws Exception {

        final String unresolvablePropertyName = "test.unresolvable";
        final String unresolvablePlaceholder = "${" + unresolvablePropertyName + "}";
        final String flowsSubdir = unresolvablePlaceholder;
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.FLOW_LOG_SUBDIR_PROPERTY_NAME, flowsSubdir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(
                        new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE), unresolvablePlaceholder)
                                .getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());
            } finally {
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check the generation of a log trace with an unresolvable property in
     * definition of basedir
     */
    @Test
    public void testPublishWithUnresolvedPropertyInBasedir() throws Exception {

        final String unresolvablePropertyName = "test.unresolvable";
        final String unresolvablePlaceholder = "${" + unresolvablePropertyName + "}";
        final String basedir = PetalsFileHandler.DEFAULT_BASEDIR + File.separator
                + unresolvablePlaceholder;
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, basedir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, unresolvablePlaceholder).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, unresolvablePlaceholder),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

                PetalsExecutionContext.initFlowInstanceId();
                final File expectedLogFile = new File(new File(new File(new File(temporaryRootDir,
                        unresolvablePlaceholder), FLOWSUBDIR_DEFAULT_TEST_VALUE), ExecutionContext
                        .getProperties().getProperty(
                                PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                        LOGFILENAME_DEFAULT_TEST_VALUE);

                testPublishRecords(pfh, createTestLogRecords(new String[] { "testMessage1" }),
                        expectedLogFile, createTestLogRecords(new String[] { "testMessage1" }));

            } finally {
                PetalsExecutionContext.clear();
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }

    }

    /**
     * Check the generation of a log trace with an unresolvable property in
     * definition of the log filename
     */
    @Test
    public void testPublishWithUnresolvedPropertyInLogFilename() throws Exception {

        final String unresolvablePropertyName = "test.unresolvable";
        final String unresolvablePlaceholder = "${" + unresolvablePropertyName + "}";
        final String logfilename = unresolvablePlaceholder + "-"
                + PetalsFileHandler.DEFAULT_LOGFILENAME;
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.LOGFILENAME_PROPERTY_NAME, logfilename);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertTrue("An error occurs", error.isEmpty());
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.basedir.getCanonicalPath());
                assertEquals(new File(new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE),
                        FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
                assertEquals(logfilename, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

                PetalsExecutionContext.initFlowInstanceId();
                final File expectedLogFile = new File(new File(new File(new File(temporaryRootDir,
                        BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE),
                        ExecutionContext
                        .getProperties().getProperty(
                                PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                        logfilename);

                testPublishRecords(pfh, createTestLogRecords(new String[] { "testMessage1" }),
                        expectedLogFile, createTestLogRecords(new String[] { "testMessage1" }));

            } finally {
                PetalsExecutionContext.clear();
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check the generation of a log trace into a log file defined with a loop
     * in property definition of basedir
     */
    @Test
    public void testPublishWithLoopPropertyInBasedir() throws Exception {

        final String loopPropertyName = "test.loop1";
        final String basedir = "baseDirTest" + File.separator + "${" + loopPropertyName + "}";
        // Generate the log conf file
        final File logConfFile = this.generateLogConfFile(new ConfPropertiesSetter() {

            @Override
            public void customizeProperties(final Properties confProperties) throws Exception {
                confProperties.setProperty(PetalsFileHandler.class.getName()
                        + PetalsFileHandler.BASEDIR_PROPERTY_NAME, basedir);
            }

        });

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());
        System.setProperty(loopPropertyName, "testBaseDir/${" + loopPropertyName + "}");
        try {
            final LogManager manager = LogManager.getLogManager();
            final InputStream is2 = new FileInputStream(logConfFile);
            try {
                manager.readConfiguration(is2);
            } finally {
                is2.close();
            }

            final PrintStream standardConsoleError = System.err;
            try {
                final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
                System.setErr(new PrintStream(errBAIS));

                final PetalsFileHandler pfh = new PetalsFileHandler();

                final String error = errBAIS.toString();
                assertFalse("No error occurs", error.isEmpty());
                assertTrue("Unexpected error", error.contains(loopPropertyName));
                assertSame(Level.FINEST, pfh.getLevel());
                assertEquals(temporaryRootDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
                assertEquals(new File(temporaryRootDir, FLOWSUBDIR_DEFAULT_TEST_VALUE).getCanonicalPath(),
                        pfh.flowsSubdir.getCanonicalPath());
                assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
                assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

                PetalsExecutionContext.initFlowInstanceId();
                final File expectedLogFile = new File(new File(new File(temporaryRootDir,
                        FLOWSUBDIR_DEFAULT_TEST_VALUE), ExecutionContext.getProperties()
                        .getProperty(PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                        LOGFILENAME_DEFAULT_TEST_VALUE);

                testPublishRecords(pfh, createTestLogRecords(new String[] { "testMessage1" }),
                        expectedLogFile, createTestLogRecords(new String[] { "testMessage1" }));

            } finally {
                PetalsExecutionContext.clear();
                System.setErr(standardConsoleError);
            }
        } finally {
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
            System.clearProperty(loopPropertyName);
        }
    }

    /**
     * Check the generation of a log traces deleting the log file
     */
    @Test
    public void testPublishCreatesLogFileIfAbsent() throws Exception {

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());

        final LogManager manager = LogManager.getLogManager();
        final InputStream is = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("logConf.properties");
        try {
            assertNotNull("Log file configuration not found", is);
            manager.readConfiguration(is);
        } finally {
            is.close();
        }

        final PrintStream standardConsoleError = System.err;
        try {
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));

            final PetalsFileHandler pfh = new PetalsFileHandler();

            final String error = errBAIS.toString();
            assertTrue("An error occurs", error.isEmpty());
            assertSame(Level.FINEST, pfh.getLevel());
            final File expectedBaseDir = new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedBaseDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
            final File expectedFlowsSubDir = new File(new File(temporaryRootDir,
                    BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedFlowsSubDir.getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
            assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
            assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

            PetalsExecutionContext.initFlowInstanceId();
            final File expectedLogFile = new File(new File(new File(new File(temporaryRootDir,
                    BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE), ExecutionContext
                    .getProperties().getProperty(
                            PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                    LOGFILENAME_DEFAULT_TEST_VALUE);

            testPublishRecords(pfh, createTestLogRecords(new String[] { "testMessage1" }),
                    expectedLogFile, createTestLogRecords(new String[] { "testMessage1" }));

            assertTrue(expectedLogFile.delete());

            testPublishRecords(pfh, createTestLogRecords(new String[] { "testMessage2",
                    "testMessage3" }), expectedLogFile, createTestLogRecords(new String[] {
                    "testMessage2", "testMessage3" }));

        } finally {
            PetalsExecutionContext.clear();
            System.setErr(standardConsoleError);
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }

    }

    /**
     * Check the appending of a log traces into the log file
     */
    @Test
    public void testPublishAppendsInLogFile() throws Exception {

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());

        final LogManager manager = LogManager.getLogManager();
        final InputStream is = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("logConf.properties");
        try {
            assertNotNull("Log file configuration not found", is);
            manager.readConfiguration(is);
        } finally {
            is.close();
        }

        final PrintStream standardConsoleError = System.err;
        try {
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));

            final PetalsFileHandler pfh = new PetalsFileHandler();

            final String error = errBAIS.toString();
            assertTrue("An error occurs", error.isEmpty());
            assertSame(Level.FINEST, pfh.getLevel());
            final File expectedBaseDir = new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedBaseDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
            final File expectedFlowsSubDir = new File(new File(temporaryRootDir,
                    BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedFlowsSubDir.getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
            assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
            assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

            PetalsExecutionContext.initFlowInstanceId();
            final File expectedLogFile = new File(new File(new File(new File(temporaryRootDir,
                    BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE), ExecutionContext
                    .getProperties().getProperty(
                            PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                    LOGFILENAME_DEFAULT_TEST_VALUE);

            testPublishRecords(new PetalsFileHandler(),
                    createTestLogRecords(new String[] { "testMessage1" }), expectedLogFile,
                    createTestLogRecords(new String[] { "testMessage1" }));

            testPublishRecords(new PetalsFileHandler(), createTestLogRecords(new String[] {
                    "testMessage2", "testMessage3" }), expectedLogFile,
                    createTestLogRecords(new String[] { "testMessage1", "testMessage2",
                            "testMessage3" }));

        } finally {
            PetalsExecutionContext.clear();
            System.setErr(standardConsoleError);
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }

    /**
     * Check the log trace concurrent generation in different log files
     */
    @Test
    public void testPublishOnSeveralDifferentFilesConcurrently() throws Exception {

        final File temporaryRootDir = this.tempFolder.newFolder("root");
        System.setProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME,
                temporaryRootDir.getCanonicalPath());

        final LogManager manager = LogManager.getLogManager();
        final InputStream is = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("logConf.properties");
        try {
            assertNotNull("Log file configuration not found", is);
            manager.readConfiguration(is);
        } finally {
            is.close();
        }

        final PrintStream standardConsoleError = System.err;
        try {
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));

            final PetalsFileHandler pfh = new PetalsFileHandler();

            final String error = errBAIS.toString();
            assertTrue("An error occurs", error.isEmpty());
            assertSame(Level.FINEST, pfh.getLevel());
            final File expectedBaseDir = new File(temporaryRootDir, BASEDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedBaseDir.getCanonicalPath(), pfh.basedir.getCanonicalPath());
            final File expectedFlowsSubDir = new File(new File(temporaryRootDir,
                    BASEDIR_DEFAULT_TEST_VALUE), FLOWSUBDIR_DEFAULT_TEST_VALUE);
            assertEquals(expectedFlowsSubDir.getCanonicalPath(), pfh.flowsSubdir.getCanonicalPath());
            assertEquals(LOGFILENAME_DEFAULT_TEST_VALUE, pfh.logfilename);
            assertEquals(SimpleFormatter.class, pfh.getFormatter().getClass());

            final int nbThreads = 100;
            final CyclicBarrier barrier = new CyclicBarrier(nbThreads);
            final TestThread[] testThreads = new TestThread[nbThreads];
            for (int i = 0; i < testThreads.length; ++i) {
                testThreads[i] = new TestThread(new Runnable() {

                    @Override
                    public void run() {
                        final String threadId = String.valueOf(Thread.currentThread().getId());
                        try {
                            barrier.await();
                        } catch (InterruptedException ie) {
                            throw new UncheckedException(ie);
                        } catch (BrokenBarrierException bbe) {
                            throw new UncheckedException(bbe);
                        }
                        ExecutionContext.getProperties().setProperty(
                                PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME, threadId);

                        final File expectedLogFile = new File(
                                new File(
                                        new File(new File(temporaryRootDir,
                                                BASEDIR_DEFAULT_TEST_VALUE),
                                                FLOWSUBDIR_DEFAULT_TEST_VALUE),
                                        ExecutionContext
                                                .getProperties()
                                                .getProperty(
                                        PetalsExecutionContext.FLOW_INSTANCE_ID_PROPERTY_NAME)),
                                LOGFILENAME_DEFAULT_TEST_VALUE);

                        try {
                            testPublishRecords(pfh, createTestLogRecords(new String[] {
                                    "testMessageA" + threadId, "testMessageB" + threadId,
                                    "testMessageC" + threadId }), expectedLogFile,
                                    createTestLogRecords(new String[] { "testMessageA" + threadId,
                                            "testMessageB" + threadId, "testMessageC" + threadId }));
                        } catch (IOException ioe) {
                            throw new UncheckedException(ioe);
                        }
                    }
                });
                testThreads[i].start();
            }
            for (int i = 0; i < testThreads.length; ++i) {
                testThreads[i].joinExplosively();
            }

        } finally {
            System.setErr(standardConsoleError);
            System.clearProperty(PetalsFileHandler.PETALS_LOG_DIR_PROPERTY_NAME);
        }
    }
}
