/**
 * Copyright (c) 2009 Capgemini Sud, 2010-2012 EBM WebSourcing, 2012-2022 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.plugin.jbiplugin;

import java.io.File;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.junit.Test;
import org.ow2.petals.jbi.descriptor.extension.JBIDescriptorExtensionBuilder;
import org.ow2.petals.jbi.descriptor.extension.exception.NoComponentNameDeployableServiceUnitException;
import org.ow2.petals.jbi.descriptor.extension.exception.NotDeployableServiceUnitException;
import org.ow2.petals.jbi.descriptor.original.JBIDescriptorBuilder;
import org.ow2.petals.jbi.descriptor.original.generated.ClassPath;
import org.ow2.petals.jbi.descriptor.original.generated.Component;
import org.ow2.petals.jbi.descriptor.original.generated.Jbi;
import org.ow2.petals.plugin.jbiplugin.environement.ComponentWithAdditionalJBIResources;
import org.ow2.petals.plugin.jbiplugin.environement.ComponentWithReleaseTransitiveDependency;
import org.ow2.petals.plugin.jbiplugin.environement.ComponentWithSnapshotTransitiveDependency;
import org.ow2.petals.plugin.jbiplugin.environement.DeployableServiceUnitWithUpdate;
import org.ow2.petals.plugin.jbiplugin.environement.DeployableServiceUnitWithoutUpdate;
import org.ow2.petals.plugin.jbiplugin.environement.GlobalUnitTestEnvironnement;
import org.ow2.petals.plugin.jbiplugin.environement.SimpleServiceUnitWithUpdate;

import junitx.framework.Assert;

/**
 * Test the jbi maven plugin about the goal 'jbi-package'.
 * 
 * @author Christophe DENEUX - Capgemini Sud
 */
public class JBIPackageMojoTest extends JBIAbstractTestMojo {

