/**
 * Copyright (c) 2019-2024 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.bc.filetransfer;

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

import javax.management.MalformedObjectNameException;

import org.junit.ClassRule;
import org.junit.Test;
import org.ow2.petals.component.framework.AbstractComponent;
import org.ow2.petals.component.framework.exception.NegativeValueException;
import org.ow2.petals.component.framework.exception.StrictPositiveValueException;
import org.ow2.petals.component.framework.junit.mbean.AbstractBootstrapTest;
import org.ow2.petals.component.framework.junit.rule.ComponentUnderTest;
import org.ow2.petals.junit.rules.log.handler.InMemoryLogHandler;

/**
 * Unit tests of {@link FileTransferBootstrap}
 * 
 * @author Christophe DENEUX - Linagora
 * 
 */
public class FileTransferBootstrapTest extends AbstractBootstrapTest {

    @ClassRule
    public static final InMemoryLogHandler IN_MEMORY_LOG_HANDLER = new InMemoryLogHandler();

    public FileTransferBootstrapTest() throws MalformedObjectNameException {
        super();
    }

    /**
     * Check that the component embeds the right default configuration in its JBI descriptor (values set to their
     * default value in jbi.xml)
     */
    @Test
    public void defaultConfiguration_definedInJbiDescriptor() throws Exception {

        this.embeddedJmxSrvCon.registerConfigurationInstallerMBean(this.initBootstrap(new FileTransferBootstrap()));

        this.assertDefaultConfigurationValues();
    }

    /**
     * Check to set invalid values
     */
    @Test
    public void setInvalidValues() throws Exception {

        this.embeddedJmxSrvCon.registerConfigurationInstallerMBean(this.initBootstrap(new FileTransferBootstrap()));

        // -------------------------------
        // About the locking waiting time
        // -------------------------------
        // 1 - Negative values are invalid
        try {
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME, Long.valueOf(-1));
        } catch (final NegativeValueException e) {
            // NOP, it's the expected exception
        }
        // 2 - Zero value is invalid
        try {
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME, Long.valueOf(0));
        } catch (final StrictPositiveValueException e) {
            // NOP, it's the expected exception
        }

        // -------------------------------
        // About the locking poll interval
        // -------------------------------
        // 1 - Negative values are invalid
        try {
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL,
                    Long.valueOf(-1));
        } catch (final NegativeValueException e) {
            // NOP, it's the expected exception
        }
        // 2 - Zero value is invalid
        try {
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL,
                    Long.valueOf(0));
        } catch (final StrictPositiveValueException e) {
            // NOP, it's the expected exception
        }
    }

    /**
     * Check that valid values are correctly set
     */
    @Test
    public void setValues() throws Exception {

        this.embeddedJmxSrvCon.registerConfigurationInstallerMBean(this.initBootstrap(new FileTransferBootstrap()));

        // --------------------------------
        // About the locking waiting time
        // --------------------------------
        final long lockingWaitingTime = 7;
        this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME,
                Long.valueOf(lockingWaitingTime));
        assertEquals(lockingWaitingTime,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME));

        // -------------------------------
        // About the locking poll interval
        // -------------------------------
        final long lockingLockingPollInterval = 1234;
        this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL,
                Long.valueOf(lockingLockingPollInterval));
        assertEquals(lockingLockingPollInterval,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL));
    }

    private void assertDefaultConfigurationValues() throws Exception {

        assertEquals(FileTransferConstants.DEFAULT_PARAM_LOCKING_WAIT_TIME,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME));
        assertEquals(FileTransferConstants.DEFAULT_PARAM_LOCKING_POLL_INTERVAL,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL));
    }

    /**
     * <p>
     * Pseudo integration test setting installation configuration using JMX.
     * </p>
     * <p>
     * Expected results:
     * </p>
     * <ul>
     * <li>when the component is loaded, installation parameters are set to their default values,</li>
     * <li>when setting new values at installation time, they are correctly set,</li>
     * <li>when starting the component, the values set at installation time are kept.</li>
     * </ul>
     */
    @Test
    public void configurationChanges() throws Throwable {

        // To access the component bootstrap through JMX, the component has not to be installed, only loaded
        final ComponentUnderTest componentUnderTest = new ComponentUnderTest(false, false)
                .addLogHandler(IN_MEMORY_LOG_HANDLER.getHandler()).addEmbeddedJmxSrv(this.embeddedJmxSrvCon);
        componentUnderTest.create();

        // Assertion about default parameter values
        final AbstractComponent component = componentUnderTest.getComponentObject();
        assertNotNull(component);
        assertTrue(component instanceof FileTransferComponent);
        final FileTransferComponent ftComponent = (FileTransferComponent) component;
        assertEquals(FileTransferConstants.DEFAULT_PARAM_LOCKING_WAIT_TIME,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME));
        assertEquals(FileTransferConstants.DEFAULT_PARAM_LOCKING_POLL_INTERVAL,
                this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL));

        try {
            // Use the installation configuration MBean to set parameter values
            final long lockingWaitingTime = 15;
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME, lockingWaitingTime);
            final long lockingPollInterval = 1500;
            this.jmxClient.setBootstrapAttribute(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL,
                    lockingPollInterval);

            // We continue component lifecycle to be able to check that parameters value are correctly used
            componentUnderTest.install();

            // Assertion about parameter values set at installation time
            assertEquals(lockingWaitingTime,
                    this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME));
            assertEquals(lockingPollInterval,
                    this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL));
            assertEquals(lockingWaitingTime, ftComponent.getLockingWaitingTime());
            assertEquals(lockingPollInterval, ftComponent.getLockingPollInterval());

            // We continue component lifecycle starting it
            componentUnderTest.start();

            // Assertion about parameter values set at installation time. They are not reseted
            assertEquals(lockingWaitingTime,
                    this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_WAIT_TIME));
            assertEquals(lockingPollInterval,
                    this.jmxClient.getBootstrapAttributeAsLong(FileTransferBootstrap.ATTR_NAME_LOCKING_POLL_INTERVAL));
            assertEquals(lockingWaitingTime, ftComponent.getLockingWaitingTime());
            assertEquals(lockingPollInterval, ftComponent.getLockingPollInterval());
        } finally {
            componentUnderTest.delete();
        }
    }
}