de.jpdigital.maven.plugins.hibernate4ddl.tests.DdlMojoTest.java Source code

Java tutorial

Introduction

Here is the source code for de.jpdigital.maven.plugins.hibernate4ddl.tests.DdlMojoTest.java

Source

/*
 * Copyright (C) 2014 Jens Pelzetter
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.jpdigital.maven.plugins.hibernate4ddl.tests;

import de.jpdigital.maven.plugins.hibernate4ddl.GenerateDdlMojo;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Locale;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

/**
 * TestSuite for testing the {@link GenerateDdlMojo}.
 *
 * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
 */
public class DdlMojoTest {

    /**
     * Directory to place the test files in
     */
    private static final String TEST_DIR = "target/test/ddl/test";
    /**
     * Path to a mock {@code persistence.xml} file.
     */
    private static final String TEST_PERSISTENCE_XML = "src/test/resources/test-persistence.xml";
    /**
     * An instance of the Mojo under test.
     */
    private GenerateDdlMojo mojo;

    ;

    public DdlMojoTest() {
    }

    @BeforeClass
    public static void setUpClass() {
    }

    @AfterClass
    public static void tearDownClass() {
    }

    /**
     * Creates the Mojo instance.
     */
    @Before
    public void setUp() {
        mojo = new GenerateDdlMojo();
    }

    /**
     * Resets the Mojo by setting {@link #mojo} to {@code null} and deletes the
     * test directory.
     *
     * @throws IOException Thrown if the test directory could not be deleted
     */
    @After
    public void tearDown() throws IOException {
        //Unset Mojo instance
        mojo = null;

        //Delete test directory
        final Path testDir = Paths.get(TEST_DIR);
        if (Files.exists(testDir)) {
            //First get all files in the test directory (if the test directory
            //exists and delete them. This is necessary because there is no
            //method for recursivly deleting a directory in the Java API.
            try (final DirectoryStream<Path> files = Files.newDirectoryStream(testDir)) {
                for (final Path file : files) {
                    Files.deleteIfExists(file);
                }
            } catch (DirectoryIteratorException ex) {
                throw ex.getCause();
            }
            //Delete the (now empty) test directory.
            Files.deleteIfExists(testDir);
        }
    }

    /**
     * Check if the DDL files are generated and have the expected content.
     *
     * @throws MojoExecutionException if something wants wrong when executing
     *                                the Mojo.
     * @throws MojoFailureException   if something wants wrong when executing
     *                                the Mojo.
     * @throws IOException            if the test directory can't be opened or
     *                                created.
     */
    @Test
    public void generateDdl() throws MojoExecutionException, MojoFailureException, IOException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        mojo.execute();

