//$Id: TestCase.java,v 1.4 2010/06/09 10:53:08 msekoran Exp $
package alma.hibernate.test;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.jdbc.Work;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A base class for all tests.
*
* @author Emmnauel Bernand
* @author Hardy Ferentschik
*/
public abstract class TestCase extends junit.framework.TestCase {
/**
* Sets the property <code>ACS.log.minlevel.namedloggers</code> to configure the ACS hibernate loggers.
* <p>
* Note that this gives us the same kind of dependency on module acsjlog as we anyway have through the slf4j binding:
* this module's test will compile fine before acsjlog is built, but can only run after acsjlog has been built.
*/
static {
System.setProperty("ACS.log.minlevel.namedloggers", "hibernateSQL=1,5:hibernate=1,5");
}
public static final Logger log = LoggerFactory.getLogger(TestCase.class);
private static SessionFactory sessions;
private static Configuration cfg;
private static Class<?> lastTestClass;
private Session session;
/**
* The test method.
*/
private Method runMethod = null;
/**
* Flag indicating whether the test should be skipped.
*/
private boolean skip = false;
public TestCase() {
super();
}
public TestCase(String x) {
super(x);
}
protected void buildSessionFactory( Class<?>[] classes, String[] packages, String[] xmlFiles ) throws Exception {
if ( getSessions() != null )
getSessions().close();
try {
setCfg(new Configuration());
configure(cfg);
if ( recreateSchema() ) {
cfg.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
}
for ( int i = 0; i < packages.length; i++ ) {
getCfg().addPackage(packages[i]);
}
for ( int i = 0; i < classes.length; i++ ) {
getCfg().addAnnotatedClass(classes[i]);
}
for ( int i = 0; i < xmlFiles.length; i++ ) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFiles[i]);
getCfg().addInputStream(is);
}
// setDialect(Dialect.getDialect());
setSessions(getCfg().buildSessionFactory( /* new TestInterceptor() */));
} catch ( Exception e ) {
e.printStackTrace();
throw e;
}
}
protected void setUp() throws Exception {
runMethod = findTestMethod();
checkSkip(runMethod);
if ( !skip ) {
if ( getSessions() == null || lastTestClass != getClass() ) {
buildSessionFactory(getMappings(), getAnnotatedPackages(), getXmlFiles());
lastTestClass = getClass();
} else {
runSchemaGeneration();
}
}
}
protected void runTest() throws Throwable {
try {
if ( !skip ) {
runTestMethod(runMethod);
handleUnclosedSession();
}
} catch ( Throwable e ) {
closeSession(e);
}
}
/**
* Annotations used to mark a test to be specific to a given dialect.
*
* @author Hardy Ferentschik
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresDialect {
Class<? extends Dialect>[] value();
}
private void checkSkip( Method runMethod ) {
Set<Class<? extends Dialect>> dialectList = new HashSet<Class<? extends Dialect>>();
RequiresDialect requiresDialectMethodAnn = runMethod.getAnnotation(RequiresDialect.class);
if ( requiresDialectMethodAnn != null ) {
Class<? extends Dialect>[] requiredDialects = requiresDialectMethodAnn.value();
dialectList.addAll(Arrays.asList(requiredDialects));
}
RequiresDialect requiresDialectClassAnn = getClass().getAnnotation(RequiresDialect.class);
if ( requiresDialectClassAnn != null ) {
Class<? extends Dialect>[] requiredDialects = requiresDialectClassAnn.value();
dialectList.addAll(Arrays.asList(requiredDialects));
}
if ( dialectList.isEmpty() || dialectList.contains(Dialect.getDialect().getClass()) ) {
skip = false;
} else {
log.warn("Skipping test {}, because test does not apply for dialect {}", runMethod.getName(), Dialect
.getDialect().getClass());
skip = true;
}
}
private void runTestMethod( Method runMethod ) throws Throwable, IllegalAccessException {
try {
runMethod.invoke(this, new Class[0]);
} catch ( InvocationTargetException e ) {
e.fillInStackTrace();
throw e.getTargetException();
} catch ( IllegalAccessException e ) {
e.fillInStackTrace();
throw e;
}
}
private Method findTestMethod() {
String fName = getName();
assertNotNull(fName);
Method runMethod = null;
try {
runMethod = getClass().getMethod(fName, null);
} catch ( NoSuchMethodException e ) {
fail("Method \"" + fName + "\" not found");
}
if ( !Modifier.isPublic(runMethod.getModifiers()) ) {
fail("Method \"" + fName + "\" should be public");
}
return runMethod;
}
private void handleUnclosedSession() {
if ( session != null && session.isOpen() ) {
if ( session.isConnected() )
session.doWork(new RollbackWork());
session.close();
session = null;
fail("unclosed session");
} else {
session = null;
}
}
private void closeSession( Throwable e ) throws Throwable {
try {
if ( session != null && session.isOpen() ) {
if ( session.isConnected() )
session.doWork(new RollbackWork());
session.close();
}
} catch ( Exception ignore ) {
}
try {
if ( sessions != null ) {
sessions.close();
sessions = null;
}
} catch ( Exception ignore ) {
}
throw e;
}
public Session openSession() throws HibernateException {
session = getSessions().openSession();
return session;
}
public Session openSession( Interceptor interceptor ) throws HibernateException {
session = getSessions().openSession(interceptor);
return session;
}
protected abstract Class<?>[] getMappings();
protected String[] getAnnotatedPackages() {
return new String[] {};
}
protected String[] getXmlFiles() {
return new String[] {};
}
private void setSessions( SessionFactory sessions ) {
TestCase.sessions = sessions;
}
protected SessionFactory getSessions() {
return sessions;
}
protected static void setCfg( Configuration cfg ) {
TestCase.cfg = cfg;
}
protected static Configuration getCfg() {
return cfg;
}
protected void configure( Configuration cfg ) {
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
cfg.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbc.JDBCDriver");
cfg.setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test");
cfg.setProperty("hibernate.connection.username", "sa");
cfg.setProperty("hibernate.connection.password", "");
cfg.setProperty("hibernate.show_sql", "true");
}
protected boolean recreateSchema() {
return true;
}
protected void runSchemaGeneration() {
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
}
public class RollbackWork implements Work {
public void execute( Connection connection ) throws SQLException {
connection.rollback();
}
}
}