HHH-12509 Reduce memory usage of PreparedStatementSpyConnectionProvider

This commit is contained in:
Sanne Grinovero 2018-04-19 14:17:19 +01:00
parent c7ea49a0b3
commit 782f023a5a
32 changed files with 68 additions and 44 deletions

View File

@ -47,7 +47,7 @@ public abstract class AbstractCriteriaLiteralHandlingModeTest extends BaseEntity
@Override
public void buildEntityManagerFactory() {
connectionProvider = new PreparedStatementSpyConnectionProvider();
connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
super.buildEntityManagerFactory();
}

View File

@ -59,7 +59,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase {
@Override
public void buildEntityManagerFactory() {
connectionProvider = new PreparedStatementSpyConnectionProvider();
connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
super.buildEntityManagerFactory();
}

View File

@ -26,7 +26,7 @@ import static org.junit.Assert.assertTrue;
*/
public class DisableDiscardPersistenceContextOnCloseTest extends BaseEntityManagerFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Map getConfig() {

View File

@ -25,7 +25,7 @@ import static org.junit.Assert.fail;
*/
public class EnableDiscardPersistenceContextOnCloseTest extends BaseEntityManagerFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Map getConfig() {

View File

@ -50,7 +50,7 @@ public class EntityGraphWithFetchAnnotationTest
@Override
public void buildEntityManagerFactory() {
connectionProvider = new PreparedStatementSpyConnectionProvider();
connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
super.buildEntityManagerFactory();
}

View File

@ -32,7 +32,7 @@ import static org.junit.Assert.fail;
*/
public class StatementIsClosedAfterALockExceptionTest extends BaseEntityManagerFunctionalTestCase {
private static final PreparedStatementSpyConnectionProvider CONNECTION_PROVIDER = new PreparedStatementSpyConnectionProvider();
private static final PreparedStatementSpyConnectionProvider CONNECTION_PROVIDER = new PreparedStatementSpyConnectionProvider( false, false );
private Integer lockId;

View File

@ -59,7 +59,7 @@ public class NamedQueryCommentTest extends BaseEntityManagerFunctionalTestCase {
@Override
public void buildEntityManagerFactory() {
connectionProvider = new PreparedStatementSpyConnectionProvider();
connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
super.buildEntityManagerFactory();
}

View File

@ -26,7 +26,7 @@ import static org.junit.Assert.fail;
public class EmbeddableWithOneToMany_HHH_11302_xml_Test extends
BaseEntityManagerFunctionalTestCase {
PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
public String[] getEjb3DD() {

View File

@ -91,7 +91,7 @@ public class MySQLDropConstraintThrowsExceptionTest extends BaseUnitTestCase {
@Test
public void testEnumTypeInterpretation() {
final PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
final PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.enableAutoClose()

View File

@ -71,7 +71,7 @@ import static org.mockito.Mockito.verify;
@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
public class CriteriaQueryTest extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
public String[] getMappings() {

View File

@ -41,7 +41,7 @@ public class ElementCollectionTest extends BaseNonConfigCoreFunctionalTestCase {
return new Class[] {Task.class};
}
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected void addSettings(Map settings) {

View File

@ -39,7 +39,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithBidirectionalManyToMany
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -37,7 +37,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithBidirectionalMapsIdOneToOne
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -39,7 +39,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithBidirectionalOneToMany
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -28,7 +28,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithBidirectionalOneToOne
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -45,7 +45,7 @@ import static org.junit.Assert.assertEquals;
public class InsertOrderingWithJoinedTableInheritance
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -44,7 +44,7 @@ import static org.junit.Assert.assertEquals;
public class InsertOrderingWithJoinedTableMultiLevelInheritance
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -39,7 +39,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithManyToOne
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -40,7 +40,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithMultipleManyToOne
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -45,7 +45,7 @@ import static org.junit.Assert.assertEquals;
public class InsertOrderingWithSingleTableInheritance
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -45,7 +45,7 @@ import static org.junit.Assert.assertEquals;
public class InsertOrderingWithTablePerClassInheritance
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -36,7 +36,7 @@ import static org.mockito.Mockito.verify;
public class InsertOrderingWithUnidirectionalOneToOne
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class[] getAnnotatedClasses() {

View File

@ -30,7 +30,7 @@ import static org.mockito.Mockito.verify;
public class SessionJdbcBatchTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -50,7 +50,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void buildResources() {
connectionProvider = new PreparedStatementSpyConnectionProvider();
connectionProvider = new PreparedStatementSpyConnectionProvider( false, false );
super.buildResources();
}

View File

@ -35,7 +35,7 @@ import static org.mockito.Mockito.verify;
*/
public class QueryTimeOutTest extends BaseNonConfigCoreFunctionalTestCase {
private static final PreparedStatementSpyConnectionProvider CONNECTION_PROVIDER = new PreparedStatementSpyConnectionProvider();
private static final PreparedStatementSpyConnectionProvider CONNECTION_PROVIDER = new PreparedStatementSpyConnectionProvider( true, false );
private static final String QUERY = "update AnEntity set name='abc'";
@Override

View File

@ -33,7 +33,7 @@ import static org.mockito.Mockito.verify;
public abstract class AbstractSkipAutoCommitTest extends BaseEntityManagerFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider =
new PreparedStatementSpyConnectionProvider() {
new PreparedStatementSpyConnectionProvider( false, true ) {
@Override
protected Connection actualConnection() throws SQLException {
Connection connection = super.actualConnection();

View File

@ -45,7 +45,7 @@ import static org.mockito.Mockito.verify;
public class JdbcTimeCustomTimeZoneTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
"America/Los_Angeles" );

View File

@ -34,7 +34,7 @@ import static org.mockito.Mockito.verify;
public class JdbcTimeDefaultTimeZoneTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -42,7 +42,7 @@ import static org.mockito.Mockito.verify;
public class JdbcTimestampCustomSessionLevelTimeZoneTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
"America/Los_Angeles" );

View File

@ -42,7 +42,7 @@ import static org.mockito.Mockito.verify;
public class JdbcTimestampCustomTimeZoneTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
"America/Los_Angeles" );

View File

@ -33,7 +33,7 @@ import static org.mockito.Mockito.verify;
public class JdbcTimestampDefaultTimeZoneTest
extends BaseNonConfigCoreFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider( true, false );
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -21,6 +21,7 @@ import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.testing.jdbc.ConnectionProviderDelegate;
import org.mockito.ArgumentMatchers;
import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.internal.util.MockUtil;
@ -29,23 +30,42 @@ import org.mockito.internal.util.MockUtil;
* intercept the underlying {@link PreparedStatement} method calls.
*
* @author Vlad Mihalcea
* @author Sannne Grinovero
*/
public class PreparedStatementSpyConnectionProvider
extends ConnectionProviderDelegate {
public class PreparedStatementSpyConnectionProvider extends ConnectionProviderDelegate {
private static final MockSettings MOCK_SETTINGS = Mockito.withSettings()
.stubOnly() //important optimisation: uses far less memory, at tradeoff of mocked methods no longer being verifiable but we often don't need that.
.defaultAnswer( org.mockito.Answers.CALLS_REAL_METHODS );
private static final MockSettings VERIFIEABLE_MOCK_SETTINGS = Mockito.withSettings()
.defaultAnswer( org.mockito.Answers.CALLS_REAL_METHODS );
private final Map<PreparedStatement, String> preparedStatementMap = new LinkedHashMap<>();
private final List<String> executeStatements = new ArrayList<>();
private final List<String> executeUpdateStatements = new ArrayList<>();
private final List<String> executeStatements = new ArrayList<>( 4 );
private final List<String> executeUpdateStatements = new ArrayList<>( 4 );
private final List<Connection> acquiredConnections = new ArrayList<>( );
private final List<Connection> releasedConnections = new ArrayList<>( );
private final List<Connection> acquiredConnections = new ArrayList<>( 4 );
private final List<Connection> releasedConnections = new ArrayList<>( 4 );
private final MockSettings settingsForStatements;
private final MockSettings settingsForConnections;
/**
* @deprecated best use the {@link #PreparedStatementSpyConnectionProvider(boolean,boolean)} method to be explicit about the limitations.
*/
@Deprecated
public PreparedStatementSpyConnectionProvider() {
this( false, false );
}
public PreparedStatementSpyConnectionProvider(ConnectionProvider connectionProvider) {
super( connectionProvider );
/**
* Careful: the default is to use mocks which do not allow to verify invocations, as otherwise the
* memory usage of the testsuite is extremely high.
* When you really need to verify invocations, set the relevant constructor parameter to true.
*/
public PreparedStatementSpyConnectionProvider(boolean allowMockVerificationOnStatements, boolean allowMockVerificationOnConnections) {
this.settingsForStatements = allowMockVerificationOnStatements ? VERIFIEABLE_MOCK_SETTINGS : MOCK_SETTINGS;
this.settingsForConnections = allowMockVerificationOnConnections ? VERIFIEABLE_MOCK_SETTINGS : MOCK_SETTINGS;
}
protected Connection actualConnection() throws SQLException {
@ -54,7 +74,7 @@ public class PreparedStatementSpyConnectionProvider
@Override
public Connection getConnection() throws SQLException {
Connection connection = spy( actualConnection() );
Connection connection = instrumentConnection( actualConnection() );
acquiredConnections.add( connection );
return connection;
}
@ -72,15 +92,15 @@ public class PreparedStatementSpyConnectionProvider
super.stop();
}
private Connection spy(Connection connection) {
private Connection instrumentConnection(Connection connection) {
if ( MockUtil.isMock( connection ) ) {
return connection;
}
Connection connectionSpy = Mockito.spy( connection );
Connection connectionSpy = spy( connection, settingsForConnections );
try {
Mockito.doAnswer( invocation -> {
PreparedStatement statement = (PreparedStatement) invocation.callRealMethod();
PreparedStatement statementSpy = Mockito.spy( statement );
PreparedStatement statementSpy = spy( statement, settingsForStatements );
String sql = (String) invocation.getArguments()[0];
preparedStatementMap.put( statementSpy, sql );
return statementSpy;
@ -88,7 +108,7 @@ public class PreparedStatementSpyConnectionProvider
Mockito.doAnswer( invocation -> {
Statement statement = (Statement) invocation.callRealMethod();
Statement statementSpy = Mockito.spy( statement );
Statement statementSpy = spy( statement, settingsForStatements );
Mockito.doAnswer( statementInvocation -> {
String sql = (String) statementInvocation.getArguments()[0];
executeStatements.add( sql );
@ -108,6 +128,10 @@ public class PreparedStatementSpyConnectionProvider
return connectionSpy;
}
private static <T> T spy(T subject, MockSettings mockSettings) {
return Mockito.mock( (Class<T>) subject.getClass(), mockSettings.spiedInstance( subject ) );
}
/**
* Clears the recorded PreparedStatements and reset the associated Mocks.
*/