Skip to content

Commit d4f56f9

Browse files
dreab8DavideD
authored andcommitted
[#2055] Add test for temporary table strategies
The test is for temporary tables created for storing ids
1 parent 64c220c commit d4f56f9

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.schema;
7+
8+
import java.util.Collection;
9+
import java.util.Set;
10+
import java.util.concurrent.CompletionStage;
11+
import java.util.stream.Stream;
12+
13+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
14+
import org.hibernate.cfg.Configuration;
15+
import org.hibernate.dialect.Dialect;
16+
import org.hibernate.dialect.temptable.TemporaryTable;
17+
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableStrategy;
18+
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy;
19+
import org.hibernate.reactive.BaseReactiveTest;
20+
import org.hibernate.reactive.annotations.EnabledFor;
21+
import org.hibernate.reactive.provider.Settings;
22+
import org.hibernate.reactive.testing.SqlStatementTracker;
23+
import org.hibernate.reactive.util.impl.CompletionStages;
24+
25+
import org.junit.jupiter.api.AfterEach;
26+
import org.junit.jupiter.params.ParameterizedTest;
27+
import org.junit.jupiter.params.provider.Arguments;
28+
import org.junit.jupiter.params.provider.MethodSource;
29+
30+
import io.vertx.junit5.Timeout;
31+
import io.vertx.junit5.VertxTestContext;
32+
import jakarta.persistence.Entity;
33+
import jakarta.persistence.GeneratedValue;
34+
import jakarta.persistence.Id;
35+
import jakarta.persistence.Inheritance;
36+
import jakarta.persistence.InheritanceType;
37+
38+
import static java.util.concurrent.TimeUnit.MINUTES;
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.COCKROACHDB;
41+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.ORACLE;
42+
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
43+
import static org.junit.jupiter.params.provider.Arguments.arguments;
44+
45+
/**
46+
* Test enabling and disabling of strategies for the creation of temporary tables to store ids.
47+
*
48+
* @see GlobalTemporaryTableStrategy
49+
* @see PersistentTableStrategy
50+
*/
51+
@Timeout(value = 10, timeUnit = MINUTES)
52+
public class TemporaryIdTableStrategyTest extends BaseReactiveTest {
53+
private static SqlStatementTracker sqlStatementTracker;
54+
55+
final static Dialect[] dialect = new Dialect[1];
56+
57+
@Override
58+
protected Collection<Class<?>> annotatedEntities() {
59+
return Set.of( Engineer.class, Doctor.class, Person.class );
60+
}
61+
62+
public static Stream<Arguments> settings() {
63+
return Stream.of(
64+
arguments( true, 1, true, 1 ),
65+
arguments( true, 1, false, 0 ),
66+
// I'm assuming Hibernate won't drop the id tables if they haven't been created
67+
arguments( false, 0, true, 0 ),
68+
arguments( false, 0, false, 0 )
69+
);
70+
}
71+
72+
@Override
73+
protected Configuration constructConfiguration() {
74+
Configuration configuration = super.constructConfiguration();
75+
configuration.setProperty( Settings.HBM2DDL_AUTO, "create" );
76+
// Collect all the logs, we are going to filter them later
77+
sqlStatementTracker = new SqlStatementTracker( s -> true, configuration.getProperties() );
78+
return configuration;
79+
}
80+
81+
@Override
82+
public CompletionStage<Void> deleteEntities(Class<?>... entities) {
83+
// Deleting entities is not necessary for this test
84+
return voidFuture();
85+
}
86+
87+
@Override
88+
public void before(VertxTestContext context) {
89+
// We need to start and close our own session factories for the test
90+
}
91+
92+
@AfterEach
93+
@Override
94+
public void after(VertxTestContext context) {
95+
sqlStatementTracker.clear();
96+
super.after( context );
97+
}
98+
99+
@Override
100+
protected void addServices(StandardServiceRegistryBuilder builder) {
101+
if ( sqlStatementTracker != null ) {
102+
sqlStatementTracker.registerService( builder );
103+
}
104+
}
105+
106+
@ParameterizedTest(name = "Global Temporary tables - create: {0}, drop: {2}")
107+
@MethodSource("settings")
108+
@EnabledFor(value = ORACLE, reason = "It uses GlobalTemporaryTableStrategy by default")
109+
public void testGlobalTemporaryTablesStrategy(
110+
boolean enableCreateIdTables,
111+
// Expected number of temporary tables created
112+
int expectedTempTablesCreated,
113+
boolean enableDropIdTables,
114+
// Expected number of temporary tables dropped
115+
int expectedTempTablesDropped,
116+
VertxTestContext context) {
117+
Configuration configuration = constructConfiguration();
118+
configuration.setProperty( GlobalTemporaryTableStrategy.CREATE_ID_TABLES, enableCreateIdTables );
119+
configuration.setProperty( GlobalTemporaryTableStrategy.DROP_ID_TABLES, enableDropIdTables );
120+
121+
testTemporaryIdTablesCreationAndDropping( configuration, expectedTempTablesCreated, expectedTempTablesDropped, context );
122+
}
123+
124+
@ParameterizedTest(name = "Persistent tables - create: {0}, drop: {2}")
125+
@MethodSource("settings")
126+
@EnabledFor(value = COCKROACHDB, reason = "It uses PersistentTemporaryTableStrategy by default")
127+
public void testPersistentTemporaryTablesStrategy(
128+
boolean enableCreateIdTables,
129+
// Expected number of temporary tables created
130+
int expectedTempTablesCreated,
131+
boolean enableDropIdTables,
132+
// Expected number of temporary tables dropped
133+
int expectedTempTablesDropped,
134+
VertxTestContext context) {
135+
136+
Configuration configuration = constructConfiguration();
137+
configuration.setProperty( PersistentTableStrategy.CREATE_ID_TABLES, enableCreateIdTables );
138+
configuration.setProperty( PersistentTableStrategy.DROP_ID_TABLES, enableDropIdTables );
139+
140+
testTemporaryIdTablesCreationAndDropping( configuration, expectedTempTablesCreated, expectedTempTablesDropped, context );
141+
}
142+
143+
private void testTemporaryIdTablesCreationAndDropping(
144+
Configuration configure,
145+
int expectedTempTablesCreated,
146+
int expectedTempTablesDropped,
147+
VertxTestContext context) {
148+
test( context, setupSessionFactory( configure )
149+
.thenAccept( v -> {
150+
dialect[0] = getDialect();
151+
assertThat( commandsCount( dialect[0].getTemporaryTableCreateCommand() ) )
152+
.as( "Unexpected number of temporary tables for ids CREATED" )
153+
.isEqualTo( expectedTempTablesCreated );
154+
sqlStatementTracker.clear();
155+
} )
156+
// to ensure the factory is always closed even in case of exceptions
157+
.handle( CompletionStages::handle )
158+
.thenCompose( this::closeFactory )
159+
.thenAccept( v -> assertThat( commandsCount( dialect[0].getTemporaryTableDropCommand() ) )
160+
.as( "Unexpected number of temporary tables for ids DROPPED" )
161+
.isEqualTo( expectedTempTablesDropped ) )
162+
);
163+
}
164+
165+
// Always try to close the factory without losing the original error (if there was one)
166+
private CompletionStage<Void> closeFactory(CompletionStages.CompletionStageHandler<Void, Throwable> handler) {
167+
return factoryManager.stop()
168+
.handle( CompletionStages::handle )
169+
.thenCompose( factoryHandler -> handler
170+
.getResultAsCompletionStage()
171+
// When there's already an exception, we don't care about errors closing the factory
172+
.thenCompose( factoryHandler::getResultAsCompletionStage ) );
173+
}
174+
175+
private static long commandsCount(String temporaryTableCommand) {
176+
return sqlStatementTracker.getLoggedQueries().stream()
177+
.filter( q -> q.startsWith( temporaryTableCommand ) && q.contains( TemporaryTable.ID_TABLE_PREFIX ) )
178+
.count();
179+
}
180+
181+
@Entity(name = "Person")
182+
@Inheritance(strategy = InheritanceType.JOINED)
183+
public static class Person {
184+
185+
@Id
186+
@GeneratedValue
187+
private Long id;
188+
189+
private String name;
190+
191+
private boolean employed;
192+
193+
public Long getId() {
194+
return id;
195+
}
196+
197+
public void setId(Long id) {
198+
this.id = id;
199+
}
200+
201+
public String getName() {
202+
return name;
203+
}
204+
205+
public void setName(String name) {
206+
this.name = name;
207+
}
208+
209+
public boolean isEmployed() {
210+
return employed;
211+
}
212+
213+
public void setEmployed(boolean employed) {
214+
this.employed = employed;
215+
}
216+
}
217+
218+
@Entity(name = "Doctor")
219+
public static class Doctor extends Person {
220+
}
221+
222+
@Entity(name = "Engineer")
223+
public static class Engineer extends Person {
224+
225+
private boolean fellow;
226+
227+
public boolean isFellow() {
228+
return fellow;
229+
}
230+
231+
public void setFellow(boolean fellow) {
232+
this.fellow = fellow;
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)