Skip to content

Commit 4d8c900

Browse files
committed
Create a separate JBang template for each db
1 parent 27cec21 commit 4d8c900

6 files changed

+1051
-0
lines changed

jbang-catalog.json

+32
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,37 @@
99
"script-ref": "tooling/jbang/ReactiveTest.java",
1010
"description": "A Hibernate Reactive JUnit test using Docker, Testcontainers and Vert.x Unit"
1111
}
12+
},
13+
"templates": {
14+
"pg-reproducer": {
15+
"file-refs": {
16+
"{basename}.java": "tooling/jbang/PostgreSQLReactiveTest.java.qute"
17+
},
18+
"description": "Template for a test with PostgreSQL using Junit 4, Vert.x Unit and Testcontainers"
19+
},
20+
"mysql-reproducer": {
21+
"file-refs": {
22+
"{basename}.java": "tooling/jbang/MySQLReactiveTest.java.qute"
23+
},
24+
"description": "Template for a test with MySQL using Junit 4, Vert.x Unit and Testcontainers"
25+
},
26+
"mariadb-reproducer": {
27+
"file-refs": {
28+
"{basename}.java": "tooling/jbang/MariaDBReactiveTest.java.qute"
29+
},
30+
"description": "Template for a test with MariaDB using Junit 4, Vert.x Unit and Testcontainers"
31+
},
32+
"db2-reproducer": {
33+
"file-refs": {
34+
"{basename}.java": "tooling/jbang/Db2ReactiveTest.java.qute"
35+
},
36+
"description": "Template for a test with Db2 using Junit 4, Vert.x Unit and Testcontainers"
37+
},
38+
"cockroachdb-reproducer": {
39+
"file-refs": {
40+
"{basename}.java": "tooling/jbang/CockroachDBReactiveTest.java.qute"
41+
},
42+
"description": "Template for a test with CockroachDB using Junit 4, Vert.x Unit and Testcontainers"
43+
}
1244
}
1345
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
/* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* SPDX-License-Identifier: LGPL-2.1-or-later
5+
* Copyright: Red Hat Inc. and Hibernate Authors
6+
*/
7+
8+
//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.1.0}
9+
//DEPS io.vertx:vertx-unit:$\{vertx.version:4.1.0}
10+
//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:1.0.0.CR6}
11+
//DEPS org.assertj:assertj-core:3.19.0
12+
//DEPS junit:junit:4.13.2
13+
//DEPS org.testcontainers:cockroachdb:1.15.3
14+
//DEPS org.slf4j:slf4j-simple:1.7.30
15+
16+
//// Testcontainer needs the JDBC drivers to start the container
17+
//// Hibernate Reactive doesn't need it
18+
//DEPS org.postgresql:postgresql:42.2.16
19+
20+
import java.io.IOException;
21+
import javax.persistence.Entity;
22+
import javax.persistence.Id;
23+
24+
import org.hibernate.boot.registry.StandardServiceRegistry;
25+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
26+
import org.hibernate.cfg.Configuration;
27+
import org.hibernate.reactive.mutiny.Mutiny;
28+
import org.hibernate.reactive.provider.ReactiveServiceRegistryBuilder;
29+
import org.hibernate.reactive.provider.Settings;
30+
31+
import org.junit.After;
32+
import org.junit.Before;
33+
import org.junit.BeforeClass;
34+
import org.junit.ClassRule;
35+
import org.junit.Test;
36+
import org.junit.runner.JUnitCore;
37+
import org.junit.runner.Result;
38+
import org.junit.runner.RunWith;
39+
import org.junit.runner.notification.Failure;
40+
41+
import io.vertx.ext.unit.Async;
42+
import io.vertx.ext.unit.TestContext;
43+
import io.vertx.ext.unit.junit.VertxUnitRunner;
44+
import org.testcontainers.containers.CockroachContainer;
45+
46+
import static org.assertj.core.api.Assertions.assertThat;
47+
48+
//DESCRIPTION An example of a JUnit test class for Hibernate Reactive using
49+
//DESCRIPTION [Vert.x Unit](https://vertx.io/docs/vertx-unit/java),
50+
//DESCRIPTION [Testcontainers](https://www.testcontainers.org)
51+
//DESCRIPTION and [CockroachDB](https://www.cockroachlabs.com/)
52+
//DESCRIPTION that you can run using [JBang](JBang).
53+
//DESCRIPTION
54+
//DESCRIPTION Before running the tests, Testcontainers will start the selected
55+
//DESCRIPTION Docker image with the required database created.
56+
//DESCRIPTION
57+
//DESCRIPTION Usage example:
58+
//DESCRIPTION 1. Use as jbang template `jbang init -t cockroachdb-reproducer@hibernate/hibernate-reactive mytest.java`
59+
//DESCRIPTION 2. Run the test with JBang: `jbang mytest.java`
60+
//DESCRIPTION 3. (Optional) Edit the file (with IntelliJ IDEA for example):
61+
//DESCRIPTION jbang edit --live --open=idea mytest.java
62+
@RunWith(VertxUnitRunner.class)
63+
public class {baseName} {
64+
65+
@ClassRule
66+
public final static CockroachContainer database = new CockroachContainer( "cockroachdb/cockroach:v21.1.1" );
67+
68+
private Mutiny.SessionFactory sessionFactory;
69+
70+
@BeforeClass
71+
public static void startContainer() throws IOException, InterruptedException {
72+
database.start();
73+
// Temporary tables support is an experimental feature for CockroachDB and needs to be enabled.
74+
// Hibernate Reactive sometimes needs it when updating entities in a hierarchy.
75+
database.execInContainer(
76+
"sh",
77+
"-c",
78+
"./cockroach sql --insecure -e \"SET CLUSTER SETTING sql.defaults.experimental_temporary_tables.enabled = 'true';\""
79+
);
80+
}
81+
82+
/**
83+
* The \{@link Configuration} for the \{@link Mutiny.SessionFactory}.
84+
*/
85+
private Configuration createConfiguration() {
86+
Configuration configuration = new Configuration();
87+
88+
// JDBC url
89+
configuration.setProperty( Settings.URL, database.getJdbcUrl() );
90+
91+
// Credentials
92+
configuration.setProperty( Settings.USER, database.getUsername() );
93+
configuration.setProperty( Settings.PASS, database.getPassword() );
94+
95+
// Schema generation. Supported values are create, drop, create-drop, drop-create, none
96+
configuration.setProperty( Settings.HBM2DDL_AUTO, "create" );
97+
98+
// Register new entity classes here
99+
configuration.addAnnotatedClass( MyEntity.class );
100+
101+
// (Optional) Log the SQL queries
102+
configuration.setProperty( Settings.SHOW_SQL, "true" );
103+
configuration.setProperty( Settings.HIGHLIGHT_SQL, "true" );
104+
configuration.setProperty( Settings.FORMAT_SQL, "true" );
105+
return configuration;
106+
}
107+
108+
/*
109+
* Create a new factory and a new schema before each test (see
110+
* property `hibernate.hbm2ddl.auto`).
111+
* This way each test will start with a clean database.
112+
*
113+
* The drawback is that, in a real case scenario with multiple tests,
114+
* it can slow down the whole test suite considerably. If that happens,
115+
* it's possible to make the session factory static and, if necessary,
116+
* delete the content of the tables manually (without dropping them).
117+
*/
118+
@Before
119+
public void createSessionFactory() {
120+
Configuration configuration = createConfiguration();
121+
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
122+
.applySettings( configuration.getProperties() );
123+
StandardServiceRegistry registry = builder.build();
124+
125+
sessionFactory = configuration.buildSessionFactory( registry )
126+
.unwrap( Mutiny.SessionFactory.class );
127+
}
128+
129+
@Test
130+
public void testInsertAndSelect(TestContext context) {
131+
// the test will wait until async.complete or context.fail are called
132+
Async async = context.async();
133+
134+
MyEntity entity = new MyEntity( "first entity", 1 );
135+
sessionFactory
136+
// insert the entity in the database
137+
.withTransaction( (session, tx) -> session.persist( entity ) )
138+
.chain( () -> sessionFactory
139+
.withSession( session -> session
140+
// look for the entity by id
141+
.find( MyEntity.class, entity.getId() )
142+
// assert that the returned entity is the right one
143+
.invoke( foundEntity -> assertThat( foundEntity.getName() ).isEqualTo( entity.getName() ) ) ) )
144+
.subscribe()
145+
.with( res -> async.complete(), context::fail );
146+
}
147+
148+
@After
149+
public void closeFactory() {
150+
if ( sessionFactory != null ) {
151+
sessionFactory.close();
152+
}
153+
}
154+
155+
/**
156+
* Example of a class representing an entity.
157+
* <p>
158+
* If you create new entities, be sure to add them in .
159+
* For example:
160+
* <pre>
161+
* configuration.addAnnotatedClass( MyOtherEntity.class );
162+
* </pre>
163+
*/
164+
@Entity(name = "MyEntity")
165+
public static class MyEntity {
166+
@Id
167+
public Integer id;
168+
169+
public String name;
170+
171+
public MyEntity() {
172+
}
173+
174+
public MyEntity(String name, Integer id) {
175+
this.name = name;
176+
this.id = id;
177+
}
178+
179+
public Integer getId() {
180+
return id;
181+
}
182+
183+
public String getName() {
184+
return name;
185+
}
186+
187+
@Override
188+
public String toString() {
189+
return "MyEntity"
190+
+ "\n\t id = " + id
191+
+ "\n\t name = " + name;
192+
}
193+
}
194+
195+
// This main class is only for JBang so that it can run the tests with `jbang {baseName}.java`
196+
public static void main(String[] args) {
197+
System.out.println( "Starting the test suite with CockroachDB" );
198+
199+
Result result = JUnitCore.runClasses( {baseName}.class );
200+
201+
for ( Failure failure : result.getFailures() ) {
202+
System.out.println();
203+
System.err.println( "Test " + failure.getTestHeader() + " FAILED!" );
204+
System.err.println( "\t" + failure.getTrace() );
205+
}
206+
207+
System.out.println();
208+
System.out.print("Tests result summary: ");
209+
System.out.println( result.wasSuccessful() ? "SUCCESS" : "FAILURE" );
210+
}
211+
}

0 commit comments

Comments
 (0)