HHH-10654 - Fix mariadb and pgsql failing tests
This commit is contained in:
parent
19c03e0c5a
commit
5fd186a010
|
@ -23,6 +23,7 @@ import javax.persistence.PessimisticLockException;
|
|||
import javax.persistence.Query;
|
||||
import javax.persistence.QueryTimeoutException;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
|
@ -40,6 +41,8 @@ import org.hibernate.testing.RequiresDialect;
|
|||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.SkipForDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.hibernate.testing.util.ExceptionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -156,19 +159,23 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
try {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put( org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT, -2L );
|
||||
properties.put( org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED );
|
||||
em2.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_READ, properties );
|
||||
|
||||
try {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
TransactionUtil.setJdbcTimeout( entityManager.unwrap( Session.class ) );
|
||||
entityManager.createNativeQuery( updateStatement() )
|
||||
.setParameter( "name", "changed" )
|
||||
.setParameter( "id", lock.getId() )
|
||||
.executeUpdate();
|
||||
} );
|
||||
fail("Should throw LockTimeoutException");
|
||||
fail("Should throw Exception");
|
||||
}
|
||||
catch (LockTimeoutException expected) {
|
||||
catch (Exception e) {
|
||||
if ( !ExceptionUtil.isSqlLockTimeout( e) ) {
|
||||
fail( "Unknown exception thrown: " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -202,13 +209,16 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
|
|||
try {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
try {
|
||||
TransactionUtil.setJdbcTimeout( entityManager.unwrap( Session.class ) );
|
||||
entityManager.createNativeQuery( updateStatement() )
|
||||
.setParameter( "name", "changed" )
|
||||
.setParameter( "id", lock.getId() )
|
||||
.executeUpdate();
|
||||
}
|
||||
catch (LockTimeoutException | PessimisticLockException expected) {
|
||||
failureExpected.set( true );
|
||||
catch (Exception e) {
|
||||
if ( ExceptionUtil.isSqlLockTimeout( e ) ) {
|
||||
failureExpected.set( true );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.query.criteria.internal.expression;
|
|||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
|
@ -16,6 +18,11 @@ import javax.persistence.criteria.Expression;
|
|||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.SkipForDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -29,7 +36,8 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|||
public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
public void testCaseClause() {
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public void testCaseClause() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
|
||||
|
@ -87,6 +95,7 @@ public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase {
|
|||
private Long id;
|
||||
|
||||
@Column
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventType type;
|
||||
|
||||
protected Event() {
|
||||
|
|
|
@ -7,19 +7,17 @@
|
|||
package org.hibernate.test.locking;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||
import org.hibernate.exception.GenericJDBCException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
|
||||
import org.hibernate.testing.SkipForDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.hibernate.testing.util.ExceptionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
@ -164,43 +162,38 @@ public class LockModeTest extends BaseCoreFunctionalTestCase {
|
|||
// until the txn in the calling method completed.
|
||||
// To be able to cater to the second type, we run this block in a separate thread to be able to "time it out"
|
||||
|
||||
executeSync( () -> {
|
||||
doInHibernate( this::sessionFactory, _session -> {
|
||||
_session.doWork( connection -> {
|
||||
try {
|
||||
executeSync( () -> {
|
||||
doInHibernate( this::sessionFactory, _session -> {
|
||||
TransactionUtil.setJdbcTimeout( _session );
|
||||
try {
|
||||
connection.setNetworkTimeout( Executors.newSingleThreadExecutor(), 1000);
|
||||
} catch (Throwable ignore) {
|
||||
ignore.fillInStackTrace();
|
||||
// load with write lock to deal with databases that block (wait indefinitely) direct attempts
|
||||
// to write a locked row
|
||||
A it = _session.get(
|
||||
A.class,
|
||||
id,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setTimeOut( LockOptions.NO_WAIT )
|
||||
);
|
||||
_session.createNativeQuery( updateStatement() )
|
||||
.setParameter( "value", "changed" )
|
||||
.setParameter( "id", it.getId() )
|
||||
.executeUpdate();
|
||||
fail( "Pessimistic lock not obtained/held" );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
if ( !ExceptionUtil.isSqlLockTimeout( e) ) {
|
||||
fail( "Unexpected error type testing pessimistic locking : " + e.getClass().getName() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
try {
|
||||
// load with write lock to deal with databases that block (wait indefinitely) direct attempts
|
||||
// to write a locked row
|
||||
A it = _session.get(
|
||||
A.class,
|
||||
id,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setTimeOut( LockOptions.NO_WAIT )
|
||||
);
|
||||
_session.createNativeQuery( updateStatement() )
|
||||
.setParameter( "value", "changed" )
|
||||
.setParameter( "id", it.getId() )
|
||||
.executeUpdate();
|
||||
fail( "Pessimistic lock not obtained/held" );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
// grr, exception can be any number of types based on database
|
||||
// see HHH-6887
|
||||
if ( LockAcquisitionException.class.isInstance( e )
|
||||
|| GenericJDBCException.class.isInstance( e )
|
||||
|| PessimisticLockException.class.isInstance( e ) ) {
|
||||
// "ok"
|
||||
}
|
||||
else {
|
||||
fail( "Unexpected error type testing pessimistic locking : " + e.getClass().getName() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
catch (Exception e) {
|
||||
//MariaDB throws a time out nd closes the underlying connection
|
||||
if( !ExceptionUtil.isConnectionClose(e)) {
|
||||
fail("Unknown exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String updateStatement() {
|
||||
|
|
|
@ -91,7 +91,7 @@ public abstract class BaseUnitTestCase {
|
|||
Thread.currentThread().interrupt();
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw new RuntimeException( e );
|
||||
throw new RuntimeException( e.getCause() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.testing.transaction;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -13,16 +15,25 @@ import javax.persistence.EntityManager;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityTransaction;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionBuilder;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class TransactionUtil {
|
||||
|
||||
private static final Logger log = Logger.getLogger( TransactionUtil.class );
|
||||
|
||||
/**
|
||||
* Hibernate transaction function
|
||||
*
|
||||
|
@ -322,4 +333,38 @@ public class TransactionUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Session or Statement timeout
|
||||
* @param session Hibernate Session
|
||||
*/
|
||||
public static void setJdbcTimeout(Session session) {
|
||||
session.doWork( connection -> {
|
||||
if ( Dialect.getDialect() instanceof PostgreSQL81Dialect ) {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute( "SET statement_timeout TO 1000" );
|
||||
}
|
||||
|
||||
}
|
||||
else if( Dialect.getDialect() instanceof MySQLDialect ) {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute( "SET GLOBAL innodb_lock_wait_timeout = 1" );
|
||||
}
|
||||
}
|
||||
else if( Dialect.getDialect() instanceof H2Dialect ) {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute( "SET LOCK_TIMEOUT 100" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
connection.setNetworkTimeout( Executors.newSingleThreadExecutor(), 1000 );
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
ignore.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package org.hibernate.testing.util;
|
||||
|
||||
import javax.persistence.LockTimeoutException;
|
||||
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.exception.GenericJDBCException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
private static final ExceptionUtil INSTANCE = new ExceptionUtil();
|
||||
|
||||
public static ExceptionUtil getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private ExceptionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root cause of a particular {@code Throwable}
|
||||
*
|
||||
* @param t exception
|
||||
*
|
||||
* @return exception root cause
|
||||
*/
|
||||
public static Throwable rootCause(Throwable t) {
|
||||
Throwable cause = t.getCause();
|
||||
if ( cause != null && cause != t ) {
|
||||
return rootCause( cause );
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the given exception caused by a SQL lock timeout?
|
||||
*
|
||||
* @param e exception
|
||||
*
|
||||
* @return is caused by a SQL lock timeout
|
||||
*/
|
||||
public static boolean isSqlLockTimeout(Exception e) {
|
||||
// grr, exception can be any number of types based on database
|
||||
// see HHH-6887
|
||||
if ( LockAcquisitionException.class.isInstance( e )
|
||||
|| LockTimeoutException.class.isInstance( e )
|
||||
|| GenericJDBCException.class.isInstance( e )
|
||||
|| PessimisticLockException.class.isInstance( e )
|
||||
|| javax.persistence.PessimisticLockException.class.isInstance( e )
|
||||
|| JDBCConnectionException.class.isInstance( e ) ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Throwable rootCause = ExceptionUtil.rootCause( e );
|
||||
if ( rootCause != null && (
|
||||
rootCause.getMessage().contains( "timeout" ) ||
|
||||
rootCause.getMessage().contains( "timed out" ) )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the given exception caused by a SQL connection close
|
||||
*
|
||||
* @param e exception
|
||||
*
|
||||
* @return is caused by a SQL connection close
|
||||
*/
|
||||
public static boolean isConnectionClose(Exception e) {
|
||||
Throwable rootCause = ExceptionUtil.rootCause( e );
|
||||
if ( rootCause != null && (
|
||||
rootCause.getMessage().toLowerCase().contains( "connection is close" )
|
||||
) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue