FileDocCategorySizeDatePackage
TestCase.javaAPI DocHibernate 3.2.518366Tue Dec 12 16:22:26 GMT 2006org.hibernate.test

TestCase

public abstract class TestCase extends TestCase

Fields Summary
private static org.hibernate.SessionFactory
sessions
private static org.hibernate.cfg.Configuration
cfg
private static org.hibernate.dialect.Dialect
dialect
private static Class
lastTestClass
private org.hibernate.classic.Session
session
protected static final Log
SKIP_LOG
Constructors Summary
public TestCase(String name)

		super( name );
	
Methods Summary
protected voidaddMappings(java.lang.String[] files, org.hibernate.cfg.Configuration cfg)

		for ( int i = 0; i < files.length; i++ ) {
			if ( !files[i].startsWith( "net/" ) ) {
				files[i] = getBaseForMappings() + files[i];
			}
			cfg.addResource( files[i], TestCase.class.getClassLoader() );
		}
	
protected voidafterSessionFactoryBuilt()

		// for subclasses to override in order to perform extra "stuff" only
		// when SF (re)built...
	
protected booleanallowsPhysicalColumnNameInHaving(java.lang.String testDescription)
Does the db/dialect support using a column's physical name in the having clause even after it has been aliased in the select/group-by clause. This is not actually required by the SQL spec, although virtually ever DB in the world supports this.

param
testDescription description of the scenario being tested.
return
true if is allowed

		// I only *know* of this being a limitation on Derby, although I highly suspect
		// it is a limitation on any IBM/DB2 variant
		if ( DerbyDialect.class.isInstance( getDialect() ) ) {
			// https://issues.apache.org/jira/browse/DERBY-1624
			reportSkip( "Dialect does not support physical column name in having clause after it is aliased", testDescription );
			return false;
		}
		return true;
	
protected booleanallowsPhysicalColumnNameInOrderby(java.lang.String testDescription)
Does the db/dialect support using a column's physical name in the order-by clause even after it has been aliased in the select clause. This is not actually required by the SQL spec, although virtually ever DB in the world supports this (the most glaring omission here being IBM-variant DBs ala DB2 and Derby).

param
testDescription description of the scenario being tested.
return
true if is allowed

		if ( DB2Dialect.class.isInstance( getDialect() ) ) {
			// https://issues.apache.org/jira/browse/DERBY-1624
			reportSkip( "Dialect does not support physical column name in order-by clause after it is aliased", testDescription );
			return false;
		}
		return true;
	
public booleanappliesTo(org.hibernate.dialect.Dialect dialect)
Intended to indicate that this test class as a whole is intended for a dialect or series of dialects. Skips here (appliesTo = false) therefore simply indicate that the given tests target a particular feature of the checked database and none of the tests on this class should be run for the checked dialect.

param
dialect The dialect to be checked.
return
True if all the tests on this class apply to the given dialect (and therefore should be run); false otherwise.

		return true;
	
protected voidassertAllDataRemoved()

		if ( !recreateSchema() ) {
			return; // no tables were created...
		}
		if ( !Boolean.getBoolean( "hibernate.test.validateDataCleanup" ) ) {
			return;
		}

		Session tmpSession = sessions.openSession();
		try {
			List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list();

			Map items = new HashMap();
			if ( !list.isEmpty() ) {
				for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
					Object element = iter.next();
					Integer l = ( Integer ) items.get( tmpSession.getEntityName( element ) );
					if ( l == null ) {
						l = new Integer( 0 );
					}
					l = new Integer( l.intValue() + 1 );
					items.put( tmpSession.getEntityName( element ), l );
					System.out.println( "Data left: " + element );
				}
				fail( "Data is left in the database: " + items.toString() );
			}
		}
		finally {
			try {
				tmpSession.close();
			}
			catch( Throwable t ) {
				// intentionally empty
			}
		}
	
