/* * #%L * Nazgul Project: nazgul-core-persistence-test * %% * Copyright (C) 2010 - 2017 jGuru Europe AB * %% * Licensed under the jGuru Europe AB license (the "License"), based * on Apache License, Version 2.0; you may not use this file except * in compliance with the License. * * You may obtain a copy of the License at * * http://www.jguru.se/licenses/jguruCorporateSourceLicense-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% * */ package se.jguru.nazgul.test.persistence; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.jguru.nazgul.core.algorithms.api.Validate; import se.jguru.nazgul.test.persistence.pets.Bird; import javax.persistence.EntityTransaction; import javax.persistence.Query; import java.io.File; import java.net.URL; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB */ public class T_AbstractJpaTestTest { // Our Log private static final Logger log = LoggerFactory.getLogger(T_AbstractJpaTestTest.class); // Shared state private ClassLoader originalClassLoader; private String jpaProviderClass; private MockAbstractJpaTest unitUnderTest; private boolean teardownUnitUnderTest = false; @Before public void setupSharedState() { // Stash the original ClassLoader final Thread activeThread = Thread.currentThread(); originalClassLoader = activeThread.getContextClassLoader(); // Ensure that we have a correct Maven profile set. jpaProviderClass = System.getProperty(StandardPersistenceTest.JPA_PROVIDER_CLASS_SYSPROPKEY); Assert.assertNotNull("No JPA provider found. Ensure that system property [" + StandardPersistenceTest.JPA_PROVIDER_CLASS_SYSPROPKEY + "] contains the JPA provider class. " + "This should be done automatically by Maven.", jpaProviderClass); } @After public void teardownSharedState() { // Check sanity if (unitUnderTest != null && teardownUnitUnderTest) { try { unitUnderTest.tearDown(); } catch (Exception e) { log.error("Could not teardown MockAbstractJpaTest properly. " + e); } } // Restore the original classloader Thread.currentThread().setContextClassLoader(originalClassLoader); } @Test public void validateStandardLifecycle() throws Exception { // Assemble final String persistenceXmlFile = "testdata/mockjpa/mockpersistence.xml"; final String persistenceUnit = "birdPU"; unitUnderTest = new MockAbstractJpaTest(persistenceXmlFile, persistenceUnit, true, getHsqldbEntityManagerFactoryProperties(persistenceXmlFile)); final Bird bird = new Bird("birdName", "cool birds"); // Act & Assert #1: Validate the EntityManager properties unitUnderTest.setUp(); Assert.assertNotNull(unitUnderTest.entityManager); Assert.assertNotNull(unitUnderTest.jpa); Assert.assertNotNull(unitUnderTest.getJpaUnitTestConnection(true)); EntityTransaction userTransaction = unitUnderTest.transaction; Assert.assertNotNull(userTransaction); Assert.assertTrue(userTransaction.isActive()); // Act & Assert #2: Begin the user transaction final int firstTransactionHashCode = unitUnderTest.hashCode(); Assert.assertTrue(userTransaction.isActive()); // Act & Assert #3: Persist a Bird instance, and commit without starting a new transaction. unitUnderTest.entityManager.persist(bird); unitUnderTest.commitAndStartNewTransaction(); userTransaction = unitUnderTest.transaction; Assert.assertNotSame(firstTransactionHashCode, userTransaction.hashCode()); // Act & Assert #4: Teardown unitUnderTest.tearDown(); Assert.assertNull(unitUnderTest.transaction); } @Test public void validateTransactionlessReadDoesNotYieldException() throws Exception { // Assemble final String persistenceXmlFile = "testdata/mockjpa/mockpersistence.xml"; final String persistenceUnit = "birdPU"; unitUnderTest = new MockAbstractJpaTest(persistenceXmlFile, persistenceUnit, true, getHsqldbEntityManagerFactoryProperties(persistenceXmlFile)); teardownUnitUnderTest = true; // Act & Assert #1: Close transaction, and check state unitUnderTest.setUp(); unitUnderTest.jpaCache.evictAll(); // unitUnderTest.commit(false); Assert.assertFalse(unitUnderTest.transaction.isActive()); // Act & Assert #2: final Query query = unitUnderTest.entityManager.createQuery("select b from Bird b order by b.name"); final List<Bird> birds = query.getResultList(); Assert.assertNotNull(birds); Assert.assertEquals(0, birds.size()); Assert.assertFalse(unitUnderTest.entityManager.getTransaction().isActive()); Assert.assertSame(unitUnderTest.transaction, unitUnderTest.entityManager.getTransaction()); } @Test public void validateNoExceptionOnTeardownWithoutSetup() { // Assemble final String persistenceXmlFile = "testdata/mockjpa/mockpersistence.xml"; final String persistenceUnit = "birdPU"; unitUnderTest = new MockAbstractJpaTest(persistenceXmlFile, persistenceUnit, false, null); unitUnderTest.cleanupSchemaInTeardown = false; // Act & Assert unitUnderTest.tearDown(); } @Test public void validateFireQuery() throws Exception { // Assemble final String persistenceXmlFile = "testdata/mockjpa/mockpersistence.xml"; final String persistenceUnit = "birdPU"; unitUnderTest = new MockAbstractJpaTest(persistenceXmlFile, persistenceUnit, true, getHsqldbEntityManagerFactoryProperties(persistenceXmlFile)); final Bird bird = new Bird("birdName", "cool birds"); // Act & Assert #1: Persist a Bird instance unitUnderTest.setUp(); EntityTransaction userTransaction = unitUnderTest.transaction; Assert.assertFalse(userTransaction.isActive()); userTransaction.begin(); unitUnderTest.entityManager.persist(bird); unitUnderTest.commitAndStartNewTransaction(); // Act & Assert #2: Fire an arbitrary JPQL query final List<Bird> birds = unitUnderTest.jpa.fireJpaQuery("select a from Bird a order by a.name"); Assert.assertEquals(1, birds.size()); final Bird retrieved = birds.get(0); Assert.assertEquals("birdName", retrieved.getName()); // Act & Assert #3: Teardown unitUnderTest.tearDown(); Assert.assertNull(unitUnderTest.transaction); } @Test(expected = IllegalStateException.class) public void validateExceptionOnNonexistentPersistenceUnit() throws Exception { // Assemble final String persistenceXmlFile = "testdata/mockjpa/incorrectpersistenceunit.xml"; final String persistenceUnit = "nonexistentPersistenceUnit"; this.teardownUnitUnderTest = true; final MockAbstractJpaTest unitUnderTest = new MockAbstractJpaTest( persistenceXmlFile, persistenceUnit, true, getHsqldbEntityManagerFactoryProperties(persistenceXmlFile)); // Act & Assert unitUnderTest.setUp(); } @Test(expected = IllegalStateException.class) public void validateExceptionOnIncorrectPersistenceUnit() throws Exception { // Assemble final String persistenceXmlFile = "testdata/mockjpa/incorrectpersistenceunit.xml"; final String persistenceUnit = "incorrectPU"; final MockAbstractJpaTest unitUnderTest = new MockAbstractJpaTest( persistenceXmlFile, persistenceUnit, true, null); // Act & Assert unitUnderTest.setUp(); } // // Private helpers // public static File getTargetDirectory(final Class<?> testcaseClass) { // Use CodeSource final URL location = testcaseClass.getProtectionDomain().getCodeSource().getLocation(); // Check sanity Validate.notNull(location, "CodeSource location not found for class [" + testcaseClass.getSimpleName() + "]"); // All done. return new File(location.getPath()).getParentFile(); } protected Map<String, String> getHsqldbEntityManagerFactoryProperties(final String persistenceXmlFile) { return getHsqldbEntityManagerFactoryProperties(jpaProviderClass, T_AbstractJpaTestTest.class, persistenceXmlFile); } /** * Retrieves the EntityManagerFactory properties required to properly talk to a HSQLDB instance. * * @param jpaProviderClass The classname of the JPA provider. * @param testClass The unit test class itself. * @param persistenceXmlFile The classpath-relative path to the persistence XML file to be used. * @return The properties for the HSQLDB-compliant EntityManager. */ public static Map<String, String> getHsqldbEntityManagerFactoryProperties( final String jpaProviderClass, final Class<?> testClass, final String persistenceXmlFile) { // Get standard properties final DatabaseType hsqldb = DatabaseType.HSQL; final String jdbcDriverClass = hsqldb.getJdbcDriverClass(); final String jdbcURL = hsqldb.getUnitTestJdbcURL( StandardPersistenceTest.DEFAULT_DB_NAME, getTargetDirectory(testClass)); final Map<String, String> toReturn = new TreeMap<String, String>(); final String[][] persistenceProviderProps = new String[][]{ // Generic properties {"javax.persistence.provider", jpaProviderClass}, {"javax.persistence.jdbc.driver", jdbcDriverClass}, {"javax.persistence.jdbc.url", jdbcURL}, {"javax.persistence.jdbc.user", StandardPersistenceTest.DEFAULT_DB_UID}, {"javax.persistence.jdbc.password", StandardPersistenceTest.DEFAULT_DB_PASSWORD}, // OpenJPA properties {"openjpa.jdbc.DBDictionary", hsqldb.getDatabaseDialectClass()}, // Note! // These OpenJPA provider properties are now replaced by the standardized // properties, "javax.persistence....". // It is now an exception to define both the standardized property and the // corresponding legacy openjpa property for the commented-out properties // below. These properties will remain commented-out to indicate which openjpa // properties are now replaced by javax.persistence properties. // // {"openjpa.ConnectionDriverName", jdbcDriverClass}, // {"openjpa.ConnectionURL", jdbcURL}, // {"openjpa.ConnectionUserName", DEFAULT_DB_UID}, // {"openjpa.ConnectionPassword", DEFAULT_DB_PASSWORD}, {"openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)"}, {"openjpa.InverseManager", "true"}, {"openjpa.Log", "DefaultLevel=WARN, Tool=INFO, RUNTIME=WARN, SQL=WARN"}, {"openjpa.jdbc.SchemaFactory", "native(ForeignKeys=true)"}, {"openjpa.jdbc.TransactionIsolation", "serializable"}, {"openjpa.RuntimeUnenhancedClasses", "supported"}, // Eclipselink properties {"eclipselink.deploy-on-startup", "true"}, {"eclipselink.target-database", hsqldb.getHibernatePlatformClass()}, {"eclipselink.logging.level", "FINER"}, {"eclipselink.orm.throw.exceptions", "true"}, {"eclipselink.ddl-generation", "drop-and-create-tables"}, {"eclipselink.ddl-generation.output-mode", "database"}, {"eclipselink.persistencexml", persistenceXmlFile} }; // First, add the default values - and then overwrite them with // any given system properties. for (String[] current : persistenceProviderProps) { toReturn.put(current[0], current[1]); } // Now, overwrite with appropriate system properties final List<String> overridablePrefixes = Arrays.asList("javax.persistence.", "openjpa.", "eclipselink."); for (Map.Entry<Object, Object> current : System.getProperties().entrySet()) { final String currentPropertyName = "" + current.getKey(); for (String currentPrefix : overridablePrefixes) { if (currentPropertyName.trim().toLowerCase().startsWith(currentPrefix)) { toReturn.put(currentPropertyName, "" + current.getValue()); } } } // All done. return toReturn; } }