Skip to content

Commit 459eb50

Browse files
authored
Test batching (#1332)
* [#1333] Create the configuration for tests only if needed The method that creates the configuration was called before each test even if when not necessary - we create the factory only once. This commit makes sure that the configuration is created only when the factory is created. * [#1333] Test batching is actually happening * [#1333] Test batching with persist(Object[]) * [#1333] SqlStatementTracker javadoc SqlStatementTracker is not thread-safe
1 parent b6724e9 commit 459eb50

File tree

3 files changed

+93
-10
lines changed

3 files changed

+93
-10
lines changed

hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.concurrent.CompletableFuture;
1111
import java.util.concurrent.CompletionStage;
1212
import java.util.concurrent.TimeUnit;
13+
import java.util.function.Supplier;
1314
import javax.persistence.criteria.CriteriaQuery;
1415

1516
import org.hibernate.SessionFactory;
@@ -173,17 +174,30 @@ private <T> CriteriaQuery<T> queryForDelete(Class<T> entityClass) {
173174

174175
@Before
175176
public void before(TestContext context) {
176-
test( context, setupSessionFactory( constructConfiguration() ) );
177+
test( context, setupSessionFactory( () -> constructConfiguration() ) );
177178
}
178179

180+
/**
181+
* Set up one session factory shared by the tests in the class.
182+
*/
179183
protected CompletionStage<Void> setupSessionFactory(Configuration configuration) {
184+
return setupSessionFactory( () -> configuration );
185+
}
186+
187+
/**
188+
* Set up the session factory but create the configuration only if necessary.
189+
*
190+
* @param confSupplier supplies the configuration for the factory
191+
* @return a {@link CompletionStage} void that succeeds when the factory is ready.
192+
*/
193+
protected CompletionStage<Void> setupSessionFactory(Supplier<Configuration> confSupplier) {
180194
CompletableFuture<Void> future = new CompletableFuture<>();
181195
vertxContextRule.vertx()
182196
.executeBlocking(
183197
// schema generation is a blocking operation and so it causes an
184198
// exception when run on the Vert.x event loop. So call it using
185199
// Vertx.executeBlocking()
186-
promise -> startFactoryManager( promise, configuration ),
200+
promise -> startFactoryManager( promise, confSupplier ),
187201
event -> {
188202
if ( event.succeeded() ) {
189203
future.complete( null );
@@ -196,9 +210,9 @@ protected CompletionStage<Void> setupSessionFactory(Configuration configuration)
196210
return future;
197211
}
198212

199-
private void startFactoryManager(Promise<Object> p, Configuration configuration ) {
213+
private void startFactoryManager(Promise<Object> p, Supplier<Configuration> confSupplier ) {
200214
try {
201-
factoryManager.start( () -> createHibernateSessionFactory( configuration ) );
215+
factoryManager.start( () -> createHibernateSessionFactory( confSupplier.get() ) );
202216
p.complete();
203217
}
204218
catch (Throwable e) {

hibernate-reactive-core/src/test/java/org/hibernate/reactive/BatchingConnectionTest.java

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
package org.hibernate.reactive;
77

8+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
89
import org.hibernate.cfg.AvailableSettings;
910
import org.hibernate.cfg.Configuration;
1011
import org.hibernate.reactive.mutiny.impl.MutinySessionImpl;
@@ -13,6 +14,7 @@
1314
import org.hibernate.reactive.pool.impl.SqlClientConnection;
1415
import org.hibernate.reactive.stage.impl.StageSessionImpl;
1516
import org.hibernate.reactive.stage.impl.StageStatelessSessionImpl;
17+
import org.hibernate.reactive.testing.SqlStatementTracker;
1618

1719
import org.junit.Test;
1820

@@ -24,13 +26,59 @@
2426

2527
public class BatchingConnectionTest extends ReactiveSessionTest {
2628

29+
private static SqlStatementTracker sqlTracker;
30+
2731
@Override
2832
protected Configuration constructConfiguration() {
2933
Configuration configuration = super.constructConfiguration();
3034
configuration.setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, "5");
35+
36+
// Construct a tracker that collects query statements via the SqlStatementLogger framework.
37+
// Pass in configuration properties to hand-off any actual logging properties
38+
sqlTracker = new SqlStatementTracker( BatchingConnectionTest::filter, configuration.getProperties() );
3139
return configuration;
3240
}
3341

42+
protected void addServices(StandardServiceRegistryBuilder builder) {
43+
sqlTracker.registerService( builder );
44+
}
45+
46+
private static boolean filter(String s) {
47+
String[] accepted = { "insert ", "update ", "delete " };
48+
for ( String valid : accepted ) {
49+
if ( s.toLowerCase().startsWith( valid ) ) {
50+
return true;
51+
}
52+
}
53+
return false;
54+
}
55+
56+
@Test
57+
public void testBatchingWithPersistAll(TestContext context) {
58+
test( context, openSession()
59+
.thenCompose( s -> s
60+
.persist(
61+
new GuineaPig( 11, "One" ),
62+
new GuineaPig( 22, "Two" ),
63+
new GuineaPig( 33, "Three" )
64+
)
65+
// Auto-flush
66+
.thenCompose( v -> s
67+
.createQuery( "select name from GuineaPig" )
68+
.getResultList()
69+
.thenAccept( names -> {
70+
assertThat( names ).containsExactlyInAnyOrder( "One", "Two", "Three" );
71+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
72+
// Parameters are different for different dbs, so we cannot do an exact match
73+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
74+
.startsWith( "insert into pig (name, version, id) values " );
75+
sqlTracker.clear();
76+
} )
77+
)
78+
)
79+
);
80+
}
81+
3482
@Test
3583
public void testBatching(TestContext context) {
3684
test(
@@ -40,9 +88,17 @@ public void testBatching(TestContext context) {
4088
.thenCompose( v -> s.persist( new GuineaPig(11, "One") ) )
4189
.thenCompose( v -> s.persist( new GuineaPig(22, "Two") ) )
4290
.thenCompose( v -> s.persist( new GuineaPig(33, "Three") ) )
43-
.thenCompose( v -> s.createQuery("select count(*) from GuineaPig")
44-
.getSingleResult()
45-
.thenAccept( count -> context.assertEquals( 3L, count) )
91+
// Auto-flush
92+
.thenCompose( v -> s.createQuery("select name from GuineaPig")
93+
.getResultList()
94+
.thenAccept( names -> {
95+
assertThat( names ).containsExactlyInAnyOrder( "One", "Two", "Three" );
96+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
97+
// Parameters are different for different dbs, so we cannot do an exact match
98+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
99+
.startsWith( "insert into pig (name, version, id) values " );
100+
sqlTracker.clear();
101+
} )
46102
)
47103
)
48104
.thenCompose( v -> openSession() )
@@ -51,15 +107,27 @@ public void testBatching(TestContext context) {
51107
.thenAccept( list -> list.forEach( pig -> pig.setName("Zero") ) )
52108
.thenCompose( v -> s.<Long>createQuery("select count(*) from GuineaPig where name='Zero'")
53109
.getSingleResult()
54-
.thenAccept( count -> context.assertEquals( 3L, count) )
110+
.thenAccept( count -> {
111+
context.assertEquals( 3L, count);
112+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
113+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
114+
.matches( "update pig set name=.+, version=.+ where id=.+ and version=.+" );
115+
sqlTracker.clear();
116+
} )
55117
) )
56118
.thenCompose( v -> openSession() )
57119
.thenCompose( s -> s.<GuineaPig>createQuery("from GuineaPig")
58120
.getResultList()
59121
.thenCompose( list -> loop( list, s::remove ) )
60122
.thenCompose( v -> s.<Long>createQuery("select count(*) from GuineaPig")
61123
.getSingleResult()
62-
.thenAccept( count -> context.assertEquals( 0L, count) )
124+
.thenAccept( count -> {
125+
context.assertEquals( 0L, count);
126+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
127+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
128+
.matches( "delete from pig where id=.+ and version=.+" );
129+
sqlTracker.clear();
130+
} )
63131
)
64132
)
65133
);

hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/SqlStatementTracker.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
import org.hibernate.service.spi.ServiceRegistryImplementor;
2222

2323
/**
24-
* Track sql queries
24+
* Track sql queries.
2525
* <p>
2626
* Check {@link #registerService(StandardServiceRegistryBuilder)} to register an instance of this class.
27+
* It's not thread-safe.
2728
* </p>
2829
*/
2930
public class SqlStatementTracker extends SqlStatementLogger {

0 commit comments

Comments
 (0)