/* * 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.hibernate5ddl; import java.io.File; import java.io.IOException; 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.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.nio.file.StandardOpenOption; import java.util.HashMap; import java.util.Map; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertEquals; /** * TestSuite for testing the {@link GenerateDdlMojo}. * * @author <a href="mailto:[email protected]">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 that no Exception is thrown when a file that does not exist is * injected into {@link GenerateDdlMojo#persistenceXml} and then executed. * * @throws org.apache.maven.plugin.MojoExecutionException * @throws org.apache.maven.plugin.MojoFailureException * @throws java.io.IOException */ @Test public void persistenceXmlDoesntExist() throws MojoExecutionException, MojoFailureException, IOException { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2" }; mojo.setPackages(packages); final String[] dialects = new String[]{ "mysql5" }; mojo.setDialects(dialects); mojo.setPersistenceXml(new File("file/doesnt/exist")); mojo.execute(); } /** * 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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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)); //Drop statements have not been enabled and should be generated. assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "persons but should not.", dialect.toLowerCase()), fileContainsDropPersonTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "companies but should not.", dialect.toLowerCase()), fileContainsDropCompaniesTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "reports but should not.", dialect.toLowerCase()), fileContainsDropReportsTable(path)); } } /** * Check if the DDL files are generated and have the expected content, * including drop statements. * * @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 generateDdlWithDrop() throws MojoExecutionException, MojoFailureException, IOException { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2" }; mojo.setPackages(packages); final String[] dialects = new String[]{ "hsql", "mysql5", "POSTGRESQL9" }; mojo.setDialects(dialects); mojo.setCreateDropStatements(true); 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)); assertTrue(String.format( "DDL file '%s' does not contain 'drop table' statement for table " + "persons.", dialect.toLowerCase()), fileContainsDropPersonTable(path)); assertTrue(String.format( "DDL file '%s' does not contain'drop table' statement for table " + "companies.", dialect.toLowerCase()), fileContainsDropCompaniesTable(path)); assertTrue(String.format( "DDL file '%s' does not contain 'drop table' statement for table " + "reports.", dialect.toLowerCase()), fileContainsDropReportsTable(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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2" }; mojo.setPackages(packages); final String[] dialects = new String[]{ "hsql", "mysql5", "POSTGRESQL9" }; mojo.setDialects(dialects); 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)); //Drop statements have not been enabled and should be generated. assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "persons but should not.", dialect.toLowerCase()), fileContainsDropPersonTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "companies but should not.", dialect.toLowerCase()), fileContainsDropCompaniesTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "reports but should not.", dialect.toLowerCase()), fileContainsDropReportsTable(path)); } } @Test public void generateDdl4EnversWithDrop() throws MojoExecutionException, MojoFailureException, IOException { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2" }; mojo.setPackages(packages); final String[] dialects = new String[]{ "hsql", "mysql5", "POSTGRESQL9" }; mojo.setDialects(dialects); mojo.setCreateDropStatements(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)); assertTrue(String.format( "DDL file '%s' does not contain 'drop table' statement for table " + "persons.", dialect.toLowerCase()), fileContainsDropPersonTable(path)); assertTrue(String.format( "DDL file '%s' does not contain'drop table' statement for table " + "companies.", dialect.toLowerCase()), fileContainsDropCompaniesTable(path)); assertTrue(String.format( "DDL file '%s' does not contain 'drop table' statement for table " + "reports.", dialect.toLowerCase()), fileContainsDropReportsTable(path)); } } /** * Checks if {@link MojoFailureException} 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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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.hibernate5ddl.tests.entities"); assertEquals(retrievedPackages[1], "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2"); } @Test public void checkDialectsGetter() { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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 fileContainsDropPersonTable(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( "drop table if exists persons") || sql.toLowerCase(Locale.ENGLISH).contains( "drop table persons if exists") || sql.toLowerCase(Locale.ENGLISH).contains( "drop 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 fileContainsDropReportsTable(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( "drop table if exists reports") || sql.toLowerCase(Locale.ENGLISH).contains( "drop table reports if exists") || sql.toLowerCase(Locale.ENGLISH).contains( "drop 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"); } private boolean fileContainsDropCompaniesTable(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( "drop table if exists companies") || sql.toLowerCase(Locale.ENGLISH).contains( "drop table companies if exists") || sql.toLowerCase(Locale.ENGLISH).contains( "drop 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.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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. * @throws java.io.IOException if the access to the file system fails */ @Test public void overwriteFileIfContentChanges() throws MojoExecutionException, MojoFailureException, InterruptedException, IOException { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.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); final Path filePath = file.toPath(); Files.write(filePath, "CREATE TABLE Foo;".getBytes("UTF-8"), StandardOpenOption.APPEND); timestamps.put(dialect, file.lastModified()); } mojo.setPackages(packages); 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))); } } /** * Check if the DDL files are generated and have the expected content if a * custom dialect is used. * * @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 generateDdlForCustomDialect() throws MojoExecutionException, MojoFailureException, IOException { mojo.setOutputDirectory(new File(TEST_DIR)); final String[] packages = new String[]{ "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities", "de.jpdigital.maven.plugins.hibernate5ddl.tests.entities2" }; mojo.setPackages(packages); final String[] customDialects = new String[]{ "org.hibernate.dialect.PostgreSQL92Dialect" }; mojo.setCustomDialects(customDialects); mojo.execute(); for (final String dialectClassName : customDialects) { final String path = String.format( "%s/%s.sql", TEST_DIR, mojo.getDialectNameFromClassName(dialectClassName)); 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", path), fileContainsPersonEntity(path)); assertTrue(String.format( "DDL file '%s' does not contain 'create table' statement for " + "company entity", path), fileContainsCompanyEntity(path)); assertTrue(String.format( "DDL file '%s' does not contains 'create table' statement for " + "reports entity", path), fileContainsReportEntity(path)); //Drop statements have not been enabled and should be generated. assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "persons but should not.", path), fileContainsDropPersonTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "companies but should not.", path), fileContainsDropCompaniesTable(path)); assertFalse(String.format( "DDL file '%s' contains 'drop table' statement for table " + "reports but should not.", path), fileContainsDropReportsTable(path)); } } }