/* * Hibernate, Relational Persistence for Idiomatic Java * * JBoss, Home of Professional Open Source * Copyright 2010-2011 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.hibernate.ogm.test.simpleentity; import static org.fest.assertions.Assertions.assertThat; import static org.hibernate.ogm.test.utils.TestHelper.assertNumberOfAssociations; import static org.hibernate.ogm.test.utils.TestHelper.assertNumberOfEntities; import static org.hibernate.ogm.test.utils.TestHelper.dropSchemaAndDatabase; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; import junit.framework.TestCase; import org.junit.After; import org.junit.Before; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.annotations.common.util.StringHelper; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.ogm.cfg.OgmConfiguration; import org.hibernate.ogm.test.utils.GridDialectType; import org.hibernate.ogm.test.utils.SkipByGridDialect; import org.hibernate.ogm.test.utils.TestHelper; import org.hibernate.ogm.util.impl.Log; import org.hibernate.ogm.util.impl.LoggerFactory; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.SearchFactory; import org.hibernate.search.engine.spi.SearchFactoryImplementor; import org.hibernate.testing.FailureExpected; /** * A base class for all OGM tests. * * This class is a mix of SearchTestCase from HSearch 4 and OgmTestCase from the Core 3.6 days * It could get some love to clean this mess * * @author Emmanuel Bernard * @author Hardy Ferentschik */ public abstract class OgmTestCase extends TestCase { static { TestHelper.initializeHelpers(); } private static final Log log = LoggerFactory.make(); protected SessionFactory sessions; private Session session; protected static Configuration cfg; private static Class<?> lastTestClass; @Before public void setUp() throws Exception { if ( cfg == null || lastTestClass != getClass() ) { buildConfiguration(); lastTestClass = getClass(); } } protected String[] getXmlFiles() { return new String[] { }; } protected static void setCfg(Configuration cfg) { OgmTestCase.cfg = cfg; } protected static Configuration getCfg() { return cfg; } protected void configure(Configuration cfg) { } @After public void tearDown() throws Exception { handleUnclosedResources(); closeResources(); } protected abstract Class<?>[] getAnnotatedClasses(); protected boolean recreateSchema() { return true; } protected String[] getAnnotatedPackages() { return new String[] { }; } protected SearchFactoryImplementor getSearchFactoryImpl() { FullTextSession s = Search.getFullTextSession( openSession() ); s.close(); SearchFactory searchFactory = s.getSearchFactory(); return (SearchFactoryImplementor) searchFactory; } private void reportSkip(Skip skip) { reportSkip( skip.reason, skip.testDescription ); } protected void reportSkip(String reason, String testDescription) { StringBuilder builder = new StringBuilder(); builder.append( "*** skipping test [" ); builder.append( fullTestName() ); builder.append( "] - " ); builder.append( testDescription ); builder.append( " : " ); builder.append( reason ); log.warn( builder.toString() ); } protected Skip buildSkip(GridDialectType dialect, String comment) { StringBuilder buffer = new StringBuilder(); buffer.append( "skipping database-specific test [" ); buffer.append( fullTestName() ); buffer.append( "] for dialect [" ); buffer.append( dialect.name() ); buffer.append( ']' ); if ( StringHelper.isNotEmpty(comment) ) { buffer.append( "; " ).append( comment ); } return new Skip( buffer.toString(), null ); } protected <T extends Annotation> T locateAnnotation(Class<T> annotationClass, Method runMethod) { T annotation = runMethod.getAnnotation( annotationClass ); if ( annotation == null ) { annotation = getClass().getAnnotation( annotationClass ); } if ( annotation == null ) { annotation = runMethod.getDeclaringClass().getAnnotation( annotationClass ); } return annotation; } protected final Skip determineSkipByGridDialect(Method runMethod) throws Exception { SkipByGridDialect skipForDialectAnn = locateAnnotation( SkipByGridDialect.class, runMethod ); if ( skipForDialectAnn != null ) { for ( GridDialectType gridDialectType : skipForDialectAnn.value() ) { if ( gridDialectType.equals( TestHelper.getCurrentDialectType() ) ) { return buildSkip( gridDialectType, skipForDialectAnn.comment() ); } } } return null; } protected static class Skip { private final String reason; private final String testDescription; public Skip(String reason, String testDescription) { this.reason = reason; this.testDescription = testDescription; } } @Override protected void runTest() throws Throwable { Method runMethod = findTestMethod(); FailureExpected failureExpected = locateAnnotation( FailureExpected.class, runMethod ); try { super.runTest(); if ( failureExpected != null ) { throw new FailureExpectedTestPassedException(); } } catch ( FailureExpectedTestPassedException t ) { closeResources(); throw t; } catch ( Throwable t ) { if ( t instanceof InvocationTargetException) { t = ( ( InvocationTargetException ) t ).getTargetException(); } if ( t instanceof IllegalAccessException ) { t.fillInStackTrace(); } closeResources(); if ( failureExpected != null ) { StringBuilder builder = new StringBuilder(); if ( StringHelper.isNotEmpty( failureExpected.message() ) ) { builder.append( failureExpected.message() ); } else { builder.append( "ignoring @FailureExpected test" ); } builder.append( " (" ) .append( failureExpected.jiraKey() ) .append( ")" ); log.warn( builder.toString(), t ); } else { throw t; } } } @Override public void runBare() throws Throwable { Method runMethod = findTestMethod(); final Skip skip = determineSkipByGridDialect( runMethod ); if ( skip != null ) { reportSkip( skip ); return; } setUp(); try { runTest(); } finally { tearDown(); } } public String fullTestName() { return this.getClass().getName() + "#" + this.getName(); } private Method findTestMethod() { String fName = getName(); assertNotNull( fName ); Method runMethod = null; try { runMethod = getClass().getMethod( fName ); } catch ( NoSuchMethodException e ) { fail( "Method \"" + fName + "\" not found" ); } if ( !Modifier.isPublic(runMethod.getModifiers()) ) { fail( "Method \"" + fName + "\" should be public" ); } return runMethod; } private static class FailureExpectedTestPassedException extends Exception { public FailureExpectedTestPassedException() { super( "Test marked as @FailureExpected, but did not fail!" ); } } public Session openSession() throws HibernateException { rebuildSessionFactory(); session = getSessions().openSession(); return session; } private void rebuildSessionFactory() { if ( sessions == null ) { try { buildConfiguration(); } catch ( Exception e ) { throw new HibernateException( e ); } } } protected void setSessions(SessionFactory sessions) { this.sessions = sessions; } protected SessionFactory getSessions() { return sessions; } protected SessionFactoryImplementor sfi() { return (SessionFactoryImplementor) getSessions(); } //FIXME clear cache when this happens protected void runSchemaGeneration() { } protected void runSchemaDrop() { dropSchemaAndDatabase( session ); } protected void buildConfiguration() throws Exception { closeSessionFactory(); try { setCfg( new OgmConfiguration() ); //Grid specific configuration cfg.setProperty( "hibernate.ogm.infinispan.configuration_resourcename", "infinispan-local.xml" ); //cfg.setProperty( "hibernate.transaction.default_factory_class", JTATransactionManagerTransactionFactory.class.getName() ); //cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, JBossTSStandaloneTransactionManagerLookup.class.getName() ); //Other configurations // by default use the new id generator scheme... cfg.setProperty( Configuration.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); for( Map.Entry<String,String> entry : TestHelper.getEnvironmentProperties().entrySet() ) { cfg.setProperty( entry.getKey(), entry.getValue() ); } configure( cfg ); if ( recreateSchema() ) { cfg.setProperty( Environment.HBM2DDL_AUTO, "none" ); } for ( String aPackage : getAnnotatedPackages() ) { getCfg().addPackage( aPackage ); } for ( Class<?> aClass : getAnnotatedClasses() ) { getCfg().addAnnotatedClass( aClass ); } for ( String xmlFile : getXmlFiles() ) { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( xmlFile ); getCfg().addInputStream( is ); } setSessions( getCfg().buildSessionFactory( /* new TestInterceptor() */ ) ); } catch ( Exception e ) { e.printStackTrace(); throw e; } } protected void handleUnclosedResources() { if ( session != null && session.isOpen() ) { if ( session.isConnected() ) { if ( session.getTransaction().isActive() ) { session.getTransaction().rollback(); } } session.close(); session = null; fail( "unclosed session" ); } else { session = null; } closeSessionFactory(); } private void closeSessionFactory() { if ( sessions != null ) { if ( !sessions.isClosed() ) { dropSchemaAndDatabase( sessions ); sessions.close(); sessions = null; } else { sessions = null; } } } protected void closeResources() { try { if ( session != null && session.isOpen() ) { if ( session.isConnected() ) { if ( session.getTransaction().isActive() ) { session.getTransaction().rollback(); } } session.close(); } } catch ( Exception ignore ) { } try { closeSessionFactory(); } catch ( Exception ignore ) { } } public void checkCleanCache() { assertThat( assertNumberOfEntities( 0, sessions ) ).as("Entity cache should be empty").isTrue(); assertThat( assertNumberOfAssociations( 0, sessions ) ).as("Association cache should be empty").isTrue(); } }