/**
 * 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.launcher.configuration;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.ow2.petals.launcher.api.server.conf.ConfigurationProperties;
import org.ow2.petals.launcher.exception.InvalidDataRootPathException;
import org.ow2.petals.launcher.exception.InvalidServerPropertiesFileException;
import org.ow2.petals.launcher.exception.NoContainerConfigurationAvailableException;
import org.ow2.petals.launcher.exception.ServerPropertiesFileNotFoundException;
import org.ow2.petals.launcher.exception.UncompleteServerConfigurationException;
import org.ow2.petals.launcher.util.ClasspathUrlStreamHandler;

/**
 * Unit tests of {@link DefaultConfiguration}
 * 
 * @author Christophe DENEUX - EBM WebSourcing
 */
public class DefaultConfigurationTest {

    @Rule
    public TemporaryFolder testTemporaryFolder = new TemporaryFolder();

    /**
     * <p>
     * Check the creation of a {@link DefaultConfiguration} against error
     * management where:
     * <ul>
     * <li>a local server configuration url set to <code>null</code>,</li>
     * <li>no default configuration is available on the classpath.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>The exception {@link InvalidServerPropertiesFileException}
     * is thrown.</li>
     * </ul>
     * </p>
     */
    @Test(expected = NoContainerConfigurationAvailableException.class)
    public final void testDefaultConfiguration_WithoutConfigurationProvidedOrDefaultConfigurationAvailable()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException {

        new DefaultConfiguration(null);
    }

    /**
     * <p>
     * Check the creation of a {@link DefaultConfiguration} against error
     * management where:
     * <ul>
     * <li>a local server configuration url set to <code>null</code>,</li>
     * <li>a default configuration is available on the classpath.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>The configuration is read successfully.</li>
     * </ul>
     * </p>
     */
    @Test(expected = NoContainerConfigurationAvailableException.class)
    public final void testDefaultConfiguration_WithDefaultConfigurationAvailable()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException {

        final ClassLoader oldClassloader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(new ClassLoader(oldClassloader) {

            @Override
            public Enumeration<URL> getResources(final String name) throws IOException {
                if (name.equals(DefaultConfiguration.DEFAULT_SERVER_PROPERTIES_FILE)) {
                    return super.getResources("default.server.properties");
                } else {
                    return super.getResources(name);
                }
            }
        });

        try {
            final Configuration conf = new DefaultConfiguration(null);
            final Properties serverProperties = conf.getServerLocalProperties();
            assertNotNull("Null server properties", serverProperties);
            assertEquals("Invalid container name found", "0",
                    serverProperties.getProperty(ConfigurationProperties.CONTAINER_NAME));
        } finally {
            Thread.currentThread().setContextClassLoader(oldClassloader);
        }
    }

    /**
     * <p>
     * Check the creation of a {@link DefaultConfiguration} where:
     * <ul>
     * <li>an local server configuration url is correctly set,</li>
     * <li>no data root path is set in the local server configuration.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>The configuration is read successfully.</li>
     * </ul>
     * </p>
     */
    @Test
    public final void testDefaultConfiguration_WithDefault()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException {

        final URL serverPropertiesUrl = Thread.currentThread().getContextClassLoader()
                .getResource("default.server.properties");
        assertNotNull("Resource 'default.server.properties' not found", serverPropertiesUrl);
        final Configuration conf = new DefaultConfiguration(serverPropertiesUrl);
        final Properties serverProperties = conf.getServerLocalProperties();
        assertNotNull("Null server properties", serverProperties);
        assertEquals("Invalid container name found", "0",
                serverProperties.getProperty(ConfigurationProperties.CONTAINER_NAME));
    }

    /**
     * <p>
     * Check the creation of a {@link DefaultConfiguration} where:
     * <ul>
     * <li>an local server configuration url is correctly set,</li>
     * <li>read permission on the local server is denied.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>The error {@link ServerPropertiesFileNotFoundException} occurs</li>
     * </ul>
     * </p>
     */
    @Test(expected = ServerPropertiesFileNotFoundException.class)
    public final void testDefaultConfiguration_WithPermissionDenied()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException,
            IOException {

        final URL serverPropertiesUrl = Thread.currentThread().getContextClassLoader()
                .getResource("default.server.properties");
        assertNotNull("Resource 'default.server.properties' not found", serverPropertiesUrl);
        final File unreadbleServerPropsFile = this.testTemporaryFolder.newFile("server.properties");
        FileUtils.copyURLToFile(serverPropertiesUrl, unreadbleServerPropsFile);
        unreadbleServerPropsFile.setReadable(false);

        try {
            new DefaultConfiguration(unreadbleServerPropsFile.toURI().toURL());
        } finally {
            unreadbleServerPropsFile.setReadable(true);
        }
    }

