From 7fa7a51016616a2adb493a73215df2191a538039 Mon Sep 17 00:00:00 2001 From: Shawn Clowater Date: Tue, 10 Apr 2012 14:51:28 -0600 Subject: [PATCH] HHH-7239 Adding unit tests for the transaction coordinator when using shared transaction context. One test to show that Sessions are leaked to the transaction observer, one to show that afterTransactionCompletion is not called on any session other than the main and finally one to show that the original session cannot be reused if child sessions were autoclose or flushBeforeCompletion. --- .../SessionWithSharedConnectionTest.java | 123 +++++++++++++++++- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/sharedSession/SessionWithSharedConnectionTest.java b/hibernate-core/src/test/java/org/hibernate/sharedSession/SessionWithSharedConnectionTest.java index adec19accb..a0cd34ca44 100644 --- a/hibernate-core/src/test/java/org/hibernate/sharedSession/SessionWithSharedConnectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/sharedSession/SessionWithSharedConnectionTest.java @@ -23,6 +23,11 @@ */ package org.hibernate.sharedSession; +import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl; +import org.hibernate.engine.transaction.spi.TransactionCoordinator; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.*; +import org.hibernate.testing.FailureExpected; import org.junit.Test; import org.hibernate.IrrelevantEntity; @@ -32,10 +37,10 @@ import org.hibernate.engine.transaction.spi.TransactionContext; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.Assert.*; /** * @author Steve Ebersole @@ -183,7 +188,117 @@ public class SessionWithSharedConnectionTest extends BaseCoreFunctionalTestCase session.getTransaction().commit(); session.close(); } + + @Test + @TestForIssue( jiraKey = "HHH-7239" ) + @FailureExpected(jiraKey = "HHH-7239" ) + public void testSessionRemovedFromObserversOnClose() throws Exception { + Session session = sessionFactory().openSession(); + session.getTransaction().begin(); + //get the initial count of observers (use reflection as the observers property isn't exposed) + Field field = TransactionCoordinatorImpl.class.getDeclaredField( "observers" ); + field.setAccessible(true); + List observers = (List) field.get( ( ( SessionImplementor ) session ).getTransactionCoordinator() ); + int originalObserverSize = observers.size(); + + //opening 2nd session registers it with the TransactionCoordinator currently as an observer + Session secondSession = session.sessionWithOptions() + .connection() + .flushBeforeCompletion( false ) + .autoClose( false ) + .openSession(); + + observers = (List) field.get( ( ( SessionImplementor ) session ).getTransactionCoordinator() ); + //the observer size should be larger + final int observerSizeWithSecondSession = observers.size(); + assertTrue( observerSizeWithSecondSession > originalObserverSize); + + //don't need to actually even do anything with the 2nd session + secondSession.close(); + + //the second session should be released from the observers on close since it didn't have any after transaction actions + observers = (List) field.get( ( ( SessionImplementor ) session ).getTransactionCoordinator() ); + + assertEquals( originalObserverSize, observers.size() ); + + //store the transaction coordinator here since it's not available after session close + TransactionCoordinator transactionCoordinator = ((SessionImplementor) session).getTransactionCoordinator(); + + session.getTransaction().commit(); + session.close(); + + //on original session close all observers should be released + observers = (List) field.get( transactionCoordinator ); + assertEquals( 0, observers.size() ); + } + + @Test + @TestForIssue( jiraKey = "HHH-7239" ) + @FailureExpected(jiraKey = "HHH-7239" ) + public void testChildSessionCallsAfterTransactionAction() throws Exception { + Session session = openSession(); + + final String postCommitMessage = "post commit was called"; + + EventListenerRegistry eventListenerRegistry = sessionFactory().getServiceRegistry().getService(EventListenerRegistry.class); + //register a post commit listener + eventListenerRegistry.appendListeners( EventType.POST_COMMIT_INSERT, new PostInsertEventListener(){ + @Override + public void onPostInsert(PostInsertEvent event) { + ((IrrelevantEntity) event.getEntity()).setName( postCommitMessage ); + } + }); + + session.getTransaction().begin(); + + IrrelevantEntity irrelevantEntityMainSession = new IrrelevantEntity(); + irrelevantEntityMainSession.setName( "main session" ); + session.save( irrelevantEntityMainSession ); + + //open secondary session to also insert an entity + Session secondSession = session.sessionWithOptions() + .connection() + .flushBeforeCompletion( true ) + .autoClose( true ) + .openSession(); + + IrrelevantEntity irrelevantEntitySecondarySession = new IrrelevantEntity(); + irrelevantEntitySecondarySession.setName( "secondary session" ); + secondSession.save( irrelevantEntitySecondarySession ); + + session.getTransaction().commit(); + + //both entities should have their names updated to the postCommitMessage value + assertEquals(postCommitMessage, irrelevantEntityMainSession.getName()); + assertEquals(postCommitMessage, irrelevantEntitySecondarySession.getName()); + } + + @Test + @TestForIssue( jiraKey = "HHH-7239" ) + @FailureExpected(jiraKey = "HHH-7239" ) + public void testChildSessionTwoTransactions() throws Exception { + Session session = openSession(); + + session.getTransaction().begin(); + + //open secondary session with managed options + Session secondarySession = session.sessionWithOptions() + .connection() + .flushBeforeCompletion( true ) + .autoClose( true ) + .openSession(); + + //the secondary session should be automatically closed after the commit + session.getTransaction().commit(); + + assertFalse( secondarySession.isOpen() ); + + //should be able to create a new transaction and carry on using the original session + session.getTransaction().begin(); + session.getTransaction().commit(); + } + @Override protected Class[] getAnnotatedClasses() { return new Class[] { IrrelevantEntity.class };