fix and clean up AbstractJPATest

clean up LockTest a little

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-09-01 14:52:04 +02:00
parent f805bcec63
commit dd16ed61f0
8 changed files with 60 additions and 153 deletions

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.orm.test.jpa.cascade2;
import jakarta.persistence.RollbackException;
import org.hibernate.Session;
import org.hibernate.TransientObjectException;
@ -60,8 +61,8 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
assertTyping( TransientObjectException.class, e.getCause() );
catch (RollbackException e) {
assertTyping( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -91,9 +92,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -123,9 +124,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -153,9 +154,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -183,9 +184,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -211,9 +212,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -239,9 +240,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -268,9 +269,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {
@ -297,9 +298,9 @@ public class CascadeTest extends AbstractJPATest {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch (IllegalStateException e) {
catch (RollbackException e) {
// expected result
assertInstanceOf( TransientObjectException.class, e.getCause() );
assertInstanceOf( TransientObjectException.class, e.getCause().getCause() );
s.getTransaction().rollback();
}
finally {

View File

@ -155,7 +155,7 @@ public class JPALockTest extends AbstractJPATest {
inTransaction(
session ->
session.remove( item )
session.remove( session.getReference(item) )
);
}
@ -270,7 +270,7 @@ public class JPALockTest extends AbstractJPATest {
inTransaction(
session -> {
session.remove( item );
session.remove( session.getReference(item) );
}
);
}

View File

@ -15,6 +15,8 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import jakarta.persistence.Timeout;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.Session;
@ -85,7 +87,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
} );
doInJPA( this::entityManagerFactory, em -> {
Map<String, Object> properties = new HashMap<String, Object>();
Map<String, Object> properties = new HashMap<>();
properties.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, 0L );
em.find( Lock.class, 1, LockModeType.PESSIMISTIC_WRITE, properties );
} );
@ -119,7 +121,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
doInJPA( this::entityManagerFactory, entityManager -> {
TransactionUtil.withJdbcTimeout( entityManager.unwrap( Session.class ), () -> {
try {
Map<String, Object> properties = new HashMap<String, Object>();
Map<String, Object> properties = new HashMap<>();
properties.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, 0L );
entityManager.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_WRITE, properties );
@ -305,7 +307,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
doInJPA( this::entityManagerFactory, _entityManagaer -> {
Map<String, Object> properties = new HashMap<>();
properties.put( AvailableSettings.JPA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED );
properties.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED );
_entityManagaer.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_READ, properties );
try {
@ -703,9 +705,9 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
Lock lock2 = _entityManager.getReference( Lock.class, lock.getId() );
lock2.getName(); // force entity to be read
log.info( "testContendedPessimisticReadLockTimeout: (BG) read write-locked entity" );
Map<String, Object> props = new HashMap<String, Object>();
Map<String, Object> props = new HashMap<>();
// timeout is in milliseconds
props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 );
props.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, 1000 );
try {
_entityManager.lock( lock2, LockModeType.PESSIMISTIC_READ, props );
}
@ -786,9 +788,9 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
Lock lock2 = _entityManager.getReference( Lock.class, lock.getId() );
lock2.getName(); // force entity to be read
log.info( "testContendedPessimisticWriteLockTimeout: (BG) read write-locked entity" );
Map<String, Object> props = new HashMap<String, Object>();
Map<String, Object> props = new HashMap<>();
// timeout is in milliseconds
props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 );
props.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, 1000 );
try {
_entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props );
}
@ -867,11 +869,8 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
Lock lock2 = _entityManager.getReference( Lock.class, lock.getId() );
lock2.getName(); // force entity to be read
log.info( "testContendedPessimisticWriteLockNoWait: (BG) read write-locked entity" );
Map<String, Object> props = new HashMap<String, Object>();
// timeout of zero means no wait (for lock)
props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 0 );
try {
_entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props );
_entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE, Timeout.ms(0) );
}
catch ( LockTimeoutException e ) {
// success
@ -904,8 +903,8 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
doInJPA( this::entityManagerFactory, em -> {
Lock _lock = em.getReference( Lock.class, lock.getId() );
assertFalse( Hibernate.isInitialized(_lock) );
em.lock( _lock, LockModeType.PESSIMISTIC_WRITE );
final Integer id = _lock.getId();
_lock.getName(); // force entity to be read
log.info( "testContendedPessimisticWriteLockNoWait: got write lock" );
@ -1019,7 +1018,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
public void testQueryTimeoutEMProps() throws Exception {
final CountDownLatch latch = new CountDownLatch( 1 );
final Map<String, Object> timeoutProps = new HashMap<String, Object>();
final Map<String, Object> timeoutProps = new HashMap<>();
timeoutProps.put( HINT_SPEC_QUERY_TIMEOUT, 500 ); // 1 sec timeout (should round up)
final Lock lock = new Lock();
@ -1106,8 +1105,8 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
final CountDownLatch latch = new CountDownLatch( 1 );
final Map<String, Object> timeoutProps = new HashMap<String, Object>();
timeoutProps.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 ); // 1 second timeout
final Map<String, Object> timeoutProps = new HashMap<>();
timeoutProps.put( AvailableSettings.JAKARTA_LOCK_TIMEOUT, 1000 ); // 1 second timeout
final Lock lock = new Lock();
FutureTask<Boolean> bgTask = new FutureTask<>(
@ -1156,8 +1155,8 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
doInJPA( this::entityManagerFactory, em -> {
Lock _lock = em.getReference( Lock.class, lock.getId() );
assertFalse( Hibernate.isInitialized(_lock) );
em.lock( _lock, LockModeType.PESSIMISTIC_WRITE );
final Integer id = _lock.getId();
_lock.getName(); // force entity to be read
log.info( "testLockTimeoutEMProps: got write lock" );

View File

@ -8,6 +8,7 @@ package org.hibernate.orm.test.jpa.lock;
import java.math.BigDecimal;
import jakarta.persistence.OptimisticLockException;
import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
@ -151,7 +152,8 @@ public class RepeatableReadTest extends AbstractJPATest {
s1.lock( item, LockMode.PESSIMISTIC_WRITE );
fail( "expected UPGRADE lock failure" );
}
catch (StaleObjectStateException expected) {
catch (OptimisticLockException expected) {
assertTrue( expected.getCause() instanceof StaleObjectStateException );
// this is the expected behavior
}
catch (SQLGrammarException t) {

View File

@ -9,28 +9,11 @@ package org.hibernate.orm.test.jpa.model;
import java.sql.Connection;
import org.hibernate.Session;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuilderImplementor;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.internal.DefaultAutoFlushEventListener;
import org.hibernate.event.internal.DefaultFlushEntityEventListener;
import org.hibernate.event.internal.DefaultFlushEventListener;
import org.hibernate.event.internal.DefaultPersistEventListener;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.FlushEntityEventListener;
import org.hibernate.event.spi.FlushEventListener;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.testing.SkipLog;
import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
@ -52,6 +35,8 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
};
}
// mimic specific exception aspects of the JPA environment ~~~~~~~~~~~~~~~~
@Override
protected void applySettings(StandardServiceRegistryBuilder builder) {
builder.applySetting( Environment.JPA_QUERY_COMPLIANCE, "true" );
@ -61,97 +46,22 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
@Override
protected void configure(SessionFactoryBuilder builder) {
super.configure( builder );
builder.applyEntityNotFoundDelegate( new JPAEntityNotFoundDelegate() );
builder.applyEntityNotFoundDelegate( (entityName, id) -> {
throw new EntityNotFoundException( "Unable to find " + entityName + " with id " + id );
} );
}
@Override
public void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) {
builder.applyIntegrator(
new Integrator() {
@Override
public void integrate(
Metadata metadata,
BootstrapContext bootstrapContext,
SessionFactoryImplementor sessionFactory) {
integrate( sessionFactory );
}
private void integrate(SessionFactoryImplementor sessionFactory) {
EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry().getService(
EventListenerRegistry.class );
eventListenerRegistry.setListeners( EventType.PERSIST, buildPersistEventListeners() );
eventListenerRegistry.setListeners(
EventType.PERSIST_ONFLUSH, buildPersisOnFlushEventListeners()
);
eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, buildAutoFlushEventListeners() );
eventListenerRegistry.setListeners( EventType.FLUSH, buildFlushEventListeners() );
eventListenerRegistry.setListeners( EventType.FLUSH_ENTITY, buildFlushEntityEventListeners() );
}
}
);
protected void applyMetadataBuilder(MetadataBuilder metadataBuilder) {
((MetadataBuilderImplementor) metadataBuilder).getBootstrapContext().markAsJpaBootstrap();
}
// mimic specific exception aspects of the JPA environment ~~~~~~~~~~~~~~~~
private static class JPAEntityNotFoundDelegate implements EntityNotFoundDelegate {
public void handleEntityNotFound(String entityName, Object id) {
throw new EntityNotFoundException( "Unable to find " + entityName + " with id " + id );
}
}
// mimic specific event aspects of the JPA environment ~~~~~~~~~~~~~~~~~~~~
protected PersistEventListener[] buildPersistEventListeners() {
return new PersistEventListener[] { new JPAPersistEventListener() };
}
protected PersistEventListener[] buildPersisOnFlushEventListeners() {
return new PersistEventListener[] { new JPAPersistOnFlushEventListener() };
}
protected AutoFlushEventListener[] buildAutoFlushEventListeners() {
return new AutoFlushEventListener[] { JPAAutoFlushEventListener.INSTANCE };
}
protected FlushEventListener[] buildFlushEventListeners() {
return new FlushEventListener[] { JPAFlushEventListener.INSTANCE };
}
protected FlushEntityEventListener[] buildFlushEntityEventListeners() {
return new FlushEntityEventListener[] { new JPAFlushEntityEventListener() };
}
public static class JPAPersistEventListener extends DefaultPersistEventListener {
// overridden in JPA impl for entity callbacks...
}
public static class JPAPersistOnFlushEventListener extends JPAPersistEventListener {
@Override
protected CascadingAction<PersistContext> getCascadeAction() {
return CascadingActions.PERSIST_ON_FLUSH;
}
}
public static class JPAAutoFlushEventListener extends DefaultAutoFlushEventListener {
// not sure why EM code has this ...
public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener();
}
public static class JPAFlushEventListener extends DefaultFlushEventListener {
// not sure why EM code has this ...
public static final FlushEventListener INSTANCE = new JPAFlushEventListener();
}
public static class JPAFlushEntityEventListener extends DefaultFlushEntityEventListener {
// in JPA, used mainly for preUpdate callbacks...
}
// a useful method that doesn't really belong here ~~~~~~~~~~~~~~~~
protected boolean readCommittedIsolationMaintained(String scenario) {
final int isolation;
try (Session testSession = sessionFactory().openSession()) {
isolation = testSession.doReturningWork(
Connection::getTransactionIsolation
);
try ( Session testSession = sessionFactory().openSession() ) {
isolation = testSession.doReturningWork(Connection::getTransactionIsolation);
}
if ( isolation < Connection.TRANSACTION_READ_COMMITTED ) {
SkipLog.reportSkip( "environment does not support at least read committed isolation", scenario );

View File

@ -63,7 +63,7 @@ public class ImmutableNaturalIdTest extends AbstractJPATest {
// clean up
inTransaction(
session ->
session.remove( merged )
session.remove( session.getReference(merged) )
);
}
@ -72,7 +72,6 @@ public class ImmutableNaturalIdTest extends AbstractJPATest {
sessionFactoryScope().inSession(
session -> {
Transaction t = session.beginTransaction();
User u = new User( "steve", "superSecret" );
session.persist( u );
u.setUserName( "Steve" );
@ -84,8 +83,6 @@ public class ImmutableNaturalIdTest extends AbstractJPATest {
//expected
t.rollback();
}
u.setUserName( "steve" );
session.remove( u );
session.close();
}
);

View File

@ -36,8 +36,9 @@ public class RemovedEntityTest extends AbstractJPATest {
boolean contains = fromTransaction(
session -> {
session.remove( item );
return session.contains( item );
Item reference = session.getReference( item );
session.remove( reference );
return session.contains( reference );
}
);
@ -58,7 +59,7 @@ public class RemovedEntityTest extends AbstractJPATest {
Item item = fromTransaction(
session -> {
session.remove( it );
session.remove( session.get( Item.class, id ) );
return session.get( Item.class, id );
}
);
@ -108,7 +109,7 @@ public class RemovedEntityTest extends AbstractJPATest {
// clean up
inTransaction(
session ->
session.remove( item )
session.remove( session.getReference(item) )
);
}
@ -138,7 +139,7 @@ public class RemovedEntityTest extends AbstractJPATest {
// clean up
inTransaction(
session ->
session.remove( item )
session.remove( session.getReference(item) )
);
}
@ -173,7 +174,7 @@ public class RemovedEntityTest extends AbstractJPATest {
// clean up
inTransaction(
session ->
session.remove( item )
session.remove( session.getReference(item) )
);
}
}

View File

@ -168,10 +168,7 @@ public class SessionFactoryExtension
throw new IllegalStateException( "Could not determine SessionFactory producer" );
}
final SessionFactoryScopeImpl sfScope = new SessionFactoryScopeImpl(
domainModelScope,
producer
);
final SessionFactoryScopeImpl sfScope = new SessionFactoryScopeImpl( domainModelScope, producer );
if ( testInstance instanceof SessionFactoryScopeAware ) {
( (SessionFactoryScopeAware) testInstance ).injectSessionFactoryScope( sfScope );