public static voidassertClassAssignability(java.lang.Class source, java.lang.Class target)

		if ( !target.isAssignableFrom( source ) ) {
			throw new AssertionFailedError(
			        "Classes were not assignment-compatible : source<" + source.getName() +
			        "> target<" + target.getName() + ">"
			);
		}
	
public static voidassertElementTypeAssignability(java.util.Collection collection, java.lang.Class clazz)

		Iterator itr = collection.iterator();
		while ( itr.hasNext() ) {
			assertClassAssignability( itr.next().getClass(), clazz );
		}
	
private voidbuildSessionFactory()

		if ( getSessions()!=null ) {
			getSessions().close();
		}

		TestCase.dialect = Dialect.getDialect();
		if ( ! appliesTo( getDialect() ) ) {
			return;
		}

		try {

			TestCase.cfg = new Configuration();
			cfg.setProperty( Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider" );
			if( recreateSchema() ) {
				cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
			}
			addMappings( getMappings(), cfg );
			configure( cfg );

			if ( getCacheConcurrencyStrategy() != null ) {
				Iterator iter = cfg.getClassMappings();
				while ( iter.hasNext() ) {
					PersistentClass clazz = (PersistentClass) iter.next();
					Iterator props = clazz.getPropertyClosureIterator();
					boolean hasLob = false;
					while ( props.hasNext() ) {
						Property prop = (Property) props.next();
						if ( prop.getValue().isSimpleValue() ) {
							String type = ( (SimpleValue) prop.getValue() ).getTypeName();
							if ( "blob".equals(type) || "clob".equals(type) ) hasLob = true;
							if ( Blob.class.getName().equals(type) || Clob.class.getName().equals(type) ) hasLob = true;
						}
					}
					if ( !hasLob && !clazz.isInherited() && overrideCacheStrategy() ) {
						cfg.setCacheConcurrencyStrategy(
								clazz.getEntityName(),
								getCacheConcurrencyStrategy()
							);
					}
				}
				iter = cfg.getCollectionMappings();
				while ( iter.hasNext() ) {
					Collection coll = (Collection) iter.next();
					cfg.setCollectionCacheConcurrencyStrategy(
							coll.getRole(),
							getCacheConcurrencyStrategy()
						);
				}
			}

			// make sure we use the same dialect...
			cfg.setProperty( Environment.DIALECT, TestCase.dialect.getClass().getName() );
			TestCase.sessions = cfg.buildSessionFactory();
			afterSessionFactoryBuilt();
		}
		catch ( Exception e ) {
			e.printStackTrace();
			throw e;
		}
	
protected voidconfigure(org.hibernate.cfg.Configuration cfg)
Apply any test-specific configuration prior to building the factory.

param
cfg The configuration which will be used to construct the factory.

	
protected booleandialectIs(java.lang.Class dialectClass)

		return dialectClass.isInstance( getDialect() );
	
protected booleandialectIsCaseSensitive(java.lang.String testDescription)
Is the db/dialect sensitive in terms of string comparisons?

param
testDescription description of the scenario being tested.
return
true if sensitive

		if ( getDialect().areStringComparisonsCaseInsensitive() ) {
			reportSkip( "Dialect is case sensitive. ", testDescription );
			return true;
		}
		return false;
	
protected booleandialectIsNot(java.lang.Class dialectClass)

		return ! dialectIs( dialectClass );
	
protected booleandialectIsNot(java.lang.Class[] dialectClasses)

		return ! dialectIsOneOf( dialectClasses );
	
protected booleandialectIsOneOf(java.lang.Class[] dialectClasses)

		for ( int i = 0; i < dialectClasses.length; i++ ) {
			if ( dialectClasses[i].isInstance( getDialect() ) ) {
				return true;
			}
		}
		return false;
	
protected booleandialectSupportsEmptyInList(java.lang.String testDescription)
Does the db/dialect support empty lists in the IN operator?

For example, is "... a.b IN () ..." supported?

param
testDescription description of the scenario being tested.
return
true if is allowed

		if ( ! getDialect().supportsEmptyInList() ) {
			reportSkip( "Dialect does not support SQL empty in list : x in ()", testDescription );
			return false;
		}
		return true;
	
protected booleandropAfterFailure()

		return true;
	
public java.lang.StringfullTestName()


	   
		return this.getName() + " (" + this.getClass().getName() + ")";
	
protected java.lang.StringgetBaseForMappings()
The base name for relative mapping resources. The default is org/hibernate/test/

return
the mapping resource base

		return "org/hibernate/test/";
	
protected java.lang.StringgetCacheConcurrencyStrategy()

		return "nonstrict-read-write";
	
protected org.hibernate.cfg.ConfigurationgetCfg()

		return cfg;
	
protected org.hibernate.dialect.DialectgetDialect()

		if ( dialect == null ) {
			dialect = Dialect.getDialect();
		}
		return dialect;
	
protected abstract java.lang.String[]getMappings()
Get the mapping resources to be used to build the configuration.

Resources should be relative to {@link #getBaseForMappings()}

return
The mapping resources

protected org.hibernate.SessionFactorygetSessions()
Get the factory for this test environment.

return
The factory.

		return sessions;
	
public org.hibernate.classic.SessionopenSession()

		session = getSessions().openSession();
		return session;
	
public org.hibernate.classic.SessionopenSession(org.hibernate.Interceptor interceptor)

		session = getSessions().openSession(interceptor);
		return session;
	
protected booleanoverrideCacheStrategy()

		return true;
	
protected booleanreadCommittedIsolationMaintained(java.lang.String scenario)
Is connection at least read committed?

Not, that this skip check relies on the JDBC driver reporting the true isolation level correctly. HSQLDB, for example, will report whatever you specify as the isolation (Connection.setTransationIsolation()), even though it only supports read-uncommitted.

param
scenario text description of the scenario being tested.
return
true if read-committed isolation is maintained.

		int isolation = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
		Session testSession = null;
		try {
			testSession = openSession();
			isolation = testSession.connection().getTransactionIsolation();
		}
		catch( Throwable ignore ) {
		}
		finally {
			if ( testSession != null ) {
				try {
					testSession.close();
				}
				catch( Throwable ignore ) {
				}
			}
		}
		if ( isolation < java.sql.Connection.TRANSACTION_READ_COMMITTED ) {
			reportSkip( "environment does not support at least read committed isolation", scenario );
			return false;
		}
		else {
			return true;
		}
	
protected booleanrecreateSchema()
Should the database schema be (re)created

return
True for auto export (including recreation on test failure).

		return true;
	
protected voidreportSkip(java.lang.String reason, java.lang.String testDescription)

		SKIP_LOG.warn( "*** skipping [" + fullTestName() + "] - " + testDescription + " : " + reason, new Exception()  );
	
public voidrunBare()

		String sysPropName = "hibernate.test.validatefailureexpected";
		assertNotNull( getName() );
		if ( Boolean.getBoolean( sysPropName ) ) {
			if ( getName().endsWith( "FailureExpected" ) ) {
				Throwable t = null;
				try {
					super.runBare();
				}
				catch ( Throwable afe ) {
					t = afe;
				}
				if ( t == null ) {
					fail( "Test where marked as FailureExpected, but did not fail!" );
				}
				else {
					reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + t.toString() );
				}
			}
			else {
				super.runBare();
			}
		}
		else {
			super.runBare();
		}
	
protected voidrunTest()

		final boolean stats = sessions.getStatistics().isStatisticsEnabled();
		try {
			if ( stats ) {
				sessions.getStatistics().clear();
			}

			super.runTest();

			if ( stats ) {
				sessions.getStatistics().logSummary();
			}

			if ( session != null && session.isOpen() ) {
				if ( session.isConnected() ) {
					session.connection().rollback();
				}
				session.close();
				session = null;
				fail( "unclosed session" );
			}
			else {
				session = null;
			}
			assertAllDataRemoved();
		}
		catch ( Throwable e ) {
			try {
				if ( session != null && session.isOpen() ) {
					if ( session.isConnected() ) {
						session.connection().rollback();
					}
					session.close();
				}
			}
			catch ( Exception ignore ) {
			}
			try {
				if ( dropAfterFailure() && sessions != null ) {
					sessions.close();
					sessions = null;
				}
			}
			catch ( Exception ignore ) {
			}
			throw e;
		}
	
protected voidsetUp()
The Hibernate test suite tries to only build the db schema once per test class (not test case which = instance) hence all the static vars.

Here is the crux of that attempt. We only build a factory when one was not previously built, or when we start a new test class.

throws
Exception

		if ( getSessions() == null || lastTestClass != getClass() ) {
			buildSessionFactory();
			lastTestClass = getClass();
		}
	
protected org.hibernate.engine.SessionFactoryImplementorsfi()
Get the factory for this test environment, casted to {@link SessionFactoryImplementor}.

Shorthand for ( {@link SessionFactoryImplementor} ) {@link #getSessions()}...

return
The factory

		return ( SessionFactoryImplementor ) getSessions();
	
protected booleansupportsCircularCascadeDelete()

		if ( ! getDialect().supportsCircularCascadeDeleteConstraints() ) {
			reportSkip( "db/dialect does not support 'circular' cascade delete constraints", "cascade delete constraint support" );
			return false;
		}
		return true;
	
protected booleansupportsExpectedLobUsagePattern()
Expected LOB usage pattern is such that I can perform an insert via prepared statement with a parameter binding for a LOB value without crazy casting to JDBC driver implementation-specific classes...

Part of the trickiness here is the fact that this is largely driver dependent. For Oracle, which is notoriously bad with LOB support in their drivers actually does a pretty good job with LOB support as of the 10.2.x versions of their drivers...

return
True if expected usage pattern is support; false otherwise.

		if ( ! getDialect().supportsExpectedLobUsagePattern() ) {
			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
			return false;
		}
		return true;
	
protected booleansupportsLobValueChangePropogation()
Does the current dialect support propogating changes to LOB values back to the database? Talking about mutating the underlying value as opposed to supplying a new LOB instance...

return
True if the changes are propogated back to the database; false otherwise.

		if ( ! getDialect().supportsLobValueChangePropogation() ) {
			reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" );
			return false;
		}
		return true;
	
protected booleansupportsResultSetPositionQueryMethodsOnForwardOnlyCursor()

		if ( ! getDialect().supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) {
			reportSkip( "Driver does not support 'position query' methods on forward-only cursors", "query support" );
			return false;
		}
		return true;
	
protected booleansupportsRowValueConstructorSyntaxInInList()

		if ( ! getDialect().supportsRowValueConstructorSyntaxInInList() ) {
			reportSkip( "Dialect does not support 'tuple' syntax as part of an IN value list", "query support" );
			return false;
		}
		return true;
	
protected booleansupportsSubqueryOnMutatingTable()

		if ( !getDialect().supportsSubqueryOnMutatingTable() ) {
			reportSkip( "database/driver does not support referencing mutating table in subquery", "bulk DML support" );
			return false;
		}
		return true;
	
protected booleansupportsSubselectOnLeftSideIn()

		if ( ! getDialect().supportsSubselectAsInPredicateLHS() ) {
			reportSkip( "Database does not support (<subselect>) in ( ... ) ", "query support" );
			return false;
		}
		return true;
	
protected booleansupportsUnboundedLobLocatorMaterialization()
Is it supported to materialize a LOB locator outside the transaction in which it was created?

Again, part of the trickiness here is the fact that this is largely driver dependent.

NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()} also support the ability to materialize a LOB outside the owning transaction...

return
True if unbounded materialization is supported; false otherwise.

		if ( !getDialect().supportsUnboundedLobLocatorMaterialization() ) {
			reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" );
			return false;
		}
		return true;