    /**
     * <p>
     * Test the goal 'jbi-package' about packaging of a component including a snapshot transitive dependency and a
     * direct snapshot dependency.
     * </p>
     */
    @Test
    public void testPackageComponentWithSnapshotTransitiveDependency() throws Exception {

        // First, we generate the component JBI archive to configure
        final File componentPomFile = new File(ComponentWithSnapshotTransitiveDependency.SRC_HOME, "pom.xml");
        final JBIPackageMojo packageMojo = this.getPackageMojo(componentPomFile);

        packageMojo.execute();

        // Second, we check the packaged component against the snapshot
        // transitive dependency.
        final ZipFile packagedComponentFile = new ZipFile(new File(
                ComponentWithSnapshotTransitiveDependency.TARGET_HOME,
                ComponentWithSnapshotTransitiveDependency.FINAL_NAME));
        assertNotNull("Snapshot dependency is missing in the packaged JBI component",
                packagedComponentFile.getEntry(ComponentWithSnapshotTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
        assertNotNull("Snapshot transitive dependency is missing in the packaged JBI component",
                packagedComponentFile
                        .getEntry(ComponentWithSnapshotTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));

        // We check the JBI descriptor against bootstrap and component classpath
        final ZipEntry jbiEntry = packagedComponentFile
                .getEntry(JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE);
        assertNotNull("The JBI descriptor is missing in the packaged JBI component", jbiEntry);
        final Jbi jbiDescriptor = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                packagedComponentFile
                .getInputStream(jbiEntry));
        packagedComponentFile.close();
        final Component jbiComponent = jbiDescriptor.getComponent();
        assertNotNull("The section 'component' is missing in the JBI descriptor.", jbiComponent);
        {
            final ClassPath jbiClassPath = jbiComponent.getBootstrapClassPath();
            assertNotNull("The boostrap classpath is missing in the section 'component' in the JBI descriptor.",
                    jbiComponent);
            final List<String> jbiClassPathElts = jbiClassPath.getPathElement();
            assertNotNull("The boostrap classpath is empty in the section 'component' in the JBI descriptor.",
                    jbiClassPathElts);
            Assert.assertNotEquals("The boostrap classpath is empty in the section 'component' in the JBI descriptor.",
                    0, jbiClassPathElts.size());
            assertTrue("Snapshot dependency is missing in bootstrap classpath in the JBI descriptor",
                    jbiClassPathElts.contains(ComponentWithSnapshotTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
            assertTrue("Snapshot transitive dependency is missing in bootstrap classpath in the JBI descriptor",
                    jbiClassPathElts
                            .contains(ComponentWithSnapshotTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));
        }

        {
            final ClassPath jbiClassPath = jbiComponent.getComponentClassPath();
            assertNotNull("The component classpath is missing in the section 'component' in the JBI descriptor.",
                    jbiComponent);
            final List<String> jbiClassPathElts = jbiClassPath.getPathElement();
            assertNotNull("The component classpath is empty in the section 'component' in the JBI descriptor.",
                    jbiClassPathElts);
            Assert.assertNotEquals(
                    "The component classpath is empty in the section 'component' in the JBI descriptor.", 0,
                    jbiClassPathElts.size());
            assertTrue("Snapshot dependency is missing in component classpath in the JBI descriptor",
                    jbiClassPathElts.contains(ComponentWithSnapshotTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
            assertTrue("Snapshot transitive dependency is missing in component classpath in the JBI descriptor",
                    jbiClassPathElts
                            .contains(ComponentWithSnapshotTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));
        }

    }

    /**
     * <p>
     * Test the goal 'jbi-package' about packaging of a component including a realease transitive dependency and a
     * direct realease dependency.
     * </p>
     */
    @Test
    public void testPackageComponentWithRealeaseTransitiveDependency() throws Exception {

        // First, we generate the component JBI archive to configure
        final File componentPomFile = new File(ComponentWithReleaseTransitiveDependency.SRC_HOME, "pom.xml");
        final JBIPackageMojo packageMojo = this.getPackageMojo(componentPomFile);

        packageMojo.execute();

        // Second, we check the packaged component against the snapshot
        // transitive dependency.
        final ZipFile packagedComponentFile = new ZipFile(new File(
                ComponentWithReleaseTransitiveDependency.TARGET_HOME,
                ComponentWithReleaseTransitiveDependency.FINAL_NAME));
        assertNotNull("Release dependency is missing in the packaged JBI component",
                packagedComponentFile.getEntry(ComponentWithReleaseTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
        assertNotNull("Release transitive dependency is missing in the packaged JBI component",
                packagedComponentFile
                        .getEntry(ComponentWithReleaseTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));

        // We check the JBI descriptor against bootstrap and component classpath
        final ZipEntry jbiEntry = packagedComponentFile
                .getEntry(JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE);
        assertNotNull("The JBI descriptor is missing in the packaged JBI component", jbiEntry);
        final Jbi jbiDescriptor = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                packagedComponentFile
                .getInputStream(jbiEntry));
        packagedComponentFile.close();
        final Component jbiComponent = jbiDescriptor.getComponent();
        assertNotNull("The section 'component' is missing in the JBI descriptor.", jbiComponent);
        {
            final ClassPath jbiClassPath = jbiComponent.getBootstrapClassPath();
            assertNotNull("The boostrap classpath is missing in the section 'component' in the JBI descriptor.",
                    jbiComponent);
            final List<String> jbiClassPathElts = jbiClassPath.getPathElement();
            assertNotNull("The boostrap classpath is empty in the section 'component' in the JBI descriptor.",
                    jbiClassPathElts);
            Assert.assertNotEquals("The boostrap classpath is empty in the section 'component' in the JBI descriptor.",
                    0, jbiClassPathElts.size());
            assertTrue("Release dependency is missing in bootstrap classpath in the JBI descriptor",
                    jbiClassPathElts.contains(ComponentWithReleaseTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
            assertTrue("Release transitive dependency is missing in bootstrap classpath in the JBI descriptor",
                    jbiClassPathElts
                            .contains(ComponentWithReleaseTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));
        }

        {
            final ClassPath jbiClassPath = jbiComponent.getComponentClassPath();
            assertNotNull("The component classpath is missing in the section 'component' in the JBI descriptor.",
                    jbiComponent);
            final List<String> jbiClassPathElts = jbiClassPath.getPathElement();
            assertNotNull("The component classpath is empty in the section 'component' in the JBI descriptor.",
                    jbiClassPathElts);
            Assert.assertNotEquals(
                    "The component classpath is empty in the section 'component' in the JBI descriptor.", 0,
                    jbiClassPathElts.size());
            assertTrue("Release dependency is missing in component classpath in the JBI descriptor",
                    jbiClassPathElts.contains(ComponentWithReleaseTransitiveDependency.DIRECT_DEPENDENCY_FINAL_NAME));
            assertTrue("Release transitive dependency is missing in component classpath in the JBI descriptor",
                    jbiClassPathElts
                            .contains(ComponentWithReleaseTransitiveDependency.TRANSITIVE_DEPENDENCY_FINAL_NAME));
        }
    }

    /**
     * <p>
     * Test the goal 'jbi-package' about packaging of a component including additional JBI resources.
     * </p>
     */
    @Test
    public void testPackageComponentWithAdditionalJBIResources() throws Exception {

        // First, we generate the component JBI archive to configure
        final File componentPomFile = new File(ComponentWithAdditionalJBIResources.SRC_HOME, "pom.xml");

        final JBIPackageMojo packageMojo = this.getPackageMojo(componentPomFile);

        packageMojo.execute();

        // Second, we check the packaged component if its has additionals JBI resources.
        final ZipFile packagedComponentFile = new ZipFile(new File(ComponentWithAdditionalJBIResources.TARGET_HOME,
                ComponentWithAdditionalJBIResources.FINAL_NAME));
        assertNotNull("Addition JBI resource is missing in the packaged JBI component",
                packagedComponentFile.getEntry(ComponentWithAdditionalJBIResources.ADDITIONAL_JBI_RESOURCE));

        assertNotNull("Addition JBI resource is missing in the packaged JBI component",
                packagedComponentFile.getEntry(ComponentWithAdditionalJBIResources.ADDITIONAL_JBI_DIRECTORY_RESOURCE));

        assertTrue("Addition JBI resource isn't a directory",
                packagedComponentFile.getEntry(ComponentWithAdditionalJBIResources.ADDITIONAL_JBI_DIRECTORY_RESOURCE)
                        .isDirectory());

        assertNotNull("Addition JBI resource is missing in the packaged JBI component",
                packagedComponentFile
                        .getEntry(ComponentWithAdditionalJBIResources.ADDITIONAL_JBI__RESOURCE_LOCATED_IN_DIRECTORY));
        packagedComponentFile.close();
    }

    /**
     * <p>
     * Test the goal 'jbi-package' about a simple service unit without updating its JBI descriptor.
     * </p>
     * <p>
     * Expected results:
     * </p>
     * <ul>
     * <li>no error occurs,</li>
     * <li>the service unit is always a standard service unit, not a deployable service unit.</li>
     * </ul>
     */
    @Test
    public void testPackageStandardServiceUnitWithoutUpdate() throws Exception {

        // First, we generate the service unit JBI archive to configure
        final File serviceUnitPomFile = new File(new File(GlobalUnitTestEnvironnement.PACKAGE_UNIT_TESTS_SRC_HOME,
                SimpleServiceUnitWithUpdate.ARTIFACT_ID), "pom.xml");
        final JBIPackageMojo packageMojo = this.getPackageMojo(serviceUnitPomFile);

        // No update of the JBI descriptor
        packageMojo.updateJBIXml = false;

        packageMojo.execute();

        // Second, we check the content of the JBI archive
        final ZipFile packagedSuFile = new ZipFile(new File(SimpleServiceUnitWithUpdate.TARGET_HOME,
                SimpleServiceUnitWithUpdate.FINAL_NAME));

        // The JBI descriptor does not contain extensions of a deployable service unit
        final ZipEntry jbiEntry = packagedSuFile.getEntry(JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE);
        assertNotNull(jbiEntry);
        final Jbi jbi = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                packagedSuFile.getInputStream(jbiEntry));
        packagedSuFile.close();
        try {
            JBIDescriptorExtensionBuilder.getInstance().getDeployableServiceUnitIndentification(jbi);
            fail("The identification part of a deployable service unit is present in the JBI descriptor.");
        } catch (final NotDeployableServiceUnitException e) {
            // Expected exception
        }
        try {
            JBIDescriptorExtensionBuilder.getInstance().getDeployableServiceUnitTargetComponent(jbi);
            fail("The target component part of a deployable service unit is present in the JBI descriptor.");
        } catch (final NotDeployableServiceUnitException e) {
            // Expected exception
        }

        // The JBI descriptor does not contain extension about target component as GAV
        try {
            JBIDescriptorExtensionBuilder.getInstance().getServiceUnitTargetComponentAsGA(jbi);
            fail("The target component as GAV is present in the JBI descriptor.");
        } catch (final NoComponentNameDeployableServiceUnitException e) {
            // Expected exception
        }
    }

    /**
     * <p>
     * Test the goal 'jbi-package' about a simple service unit, updating JBI descriptor for a deployable service unit.
     * </p>
     * <p>
     * Expected results:
     * </p>
     * <ul>
     * <li>no error occurs,</li>
     * <li>the service unit is a deployable service unit</li>
     * </ul>
     */
    @Test
    public void testPackageServiceUnitWithUpdateForDeployableServiceUnit() throws Exception {

        // First, we generate the service unit JBI archive to configure
        final File serviceUnitPomFile = new File(DeployableServiceUnitWithUpdate.SRC_HOME, "pom.xml");
        final JBIPackageMojo packageMojo = this.getPackageMojo(serviceUnitPomFile);

        // Extension for deployable service unit have to be generated
        packageMojo.isDeployableServiceUnit = true;
        packageMojo.execute();

        // Second, we check the content of the JBI archive
        final ZipFile packagedSuFile = new ZipFile(new File(DeployableServiceUnitWithUpdate.TARGET_HOME,
                DeployableServiceUnitWithUpdate.FINAL_NAME));

        // The JBI descriptor must contain extensions of a deployable service unit because of
        // "isDeployableServiceUnit=true"
        final ZipEntry jbiEntry = packagedSuFile.getEntry(JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE);
        assertNotNull(jbiEntry);
        final Jbi jbi = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                packagedSuFile.getInputStream(jbiEntry));
        packagedSuFile.close();
        final org.ow2.petals.jbi.descriptor.extension.generated.Identification suIdentification = JBIDescriptorExtensionBuilder
                .getInstance().getDeployableServiceUnitIndentification(jbi);
        assertEquals(DeployableServiceUnitWithUpdate.ARTIFACT_ID + "-" + DeployableServiceUnitWithUpdate.VERSION,
                suIdentification.getName());
        assertEquals(DeployableServiceUnitWithUpdate.COMPONENT_ID, JBIDescriptorExtensionBuilder.getInstance()
                .getDeployableServiceUnitTargetComponent(jbi));
    }

    /**
     * <p>
     * Test the goal 'jbi-package' about a deployable service unit without updating its JBI descriptor.
     * </p>
     * <p>
     * Expected results:
     * </p>
     * <ul>
     * <li>no error occurs,</li>
     * <li>the service unit is always a deployable service unit</li>
     * </ul>
     */
    @Test
    public void testPackageDeployableServiceUnitWithoutUpdate() throws Exception {

        // First, we generate the service unit JBI archive to configure
        final File serviceUnitPomFile = new File(DeployableServiceUnitWithoutUpdate.SRC_HOME, "pom.xml");
        final JBIPackageMojo packageMojo = this.getPackageMojo(serviceUnitPomFile);

        // No update of the JBI descriptor
        packageMojo.updateJBIXml = false;

        packageMojo.execute();

        // Second, we check the content of the JBI archive
        final ZipFile packagedSuFile = new ZipFile(new File(DeployableServiceUnitWithoutUpdate.TARGET_HOME,
                DeployableServiceUnitWithoutUpdate.FINAL_NAME));

        // The JBI descriptor contains extensions of a deployable service unit
        final ZipEntry jbiEntry = packagedSuFile.getEntry(JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE);
        assertNotNull(jbiEntry);
        final Jbi jbi = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                packagedSuFile.getInputStream(jbiEntry));
        packagedSuFile.close();
        final org.ow2.petals.jbi.descriptor.extension.generated.Identification suIdentification = JBIDescriptorExtensionBuilder
                .getInstance().getDeployableServiceUnitIndentification(jbi);
        assertEquals("deployable-su-without-update", suIdentification.getName());
        assertEquals(DeployableServiceUnitWithoutUpdate.COMPONENT_ID, JBIDescriptorExtensionBuilder.getInstance()
                .getDeployableServiceUnitTargetComponent(jbi));
    }
}
