/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink * 11/17/2010-2.2 Guy Pelletier * - 329008: Support dynamic context creation without persistence.xml * 01/23/2013-2.5 Guy Pelletier * - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls ******************************************************************************/ package org.eclipse.persistence.testing.framework.junit; import java.io.StringWriter; import java.io.Writer; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Hashtable; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import javax.persistence.*; import junit.framework.*; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform; import org.eclipse.persistence.internal.databaseaccess.Platform; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl; import org.eclipse.persistence.logging.DefaultSessionLog; import org.eclipse.persistence.logging.SessionLog; import org.eclipse.persistence.sessions.Connector; import org.eclipse.persistence.sessions.DefaultConnector; import org.eclipse.persistence.sessions.JNDIConnector; import org.eclipse.persistence.sessions.broker.SessionBroker; import org.eclipse.persistence.sessions.server.ServerSession; import org.eclipse.persistence.testing.framework.server.JEEPlatform; import org.eclipse.persistence.testing.framework.server.ServerPlatform; import org.eclipse.persistence.testing.framework.server.TestRunner; import org.eclipse.persistence.testing.framework.server.TestRunner1; import org.eclipse.persistence.testing.framework.server.TestRunner2; import org.eclipse.persistence.testing.framework.server.TestRunner3; import org.eclipse.persistence.testing.framework.server.TestRunner4; import org.eclipse.persistence.testing.framework.server.TestRunner5; /** * This is the superclass for all EclipseLink JUnit tests * Provides convenience methods for transactional access as well as to access * login information and to create any sessions required for setup. * * Assumes the existence of a test.properties file on the classpath that defines the * following properties: * * db.platform * db.user * db.pwd * db.url * db.driver * * If you are using the TestingBrowser, these properties come from the login panel instead. * If you are running the test in JEE the properties come from the server config. * This class should be used for all EntityManager operations to allow tests to be run in the server. */ public abstract class JUnitTestCase extends TestCase { private static Map<String, EntityManagerFactory> emfNamedPersistenceUnits = null; /** Default persistence unit name. */ private static String DEFAULT_PU_NAME = "default"; /** Determine if the test is running on a JEE server, or in JSE. */ protected static Boolean isOnServer; /** Determine if the data-source is JTA, or non-JTA. */ public static Boolean isJTA =true; /** Allow a JEE server platform to be set. */ protected static ServerPlatform serverPlatform; /** Sets if the test should be run on the client or server. */ public Boolean shouldRunTestOnServer; /** System variable to set the tests to run on the server. */ public static final String RUN_ON_SERVER = "server.run"; /** Persistence unit name associated with the test runner, null means single persistence unit */ public String puName = null; static { emfNamedPersistenceUnits = new Hashtable(); } protected static boolean isInitialzied; /** Allow OSGi specific behavior. */ public static boolean isOSGi = false; /** Indicates whether SOP should be used */ public static Boolean usesSOP; /** Indicates whether SOP should be recoverable. Ignored unless useSOP is true */ public static Boolean isSOPRecoverable; /** * This is a hack to enable weaving in Spring tests. * The Spring agent does not load persistence units in premain * So it must be forced to do so before any domain classes are loaded, * otherwise weaving will not work. */ public static void initializePlatform() { if (isInitialzied) { return; } ServerPlatform platform = getServerPlatform(); if (platform != null) { platform.initialize(); } isInitialzied = true; } public JUnitTestCase() { super(); initializePlatform(); } public JUnitTestCase(String name) { super(name); initializePlatform(); } /** * Return the name of the persistence context this test uses. * This allow a subclass test to set this only in one place. */ public String getPersistenceUnitName() { return DEFAULT_PU_NAME; } /** * Return if the test should run on the server. */ public boolean shouldRunTestOnServer() { if (shouldRunTestOnServer == null) { String property = System.getProperty(RUN_ON_SERVER); if (property != null) { shouldRunTestOnServer = property.toUpperCase().equals("TRUE"); } else { shouldRunTestOnServer = false; } } return shouldRunTestOnServer; } /** * Return if the data-source is JTA or not. */ public static boolean isJTA() { String property =System.getProperty("is.JTA"); if (property != null && property.toUpperCase().equals("FALSE")) { isJTA = false; } else { isJTA = true; } return isJTA; } public boolean isWeavingForChangeTrackingEnabled() { return isWeavingForChangeTrackingEnabled(getPersistenceUnitName()); } public boolean isWeavingForChangeTrackingEnabled(String persistenceUnitName) { Object changeTrackingWeaving = JUnitTestCase.getDatabaseSession(persistenceUnitName).getProperty("eclipselink.weaving.changetracking"); if (changeTrackingWeaving == null) { changeTrackingWeaving = System.getProperty("eclipselink.weaving.changetracking"); } if ("false".equals(changeTrackingWeaving)) { return false; } return true; } public boolean isWeavingForFetchGroupsEnabled() { return isWeavingForFetchGroupsEnabled(getPersistenceUnitName()); } public boolean isWeavingForFetchGroupsEnabled(String persistenceUnitName) { Object fetchGroupsWeaving = JUnitTestCase.getDatabaseSession(persistenceUnitName).getProperty("eclipselink.weaving.fetchgroups"); if (fetchGroupsWeaving == null) { fetchGroupsWeaving = System.getProperty("eclipselink.weaving.fetchgroups"); } if ("false".equals(fetchGroupsWeaving)) { return false; } return true; } /** * Return if the tests were run using weaving, agent or static. */ public boolean isWeavingEnabled() { return isWeavingEnabled(getPersistenceUnitName()); } /** * Return if the tests were run using weaving, agent or static. */ public static boolean isWeavingEnabled(String persistenceUnitName) { return System.getProperty("TEST_NO_WEAVING") == null; } /** * Return if the test is running against JPA 1.0. Any test that uses 2.0 * functionality should call this method to avoid been run against a 1.0 * container. */ public static boolean isJPA10() { try { LockModeType.valueOf("NONE"); } catch (Exception e) { return true; } return false; } /** * Return if the test is running on a JEE server, or in JSE. */ public static boolean isOnServer() { if (isOnServer == null) { if (System.getProperty("TEST_SERVER_PLATFORM") != null) { isOnServer = true; } else { isOnServer = false; } } return isOnServer; } /** * Set if the test is running on a JEE server, or in JSE. */ public static void setIsOnServer(boolean value) { isOnServer = value; } /** * Return if the Hermes parser is being used for JPQL. */ public boolean isHermesParser() { return getDatabaseSession().getQueryBuilder().getClass().getName().indexOf("Hermes") != -1; } /** * Indicates whether SOP should be used. */ public static boolean usesSOP() { if (usesSOP == null) { usesSOP = Boolean.valueOf(System.getProperty("sop")); } return usesSOP; } /** * Indicates whether SOP should be recoverable. Ignored unless useSOP is true. */ public static boolean isSOPRecoverable() { if (isSOPRecoverable == null) { isSOPRecoverable = Boolean.valueOf(System.getProperty("sop.recoverable")); } return isSOPRecoverable; } /** * Return the server platform if running in JEE. */ public static ServerPlatform getServerPlatform() { if (serverPlatform == null) { String platformClass = System.getProperty("TEST_SERVER_PLATFORM"); if (platformClass == null) { serverPlatform = new JEEPlatform(); } else { try { serverPlatform = (ServerPlatform)Class.forName(platformClass).newInstance(); } catch (Exception notFound) { throw new RuntimeException(notFound); } } } return serverPlatform; } /** * Set the server platform, this should be done by the test executor * when running a test in the server. */ public static void setServerPlatform(ServerPlatform value) { serverPlatform = value; } public void clearCache() { try { getDatabaseSession().getIdentityMapAccessor().initializeAllIdentityMaps(); } catch (Exception ex) { throw new RuntimeException("An exception occurred trying clear the database session cache.", ex); } } public void clearServerSessionCache() { try { getServerSession().getIdentityMapAccessor().initializeAllIdentityMaps(); } catch (Exception ex) { throw new RuntimeException("An exception occurred trying clear the server session cache.", ex); } } public static void clearCache(String persistenceUnitName) { try { getDatabaseSession(persistenceUnitName).getIdentityMapAccessor().initializeAllIdentityMaps(); } catch (Exception ex) { throw new RuntimeException("An exception occurred trying clear the database session cache.", ex); } } public static void clearServerSessionCache(String persistenceUnitName) { try { getServerSession(persistenceUnitName).getIdentityMapAccessor().initializeAllIdentityMaps(); } catch (Exception ex) { throw new RuntimeException("An exception occurred trying clear the server session cache.", ex); } } /** * Close the entity manager. * This allows the same code to be used on the server where managed entity managers are not closed. */ public void closeEntityManager(EntityManager entityManager) { if (!isOnServer()) { entityManager.close(); } } /** * Close the entity manager. * If a transaction is active, then roll it back. */ public void closeEntityManagerAndTransaction(EntityManager entityManager) { if (isTransactionActive(entityManager)) { rollbackTransaction(entityManager); } closeEntityManager(entityManager); } /** * Return if the transaction is active. * This allows the same code to be used on the server where JTA is used. */ public boolean isTransactionActive(EntityManager entityManager) { if (isOnServer() && isJTA()) { return getServerPlatform().isTransactionActive(); } else { return entityManager.getTransaction().isActive(); } } /** * Return if the transaction is roll back only. * This allows the same code to be used on the server where JTA is used. */ public boolean getRollbackOnly(EntityManager entityManager) { if (isOnServer() && isJTA()) { return getServerPlatform().getRollbackOnly(); } else { return entityManager.getTransaction().getRollbackOnly(); } } /** * Begin a transaction on the entity manager. * This allows the same code to be used on the server where JTA is used, * and will join the EntityManager to the transaction. */ public void beginTransaction(EntityManager entityManager) { if (isOnServer() && isJTA()) { getServerPlatform().beginTransaction(); //bug 404294 - the EM is required to join the transaction to be able to // use transactions started after it was created. getServerPlatform().joinTransaction(entityManager); } else { entityManager.getTransaction().begin(); } } /** * Commit a transaction on the entity manager. * This allows the same code to be used on the server where JTA is used. */ public void commitTransaction(EntityManager entityManager) { if (isOnServer() && isJTA()) { getServerPlatform().commitTransaction(); } else { entityManager.getTransaction().commit(); } } /** * Rollback a transaction on the entity manager. * This allows the same code to be used on the server where JTA is used. */ public void rollbackTransaction(EntityManager entityManager) { if (isOnServer() && isJTA()) { getServerPlatform().rollbackTransaction(); } else { entityManager.getTransaction().rollback(); } } /** * Create a new entity manager for the test suites default persistence unit. * If in JEE this will create or return the active managed entity manager. */ public EntityManager createEntityManager() { if (isOnServer() && isJTA()) { return getServerPlatform().getEntityManager(getPersistenceUnitName()); } else { return getEntityManagerFactory(getPersistenceUnitName(), getPersistenceProperties()).createEntityManager(); } } /** * Create a new entity manager for the persistence unit. * If in JEE this will create or return the active managed entity manager. */ public static EntityManager createEntityManager(String persistenceUnitName) { if (isOnServer() && isJTA()) { return getServerPlatform().getEntityManager(persistenceUnitName); } else { return getEntityManagerFactory(persistenceUnitName).createEntityManager(); } } /** * Create a new entity manager for the persistence unit using the properties * and a default persistence unit name.. * The properties will only be used the first time this entity manager is accessed. * If in JEE this will create or return the active managed entity manager. */ public EntityManager createEntityManager(Map properties) { if (isOnServer() && isJTA()) { return getServerPlatform().getEntityManager(getPersistenceUnitName()); } else { return getEntityManagerFactory(getPersistenceUnitName(), properties).createEntityManager(properties); } } /** * Create a new entity manager for the persistence unit using the properties. * The properties will only be used the first time this entity manager is accessed. * If in JEE this will create or return the active managed entity manager. */ public static EntityManager createEntityManager(String persistenceUnitName, Map properties) { return createEntityManager(persistenceUnitName, properties, null); } /** * Create a new entity manager for the persistence unit using the properties. * The properties will only be used the first time this entity manager is accessed. * If in JEE this will create or return the active managed entity manager. */ public static EntityManager createEntityManager(String persistenceUnitName, Map properties, List<ClassDescriptor> descriptors) { if (isOnServer() && isJTA()) { return getServerPlatform().getEntityManager(persistenceUnitName); } else { return getEntityManagerFactory(persistenceUnitName, properties, descriptors).createEntityManager(); } } public DatabaseSessionImpl getDatabaseSession() { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory().createEntityManager()).getDatabaseSession(); } public static DatabaseSessionImpl getDatabaseSession(String persistenceUnitName) { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory(persistenceUnitName).createEntityManager()).getDatabaseSession(); } public SessionBroker getSessionBroker() { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory().createEntityManager()).getSessionBroker(); } public static SessionBroker getSessionBroker(String persistenceUnitName) { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory(persistenceUnitName).createEntityManager()).getSessionBroker(); } public static ServerSession getServerSession() { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory("default").createEntityManager()).getServerSession(); } public static ServerSession getServerSession(String persistenceUnitName) { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory(persistenceUnitName).createEntityManager()).getServerSession(); } public static ServerSession getServerSession(String persistenceUnitName, Map properties) { return ((org.eclipse.persistence.jpa.JpaEntityManager)getEntityManagerFactory(persistenceUnitName, properties).createEntityManager()).getServerSession(); } public ServerSession getPersistenceUnitServerSession() { return getServerSession(getPersistenceUnitName()); } public Map getPersistenceProperties() { return JUnitTestCaseHelper.getDatabaseProperties(getPersistenceUnitName()); } public static EntityManagerFactory getEntityManagerFactory(String persistenceUnitName) { return getEntityManagerFactory(persistenceUnitName, JUnitTestCaseHelper.getDatabaseProperties(persistenceUnitName), null); } public static EntityManagerFactory getEntityManagerFactory(String persistenceUnitName, Map properties) { return getEntityManagerFactory(persistenceUnitName, properties, null); } public static EntityManagerFactory getEntityManagerFactory(String persistenceUnitName, Map properties, List<ClassDescriptor> descriptors) { //properties.put("eclipselink.tuning", "ExaLogic"); if (isOnServer()) { return getServerPlatform().getEntityManagerFactory(persistenceUnitName); } else { // Set class loader for OSGi testing. if (isOSGi && (properties.get(PersistenceUnitProperties.CLASSLOADER) == null)) { try { properties.put(PersistenceUnitProperties.CLASSLOADER, JUnitTestCase.class.getClassLoader()); } catch (Exception ignore) { System.out.println(ignore); } } EntityManagerFactory emfNamedPersistenceUnit = emfNamedPersistenceUnits.get(persistenceUnitName); if (emfNamedPersistenceUnit == null) { // force closing of other persistence units to avoid Sybase running out of connections. if (!persistenceUnitName.equals("default")) { if (emfNamedPersistenceUnits.containsKey("default") && getServerSession().getPlatform().isSybase()) { Iterator<Map.Entry<String, EntityManagerFactory>> factories = emfNamedPersistenceUnits.entrySet().iterator(); while (factories.hasNext()) { Map.Entry<String, EntityManagerFactory> entry = factories.next(); if (!entry.getKey().equals("default") && !entry.getKey().equals(persistenceUnitName)) { System.out.println("Closing factory: " + entry.getKey()); entry.getValue().close(); factories.remove(); } } } } if (descriptors == null) { emfNamedPersistenceUnit = Persistence.createEntityManagerFactory(persistenceUnitName, properties); } else { emfNamedPersistenceUnit = new EntityManagerFactoryImpl(persistenceUnitName, properties, descriptors); } emfNamedPersistenceUnits.put(persistenceUnitName, emfNamedPersistenceUnit); // Force uppercase for Postgres. - no longer needed with fix for 299926: Case insensitive table / column matching } return emfNamedPersistenceUnit; } } public EntityManagerFactory getEntityManagerFactory() { return getEntityManagerFactory(getPersistenceUnitName()); } public EntityManagerFactory getEntityManagerFactory(Map properties) { return getEntityManagerFactory(getPersistenceUnitName(), properties); } public boolean doesEntityManagerFactoryExist() { return doesEntityManagerFactoryExist(getPersistenceUnitName()); } public static boolean doesEntityManagerFactoryExist(String persistenceUnitName) { EntityManagerFactory emf = emfNamedPersistenceUnits.get(persistenceUnitName); return emf != null && emf.isOpen(); } public void closeEntityManagerFactory() { closeEntityManagerFactory(getPersistenceUnitName()); } public static void closeEntityManagerFactory(String persistenceUnitName) { EntityManagerFactory emfNamedPersistenceUnit = emfNamedPersistenceUnits.get(persistenceUnitName); if(emfNamedPersistenceUnit != null) { if(emfNamedPersistenceUnit.isOpen()) { emfNamedPersistenceUnit.close(); } emfNamedPersistenceUnits.remove(persistenceUnitName); } } public Platform getPlatform() { return getPlatform(getPersistenceUnitName()); } public Platform getPlatform(Class cls) { return getPlatform(getPersistenceUnitName(), cls); } public static Platform getPlatform(String puName) { return getDatabaseSession(puName).getPlatform(); } public static Platform getPlatform(String puName, Class cls) { return getDatabaseSession(puName).getPlatform(cls); } public void setUp() { } public void tearDown() { } /** * Used to output a warning. This does not fail the test, but provides output for someone to review. */ public static void warning(String warning) { System.out.println("WARNING: " + warning); } /** * Intercept test case invocation and delegate it to a remote server. */ public void runBare() throws Throwable { if (shouldRunTestOnServer()) { runBareClient(); } else { super.runBare(); } } /** * Runs a test by delegating method invocation to the application server. */ public void runBareClient() throws Throwable { Properties properties = new Properties(); String url = System.getProperty("server.url"); if (url == null) { fail("System property 'server.url' must be set."); } properties.put("java.naming.provider.url", url); Context context = new InitialContext(properties); Throwable exception = null; if (puName == null) { String testrunner = System.getProperty("server.testrunner"); if (testrunner == null) { fail("System property 'server.testrunner' must be set."); } TestRunner runner = (TestRunner) PortableRemoteObject.narrow(context.lookup(testrunner), TestRunner.class); exception = runner.runTest(getClass().getName(), getName(), getServerProperties()); }else{ int i = puName.charAt(8) - 48; String testRunner[] = new String[6]; for (int j=1; j<=5; j++) { String serverRunner = "server.testrunner" + j; testRunner[j] = System.getProperty(serverRunner); if (testRunner[j] == null) { fail("System property 'server.testrunner'" + j + " must be set."); } } switch (i) { case 1: TestRunner1 runner1 = (TestRunner1) PortableRemoteObject.narrow(context.lookup(testRunner[1]), TestRunner1.class); exception = runner1.runTest(getClass().getName(), getName(), getServerProperties()); break; case 2: TestRunner2 runner2 = (TestRunner2) PortableRemoteObject.narrow(context.lookup(testRunner[2]), TestRunner2.class); exception = runner2.runTest(getClass().getName(), getName(), getServerProperties()); break; case 3: TestRunner3 runner3 = (TestRunner3) PortableRemoteObject.narrow(context.lookup(testRunner[3]), TestRunner3.class); exception = runner3.runTest(getClass().getName(), getName(), getServerProperties()); break; case 4: TestRunner4 runner4 = (TestRunner4) PortableRemoteObject.narrow(context.lookup(testRunner[4]), TestRunner4.class); exception = runner4.runTest(getClass().getName(), getName(), getServerProperties()); break; case 5: TestRunner5 runner5 = (TestRunner5) PortableRemoteObject.narrow(context.lookup(testRunner[5]), TestRunner5.class); exception = runner5.runTest(getClass().getName(), getName(), getServerProperties()); break; default: break; } } if (exception != null) { throw exception; } } public void runBareServer() throws Throwable { setIsOnServer(true); super.runBare(); } /** * Used by subclasses to pass any properties into the * server's vm. Should be used with caution. */ protected Properties getServerProperties() { return null; } /** * Verifies that the object was merged to the cache, and written to the database correctly. */ public void verifyObject(Object writtenObject) { verifyObject(writtenObject, getPersistenceUnitName()); } /** * Verifies that the object was merged to the cache, and written to the database correctly. */ public static void verifyObject(Object writtenObject, String persistenceUnit) { Object readObject = getDatabaseSession(persistenceUnit).readObject(writtenObject); if (!getDatabaseSession(persistenceUnit).compareObjects(readObject, writtenObject)) { fail("Object: " + readObject + " does not match object that was written: " + writtenObject + ". See log (on finest) for what did not match."); } } /** * Verifies the object in a new EntityManager. */ public void verifyObjectInEntityManager(Object writtenObject) { verifyObjectInEntityManager(writtenObject, getPersistenceUnitName()); } /** * Verifies the object in a new EntityManager. */ public void verifyObjectInEntityManager(Object writtenObject, String persistenceUnit) { EntityManager em = createEntityManager(persistenceUnit); try { Object readObject = em.find(writtenObject.getClass(), getServerSession(persistenceUnit).getId(writtenObject)); if (!getServerSession(persistenceUnit).compareObjects(readObject, writtenObject)) { fail("Object: " + readObject + " does not match object that was written: " + writtenObject + ". See log (on finest) for what did not match."); } } finally { closeEntityManager(em); } } /** * Verifies that the object was merged to the cache, and written to the database correctly. */ public void verifyObjectInCacheAndDatabase(Object writtenObject) { verifyObjectInCacheAndDatabase(writtenObject, getPersistenceUnitName()); } /** * Verifies that the object was merged to the cache, and written to the database correctly. */ public static void verifyObjectInCacheAndDatabase(Object writtenObject, String persistenceUnit) { AbstractSession dbs = getDatabaseSession(persistenceUnit); Object readObject = dbs.readObject(writtenObject); if (!dbs.compareObjects(readObject, writtenObject)) { SessionLog oldLog = dbs.getSessionLog(); dbs.setSessionLog(new DefaultSessionLog()); dbs.setLogLevel(SessionLog.FINEST); StringWriter newLog = new StringWriter(); dbs.setLog(newLog); dbs.compareObjects(readObject, writtenObject); dbs.setSessionLog(oldLog); fail("Object from cache: " + readObject + " does not match object that was written: " + writtenObject + ". " + newLog); } dbs.getIdentityMapAccessor().initializeAllIdentityMaps(); readObject = dbs.readObject(writtenObject); if (!dbs.compareObjects(readObject, writtenObject)) { SessionLog oldLog = dbs.getSessionLog(); dbs.setSessionLog(new DefaultSessionLog()); dbs.setLogLevel(SessionLog.FINEST); StringWriter newLog = new StringWriter(); dbs.setLog(newLog); dbs.compareObjects(readObject, writtenObject); dbs.setSessionLog(oldLog); fail("Object from database: " + readObject + " does not match object that was written: " + writtenObject + ". " + newLog); } } /** * Compare objects. */ public void compareObjects(Object obj1, Object obj2) { compareObjects(obj1, obj2, getPersistenceUnitName()); } /** * Compare objects. */ public static void compareObjects(Object obj1, Object obj2, String persistenceUnit) { AbstractSession dbs = getDatabaseSession(persistenceUnit); if (!dbs.compareObjects(obj1, obj2)) { fail("Objects " + obj1 + " and " + obj2 + " are not equal. See log (on finest) for what did not match."); } } /** * Generic persist test. */ public void verifyPersist(Object object) { EntityManager em = createEntityManager(); try { beginTransaction(em); em.persist(object); commitTransaction(em); beginTransaction(em); verifyObjectInCacheAndDatabase(object); rollbackTransaction(em); closeEntityManager(em); } catch (RuntimeException exception) { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); throw exception; } } /** * Generic remove test. */ public void verifyPersistAndRemove(Object object) { EntityManager em = createEntityManager(); try { beginTransaction(em); em.persist(object); commitTransaction(em); closeEntityManager(em); em = createEntityManager(); beginTransaction(em); object = em.find(object.getClass(), getServerSession(getPersistenceUnitName()).getId(object)); em.remove(object); commitTransaction(em); verifyDelete(object); closeEntityManager(em); } catch (RuntimeException exception) { if (isTransactionActive(em)){ rollbackTransaction(em); } closeEntityManager(em); throw exception; } } /** * Verifies that the object was deleted from the database correctly. */ public void verifyDelete(Object writtenObject) { verifyDelete(writtenObject, getPersistenceUnitName()); } /** * Verifies that the object was deleted from the database correctly. */ public void verifyDelete(Object writtenObject, String persistenceUnit) { AbstractSession dbs = getDatabaseSession(persistenceUnit); boolean ok; if (dbs.isServerSession()) { ok = ((ServerSession)dbs).acquireClientSession().verifyDelete(writtenObject); } else if (dbs.isSessionBroker()) { ok = ((SessionBroker)dbs).acquireClientSessionBroker().verifyDelete(writtenObject); } else { ok = dbs.verifyDelete(writtenObject); } if (!ok) { fail("Object not deleted from the database correctly: " + writtenObject); } } /** * Allow printing off stack traces for exceptions that cause test failures when the session log level is set appropriately. * Logs at at the warning level */ public void logThrowable(Throwable exception){ getDatabaseSession().getSessionLog().logThrowable(SessionLog.WARNING, exception); } /** * Return if pessimistic locking/select for update is supported for this test platform. * Currently testing supports select for update on Oracle, MySQL, SQLServer, TimesTen. * Some of the other platforms may have some support for select for update, but the databases we test with * for these do not have sufficient support to pass the tests. * TODO: Need to recheck tests on DB2 as it has some support for this. * Derby has some support, but does not work with joins (2008-12-01). */ public boolean isSelectForUpateSupported(){ return isSelectForUpateSupported(getPersistenceUnitName()); } public static boolean isSelectForUpateSupported(String puName) { AbstractSession dbSession = getDatabaseSession(puName); if (dbSession.isBroker()) { for (AbstractSession memberSession : ((SessionBroker)dbSession).getSessionsByName().values()) { if (!isSelectForUpateSupported(memberSession.getPlatform())) { return false; } } return true; } else { return isSelectForUpateSupported(dbSession.getPlatform()); } } public static boolean isSelectForUpateSupported(DatabasePlatform platform) { // DB2, Derby, Symfoware (bug 304903) and Firebird support pessimistic locking only for a single-table queries. // PostgreSQL supports for update, but not on outerjoins, which the test uses. // H2 supports pessimistic locking, but has table lock issues with multiple connections used in the tests. if (platform.isFirebird() || platform.isH2() || platform.isHSQL() || platform.isAccess() || platform.isSQLAnywhere() || platform.isDerby() || platform.isPostgreSQL() || platform.isSymfoware()) { warning("This database does not support FOR UPDATE."); return false; } return true; } /** * @return true if database supports pessimistic write lock false other wise */ public boolean isPessimisticWriteLockSupported() { return isPessimisticWriteLockSupported(getPersistenceUnitName()); } public static boolean isPessimisticWriteLockSupported(String puName) { AbstractSession dbSession = getDatabaseSession(puName); if (dbSession.isBroker()) { for(AbstractSession memberSession : ((SessionBroker)dbSession).getSessionsByName().values()) { if (!isPessimisticWriteLockSupported(memberSession.getPlatform())) { return false; } } return true; } else { return isPessimisticWriteLockSupported(dbSession.getPlatform()); } } public static boolean isPessimisticWriteLockSupported(DatabasePlatform platform) { if (platform.isSybase()) { //Sybase supports getting Pessimistic Read locks but does not support getting Perssimistic Write locks warning("This database does not support Pessimistic Write Lock."); return false; } return true; } /** * Return if pessimistic locking/select for update nowait is supported for this test platform. * Currently testing supports nowait on Oracle, SQLServer. * PostgreSQL also supports NOWAIT, but doesn't support the outer joins used in the tests. */ public static boolean isSelectForUpateNoWaitSupported(String puName) { AbstractSession dbSession = getDatabaseSession(puName); if (dbSession.isBroker()) { for (AbstractSession memberSession : ((SessionBroker)dbSession).getSessionsByName().values()) { if (!isSelectForUpateSupported(memberSession.getPlatform())) { return false; } } return true; } else { return isSelectForUpateNoWaitSupported(dbSession.getPlatform()); } } public boolean isSelectForUpateNoWaitSupported(){ return isSelectForUpateNoWaitSupported(getPersistenceUnitName()); } public static boolean isSelectForUpateNoWaitSupported(Platform platform) { if (platform.isOracle() || platform.isSQLServer()) { return true; } warning("This database does not support NOWAIT."); return false; } /** * Return if stored procedures are supported for the database platform for the test database. */ public boolean supportsStoredProcedures(){ return supportsStoredProcedures(getPersistenceUnitName()); } public static boolean supportsStoredProcedures(String puName) { DatabasePlatform platform = getDatabaseSession(puName).getPlatform(); // PostgreSQL has some level of support for "stored functions", but output parameters do not work as of 8.2. // Sybase supports stored procedures, but has issues with output parameters and transaction mode (INOUT and chaining). // TODO: DB2 should be in this list. if (platform.isOracle() || platform.isMySQL() || platform.isSQLServer()) { return true; } warning("This database does not support stored procedure creation."); return false; } /** * Return if stored functions are supported for the database platform for the test database. */ public boolean supportsStoredFunctions(){ return supportsStoredFunctions(getPersistenceUnitName()); } public static boolean supportsStoredFunctions(String puName) { DatabasePlatform platform = getDatabaseSession(puName).getPlatform(); // PostgreSQL has some level of support for "stored functions", but output parameters do not work as of 8.2. // TODO: DB2 should be in this list. if (platform.isOracle() || platform.isMySQL()) { return true; } warning("This database does not support stored function creation."); return false; } public void setPuName(String name){ puName = name; } /** * Indicates whether two sessions are connected to the same db */ public static boolean usingTheSameDatabase(AbstractSession session1, AbstractSession session2) { Connector conn1 = session1.getLogin().getConnector(); Connector conn2 = session2.getLogin().getConnector(); if (conn1 instanceof DefaultConnector && conn2 instanceof DefaultConnector) { return ((DefaultConnector)conn1).getDatabaseURL().equals(((DefaultConnector)conn2).getDatabaseURL()); } else if (conn1 instanceof JNDIConnector && conn2 instanceof JNDIConnector) { String name1 = ((JNDIConnector)conn1).getName(); String name2 = ((JNDIConnector)conn2).getName(); if (name1 != null && name1.equals(name2)) { return true; } return ((JNDIConnector)conn1).getDataSource().equals(((JNDIConnector)conn2).getDataSource()); } return false; } }