    /**
     * <p>
     * Check the method {@link DefaultConfiguration#getDataRootPath()} where:
     * <ul>
     * <li>an local server configuration url is correctly set but using a not
     * filed-based URL,</li>
     * <li>no data root path is set in the local server configuration.</li>
     * </p>
     * <p>
     * Expected results: The error
     * {@link UncompleteServerConfigurationException} occurs.
     * </p>
     */
    @Test(expected = UncompleteServerConfigurationException.class)
    public final void testGetDataRootPath_WithDefaultDataRootPathAsDirectoryThroughNotFileBasedURL()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            InvalidDataRootPathException, URISyntaxException, MalformedURLException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException {

        final String serverPropertiesName = "classpath:default.server.properties";
        final URL serverPropertiesUrl = new URL(null, serverPropertiesName,
                new ClasspathUrlStreamHandler());
        assertNotNull("Resource '" + serverPropertiesName + "' not found", serverPropertiesUrl);

        final Configuration conf = new DefaultConfiguration(serverPropertiesUrl);
        conf.getDataRootPath();
    }

    /**
     * <p>
     * Check the method {@link DefaultConfiguration#getDataRootPath()} where:
     * <ul>
     * <li>an local server configuration url is correctly set using a
     * filed-based URL,</li>
     * <li>no data root path is set in the local server configuration.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>No error occurs,</li>
     * <li>The data root path is the provided one.</li>
     * </ul>
     * </p>
     */
    @Test
    public final void testGetDataRootPath_WithDefaultDataRootPathAsDirectoryThroughFileBasedURL()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            InvalidDataRootPathException, URISyntaxException, MalformedURLException,
            NoContainerConfigurationAvailableException, ServerPropertiesFileNotFoundException {

        final String serverPropertiesName = "data-root.exist.is-dir/conf/server.properties";
        final URL serverPropertiesUrl = Thread.currentThread().getContextClassLoader()
                .getResource(serverPropertiesName);
        assertNotNull("Resource '" + serverPropertiesName + "' not found", serverPropertiesUrl);

        final File expectedDataRootPath = new File(new File(serverPropertiesUrl.toURI())
                .getParentFile().getParentFile(), DefaultConfiguration.DEFAULT_DATA_ROOT_DIRECTORY);

        final Configuration conf = new DefaultConfiguration(serverPropertiesUrl);
        final File dataRootPath = conf.getDataRootPath();
        assertNotNull("Null data root path returned", dataRootPath);
        assertEquals("Unexpected data root path", expectedDataRootPath, dataRootPath);
    }

    /**
     * <p>
     * Check the method {@link DefaultConfiguration#getDataRootPath()} where:
     * <ul>
     * <li>an local server configuration url is correctly set,</li>
     * <li>a data root path is set in the local server configuration,</li>
     * <li>the data root path is a directory.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>No error occurs,</li>
     * <li>The data root path is the provided one.</li>
     * </ul>
     * </p>
     */
    @Test
    public final void testGetDataRootPath_WithSetDataRootPathAsDirectory()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            InvalidDataRootPathException, NoContainerConfigurationAvailableException,
            ServerPropertiesFileNotFoundException {

        final String serverPropertiesName = "data-root.exist.is-dir/conf/server.properties";
        final URL serverPropertiesUrl = Thread.currentThread().getContextClassLoader()
                .getResource(serverPropertiesName);
        assertNotNull("Resource '" + serverPropertiesName + "' not found", serverPropertiesUrl);
        final Configuration conf = new DefaultConfiguration(serverPropertiesUrl);

        // We build the data root path directory
        final File expectedDataRootPath = testTemporaryFolder.newFolder("data-root");
        // We override the value of the property associated to the data root
        // path
        final Properties serverProperties = conf.getServerLocalProperties();
        serverProperties.setProperty(ConfigurationProperties.DATA_ROOT_DIRECTORY_PROPERTY_NAME,
                expectedDataRootPath.getAbsolutePath());

        final File dataRootPath = conf.getDataRootPath();
        assertNotNull("Null data root path returned", dataRootPath);
        assertEquals("Unexpected data root path", expectedDataRootPath, dataRootPath);
    }
    
    /**
     * <p>
     * Check the method {@link DefaultConfiguration#getDataRootPath()} where:
     * <ul>
     * <li>an local server configuration url is correctly set,</li>
     * <li>a data root path is set in the local server configuration,</li>
     * <li>the data root path is a file.</li>
     * </p>
     * <p>
     * Expected results:
     * <ul>
     * <li>The error {@link InvalidDataRootPathException} occurs.</li>
     * </ul>
     * </p>
     */
    @Test(expected = InvalidDataRootPathException.class)
    public final void testGetDataRootPath_WithDefaultDataRootPathAsFile()
            throws UncompleteServerConfigurationException, InvalidServerPropertiesFileException,
            InvalidDataRootPathException, NoContainerConfigurationAvailableException,
            ServerPropertiesFileNotFoundException {

        final String serverPropertiesName = "data-root.exist.is-file/conf/server.properties";
        final URL serverPropertiesUrl = Thread.currentThread().getContextClassLoader()
                .getResource(serverPropertiesName);
        assertNotNull("Resource '" + serverPropertiesName + "' not found", serverPropertiesUrl);
        final Configuration conf = new DefaultConfiguration(serverPropertiesUrl);
        conf.getDataRootPath();
    }

}