        for (String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));
            assertTrue(String.format("DDL file '%s' was not generated.", path), fileExists(path));

            assertTrue(
                    String.format("DDL file '%s' does not contain 'create table' statement for " + "persons entity",
                            dialect.toLowerCase(Locale.ENGLISH)),
                    fileContainsPersonEntity(path));

            assertTrue(
                    String.format("DDL file '%s' does not contain 'create table' statement for " + "company entity",
                            dialect.toLowerCase(Locale.ENGLISH)),
                    fileContainsCompanyEntity(path));

            assertTrue(String.format(
                    "DDL file '%s' does not contains 'create table' statement for " + "reports entity",
                    dialect.toLowerCase(Locale.ENGLISH)), fileContainsReportEntity(path));
        }
    }

    /**
     * Check if the DDL files are generated and have the expected content, but
     * this time with Envers enabled.
     *
     * @throws MojoExecutionException if something wants wrong when executing
     *                                the Mojo.
     * @throws MojoFailureException   if something wants wrong when executing
     *                                the Mojo.
     * @throws IOException            if the test directory can't be opened or
     *                                created.
     */
    @Test
    public void generateDdl4Envers() throws MojoExecutionException, MojoFailureException, IOException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        mojo.setUseEnvers(true);

        mojo.execute();

        for (final String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));

            assertTrue(String.format("DDL file '%s' was not generated.", path), fileExists(path));

            assertTrue(
                    String.format("DDL file '%s' does not contain 'create table' statement for" + "persons entity",
                            dialect.toLowerCase(Locale.ENGLISH)),
                    fileContainsPersonEntity(path));
            assertTrue(
                    String.format("DDL file '%s' does not contain 'create table' statement for" + "persons entity",
                            dialect.toLowerCase(Locale.ENGLISH)),
                    fileContainsCompanyEntity(path));

            assertTrue(String.format(
                    "DDL file '%s' does not contains 'create table' statement for " + "reports entity",
                    dialect.toLowerCase(Locale.ENGLISH)), fileContainsReportEntity(path));
            assertTrue(
                    String.format("DDL file '%s' does not contains 'create table' statement for "
                            + "reports envers table", dialect.toLowerCase(Locale.ENGLISH)),
                    fileContainsReportsEnversTable(path));
        }
    }

    /**
     * Check if the DDL files are generated and have the expected content, but
     * this time with Envers enabled.
     *
     * @throws NoSuchMethodException     if something went wrong...
     * @throws IllegalAccessException    if something went wrong...
     * @throws InvocationTargetException if something went wrong...
     */
    @Test
    public void generateDdlWithProperties() throws NoSuchMethodException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        mojo.setPersistenceXml(new File(TEST_PERSISTENCE_XML));
        assertThat(mojo.getPersistenceXml(), is(notNullValue()));

        final Configuration configuration = new Configuration();
        final Method processMethod = mojo.getClass().getDeclaredMethod("processPersistenceXml",
                Configuration.class);
        processMethod.setAccessible(true);

        processMethod.invoke(mojo, configuration);

        assertThat(configuration.getProperty("org.hibernate.envers.audit_table_suffix"), is(equalTo("_audit")));
        assertThat(configuration.getProperty("org.hibernate.envers.revision_type_field_name"),
                is(equalTo("rev_type")));

    }

    /**
     * Check if {@link MojoExecutionException} is thrown if an illegal dialect
     * if configured.
     *
     * @throws MojoExecutionException if the Mojo can't be executed.
     * @throws MojoFailureException   if the execution of the Mojo fails
     *                                (expected here)
     */
    @Test(expected = MojoFailureException.class)
    public void illegalDialect() throws MojoExecutionException, MojoFailureException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };

        mojo.setPackages(packages);

        final String[] dialects = new String[] { "fooDB" };
        mojo.setDialects(dialects);

        mojo.execute();
    }

    @Test
    public void checkOutputDirGetter() {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        final File outputDirectory = mojo.getOutputDirectory();
        final String path = outputDirectory.getAbsolutePath();

        assertTrue(String.format("The path of the output directory is '%s', " + "but is expected to end with '%s'.",
                path, TEST_DIR), path.endsWith(TEST_DIR));
    }

    @Test
    public void checkPackagesGetter() {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        final String[] retrievedPackages = mojo.getPackages();

        assertTrue(
                String.format("Expected an array containing two packages names but found an "
                        + "array containing %d package names.", retrievedPackages.length),
                retrievedPackages.length == 2);

        assertEquals(retrievedPackages[0], "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities");
        assertEquals(retrievedPackages[1], "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2");
    }

    @Test
    public void checkDialectsGetter() {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        final String[] retrievedDialects = mojo.getDialects();

        assertTrue(String.format(
                "Expected an array containing three dialects but found an array " + "containing %d dialects.",
                retrievedDialects.length), retrievedDialects.length == 3);

        assertEquals(retrievedDialects[0], "hsql");
        assertEquals(retrievedDialects[1], "mysql5");
        assertEquals(retrievedDialects[2], "POSTGRESQL9");

    }

    private boolean fileExists(final String path) {
        final File file = new File(path);
        return file.exists();
    }

    private boolean fileContainsPersonEntity(final String path) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        final String sql = new String(encoded, StandardCharsets.UTF_8);

        return sql.toLowerCase(Locale.ENGLISH).contains("create table persons");
    }

    private boolean fileContainsReportEntity(final String path) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        final String sql = new String(encoded, StandardCharsets.UTF_8);

        return sql.toLowerCase(Locale.ENGLISH).contains("create table reports");
    }

    private boolean fileContainsReportsEnversTable(final String path) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        final String sql = new String(encoded, StandardCharsets.UTF_8);

        return sql.toLowerCase(Locale.ENGLISH).contains("create table reports_revisions");
    }

    private boolean fileContainsCompanyEntity(final String path) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        final String sql = new String(encoded, StandardCharsets.UTF_8);

        return sql.toLowerCase(Locale.ENGLISH).contains("create table companies");
    }

    /**
     * Checks if the DDL are only overwritten if their content has changed.
     *
     * @throws MojoExecutionException if anything wents wrong when executing the
     *                                Mojo.
     * @throws MojoFailureException   if anything wents wrong when executing the
     *                                Mojo.
     * @throws InterruptedException   If the test thread could not be
     *                                interrupted.
     */
    @Test
    public void noOverwriteIfFileDidNotChange()
            throws MojoExecutionException, MojoFailureException, InterruptedException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        mojo.execute();

        final Map<String, Long> timestamps = new HashMap<>();

        for (final String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));
            final File file = new File(path);
            timestamps.put(dialect, file.lastModified());
        }

        Thread.sleep(2500);
        mojo.execute();

        for (final String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));
            final File file = new File(path);

            assertThat("DDL File was overwritten despite its content of the file" + " hasn't changed.",
                    file.lastModified(), is(timestamps.get(dialect)));
        }
    }

    /**
     * Checks if the DDL files are overwritten when the schema changes.
     *
     * @throws MojoExecutionException if anything wents wrong when executing the
     *                                Mojo.
     * @throws MojoFailureException   if anything wents wrong when executing the
     *                                Mojo.
     * @throws InterruptedException   If the test thread could not be
     *                                interrupted.
     */
    @Test
    public void overwriteFileIfContentChanges()
            throws MojoExecutionException, MojoFailureException, InterruptedException {
        mojo.setOutputDirectory(new File(TEST_DIR));

        final String[] packages = new String[] { "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
                "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2" };
        mojo.setPackages(packages);

        final String[] dialects = new String[] { "hsql", "mysql5", "POSTGRESQL9" };
        mojo.setDialects(dialects);

        mojo.setUseEnvers(false);

        mojo.execute();

        final Map<String, Long> timestamps = new HashMap<>();

        for (final String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));
            final File file = new File(path);
            timestamps.put(dialect, file.lastModified());
        }

        //        final String[] packages2 = new String[]{
        //            "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities",
        //            "de.jpdigital.maven.plugins.hibernate4ddl.tests.entities2"
        //        };
        //        mojo.setPackages(packages2);

        mojo.setUseEnvers(true);

        Thread.sleep(2500);
        mojo.execute();

        for (final String dialect : dialects) {
            final String path = String.format("%s/%s.sql", TEST_DIR, dialect.toLowerCase(Locale.ENGLISH));
            final File file = new File(path);

            assertThat("DDL File was not overwritten despite its content has " + "changed.", file.lastModified(),
                    greaterThan(timestamps.get(dialect)));
        }
    }

}