Skip to content

Commit 2eb7a57

Browse files
ammachadotomix26
authored andcommitted
Support for HSQLDB and Apache Derby
1 parent 228374c commit 2eb7a57

15 files changed

+719
-9
lines changed

README.md

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The primary goal of this project is to make it easier to write Spring-powered in
1010
* Spring `4.3.8` - `6.0.x`
1111
* Spring Boot `1.4.6` - `3.0.x`
1212
* Supports multiple different databases
13-
* [PostgreSQL](#postgresql), [MSSQL](#microsoft-sql-server), [MySQL](#mysql), [MariaDB](#mariadb), [H2](#h2)
13+
* [PostgreSQL](#postgresql), [MSSQL](#microsoft-sql-server), [MySQL](#mysql), [MariaDB](#mariadb), [H2](#h2), [HSQLDB](#hsqldb) and [Derby](#derby)
1414
* Supports multiple database providers
1515
* [Docker / Testcontainers](#using-docker-provider-default), [Zonky](#using-zonky-provider-previous-default), [OpenTable](#using-opentable-provider), [Yandex](#using-yandex-provider)
1616
* Supports various database migration tools
@@ -66,7 +66,7 @@ Add the following Maven dependency:
6666
<dependency>
6767
<groupId>io.zonky.test</groupId>
6868
<artifactId>embedded-database-spring-test</artifactId>
69-
<version>2.2.0</version>
69+
<version>2.3.0</version>
7070
<scope>test</scope>
7171
</dependency>
7272
```
@@ -348,6 +348,46 @@ Before you use H2 database, you have to add the following Maven dependency:
348348
**Note that the associated database provider supports database prefetching, but not template databases.
349349
So you may notice some performance degradation compared to other database providers in some cases.**
350350

351+
### HSQLDB
352+
353+
This provider may be convenient if you have an application that supports multiple databases
354+
and you want to reuse the tests using the `@AutoConfigureEmbeddedDatabase` annotation for all these databases, including the HSQLDB database.
355+
In this case, you can override the `zonky.test.database.provider` property externally and change the used database provider for each run without changing the code.
356+
You can find more information about externalized configuration here: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config
357+
358+
Before you use HSQLDB database, you have to add the following Maven dependency:
359+
360+
```xml
361+
<dependency>
362+
<groupId>org.hsqldb</groupId>
363+
<artifactId>hsqldb</artifactId>
364+
<version>2.7.1</version>
365+
</dependency>
366+
```
367+
368+
**Note that the associated database provider supports database prefetching, but not template databases.
369+
So you may notice some performance degradation compared to other database providers in some cases.**
370+
371+
### Derby
372+
373+
This provider may be convenient if you have an application that supports multiple databases
374+
and you want to reuse the tests using the `@AutoConfigureEmbeddedDatabase` annotation for all these databases, including the Apache Derby database.
375+
In this case, you can override the `zonky.test.database.provider` property externally and change the used database provider for each run without changing the code.
376+
You can find more information about externalized configuration here: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config
377+
378+
Before you use Apache Derby database, you have to add the following Maven dependency:
379+
380+
```xml
381+
<dependency>
382+
<groupId>org.apache.derby</groupId>
383+
<artifactId>derby</artifactId>
384+
<version>10.16.1.1</version>
385+
</dependency>
386+
```
387+
388+
**Note that the associated database provider supports database prefetching, but not template databases.
389+
So you may notice some performance degradation compared to other database providers in some cases.**
390+
351391
## Supported Migration Tools
352392

353393
Note that although any migration tool is supported,

build.gradle

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ ext {
7777
[name: '1.4.200', 'h2': '1.4.200'],
7878
[name: '2.0.206', 'h2': '2.0.206'],
7979
[name: '2.1.214', 'h2': '2.1.214']
80+
]],
81+
[name: 'hsqldb', versions: [
82+
[name: '2.3.6', 'hsqldb': '2.3.6'],
83+
[name: '2.4.1', 'hsqldb': '2.4.1'],
84+
[name: '2.5.1', 'hsqldb': '2.5.1'],
85+
[name: '2.5.2', 'hsqldb': '2.5.2'],
86+
[name: '2.7.1', 'hsqldb': '2.7.1'],
87+
]],
88+
[name: 'derby', versions: [
89+
[name: '10.13.1.1', 'derby': '10.13.1.1'],
90+
[name: '10.14.2.0', 'derby': '10.14.2.0'],
91+
[name: '10.15.1.3', 'derby': '10.15.1.3'],
92+
[name: '10.15.2.0', 'derby': '10.15.2.0'],
93+
[name: '10.16.1.1', 'derby': '10.16.1.1']
8094
]]
8195
]
8296
}
@@ -107,12 +121,12 @@ subprojects {
107121
}
108122

109123
task sourcesJar(type: Jar) {
110-
classifier = 'sources'
124+
archiveClassifier = 'sources'
111125
from sourceSets.main.allSource
112126
}
113127

114128
task javadocJar(type: Jar) {
115-
classifier = 'javadoc'
129+
archiveClassifier = 'javadoc'
116130
from javadoc
117131
}
118132

@@ -213,6 +227,8 @@ project(':embedded-database-spring-test') {
213227
compile 'mysql:mysql-connector-java:8.0.30', optional
214228
compile 'org.mariadb.jdbc:mariadb-java-client:3.1.0', optional
215229
compile 'com.h2database:h2:2.1.214', optional
230+
compile 'org.hsqldb:hsqldb:2.5.2', optional
231+
compile 'org.apache.derby:derbynet:10.14.2.0', optional
216232

217233
compile 'org.flywaydb:flyway-core:9.8.2', optional
218234
compile 'org.flywaydb.flyway-test-extensions:flyway-spring-test:7.0.0', optional
@@ -370,6 +386,26 @@ project(':embedded-database-spring-test') {
370386
}
371387
}
372388
}
389+
390+
if (version.hsqldb == null) { // optional dependencies are implicitly excluded
391+
exclude group: 'org.hsqldb', module: 'hsqldb'
392+
} else if (version.hsqldb != 'default') {
393+
eachDependency { details ->
394+
if (details.requested.group == 'org.hsqldb' && details.requested.name == 'hsqldb') {
395+
details.useVersion "${version.hsqldb}"
396+
}
397+
}
398+
}
399+
400+
if (version.derby == null) { // optional dependencies are implicitly excluded
401+
exclude group: 'org.apache.derby', module: 'derby'
402+
} else if (version.derby != 'default') {
403+
eachDependency { details ->
404+
if (details.requested.group == 'org.apache.derby') {
405+
details.useVersion "${version.derby}"
406+
}
407+
}
408+
}
373409
}
374410
}
375411
}
@@ -414,6 +450,8 @@ project(':embedded-database-spring-test') {
414450
excludeCategories 'io.zonky.test.category.MySQLTestSuite'
415451
excludeCategories 'io.zonky.test.category.MariaDBTestSuite'
416452
excludeCategories 'io.zonky.test.category.H2TestSuite'
453+
excludeCategories 'io.zonky.test.category.HSQLDBTestSuite'
454+
excludeCategories 'io.zonky.test.category.DerbyTestSuite'
417455
}
418456
}
419457

@@ -456,6 +494,10 @@ project(':embedded-database-spring-test') {
456494
includeCategories 'io.zonky.test.category.MariaDBTestSuite'
457495
} else if (suite.name == 'h2') {
458496
includeCategories 'io.zonky.test.category.H2TestSuite'
497+
} else if (suite.name == 'hsqldb') {
498+
includeCategories 'io.zonky.test.category.HSQLDBTestSuite'
499+
} else if (suite.name == 'derby') {
500+
includeCategories 'io.zonky.test.category.DerbyTestSuite'
459501
}
460502
}
461503
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/AutoConfigureEmbeddedDatabase.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
/**
6666
* The type of embedded database to be created when {@link #replace() replacing} the data source.
67-
* By default will attempt to detect the database type based on the classpath.
67+
* By default, will attempt to detect the database type based on the classpath.
6868
*
6969
* <p>The database type may also be configured via the {@code zonky.test.database.type} configuration property.
7070
*
@@ -155,8 +155,23 @@ enum DatabaseType {
155155
/**
156156
* H2 Database
157157
*/
158-
H2
158+
H2,
159159

160+
/**
161+
* HSQL Database
162+
*/
163+
HSQL,
164+
165+
/**
166+
* Apache Derby
167+
*/
168+
DERBY;
169+
170+
public static boolean canBeEmbedded(String databaseType) {
171+
return DatabaseType.H2.name().equalsIgnoreCase(databaseType) ||
172+
DatabaseType.HSQL.name().equalsIgnoreCase(databaseType) ||
173+
DatabaseType.DERBY.name().equalsIgnoreCase(databaseType);
174+
}
160175
}
161176

162177
/**
@@ -206,7 +221,7 @@ enum DatabaseProvider {
206221
enum Replace {
207222

208223
/**
209-
* Replace any DataSource bean (auto-configured or manually defined).
224+
* Replace any DataSource bean (autoconfigured or manually defined).
210225
*/
211226
ANY,
212227

embedded-database-spring-test/src/main/java/io/zonky/test/db/event/EventPublishingTestExecutionListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class EventPublishingTestExecutionListener extends AbstractTestExecutionL
1313
private static final Logger logger = LoggerFactory.getLogger(EventPublishingTestExecutionListener.class);
1414

1515
private static final boolean TEST_EXECUTION_METHODS_SUPPORTED = ClassUtils.getMethodIfAvailable(
16-
TestExecutionListener.class, "beforeTestExecution", null) != null;
16+
TestExecutionListener.class, "beforeTestExecution") != null;
1717

1818
@Override
1919
public void beforeTestMethod(TestContext testContext) {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.zonky.test.db.provider.derby;
18+
19+
import io.zonky.test.db.preparer.DatabasePreparer;
20+
import io.zonky.test.db.provider.DatabaseProvider;
21+
import io.zonky.test.db.provider.EmbeddedDatabase;
22+
import io.zonky.test.db.provider.ProviderException;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
26+
27+
import java.sql.DriverManager;
28+
import java.sql.SQLException;
29+
import java.util.Objects;
30+
import java.util.UUID;
31+
import java.util.concurrent.CompletableFuture;
32+
33+
public class DerbyDatabaseProvider implements DatabaseProvider {
34+
35+
private static final Logger logger = LoggerFactory.getLogger(DerbyDatabaseProvider.class);
36+
private static final String URL_TEMPLATE = "jdbc:derby:memory:%s";
37+
38+
@Override
39+
public EmbeddedDatabase createDatabase(DatabasePreparer preparer) throws ProviderException {
40+
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
41+
String databaseName = UUID.randomUUID().toString();
42+
43+
dataSource.setDriverClass(org.h2.Driver.class);
44+
dataSource.setUrl(String.format(URL_TEMPLATE + ";drop=true", databaseName));
45+
dataSource.setUsername("sa");
46+
dataSource.setPassword("");
47+
48+
DerbyEmbeddedDatabase database = new DerbyEmbeddedDatabase(dataSource, databaseName,
49+
() -> shutdownDatabase(databaseName));
50+
try {
51+
if (preparer != null) {
52+
preparer.prepare(database);
53+
}
54+
} catch (SQLException e) {
55+
throw new ProviderException("Unexpected error when creating a database", e);
56+
}
57+
return database;
58+
}
59+
60+
@Override
61+
public boolean equals(Object o) {
62+
if (this == o) return true;
63+
return o != null && getClass() == o.getClass();
64+
}
65+
66+
@Override
67+
public int hashCode() {
68+
return Objects.hash(DerbyDatabaseProvider.class);
69+
}
70+
71+
private static void shutdownDatabase(String dbName) {
72+
CompletableFuture.runAsync(() -> {
73+
try {
74+
DriverManager.getConnection(String.format(URL_TEMPLATE + ";shutdown=true", dbName));
75+
} catch (SQLException e) {
76+
// it seems that there is no error for database in use condition
77+
if (logger.isTraceEnabled()) {
78+
logger.warn("Unable to release '{}' database", dbName, e);
79+
} else {
80+
logger.warn("Unable to release '{}' database", dbName);
81+
}
82+
}
83+
});
84+
}
85+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.zonky.test.db.provider.derby;
18+
19+
import io.zonky.test.db.provider.support.AbstractEmbeddedDatabase;
20+
import org.apache.derby.drda.NetworkServerControl;
21+
22+
import javax.sql.DataSource;
23+
24+
public class DerbyEmbeddedDatabase extends AbstractEmbeddedDatabase {
25+
26+
private final DataSource dataSource;
27+
private final String dbName;
28+
29+
public DerbyEmbeddedDatabase(DataSource dataSource, String dbName, Runnable closeCallback) {
30+
super(closeCallback);
31+
this.dataSource = dataSource;
32+
this.dbName = dbName;
33+
}
34+
35+
@Override
36+
protected DataSource getDataSource() {
37+
return dataSource;
38+
}
39+
40+
@Override
41+
public String getJdbcUrl() {
42+
return String.format("jdbc:derby:mem:%s;USER=sa", dbName);
43+
}
44+
45+
public String getDatabaseName() {
46+
return dbName;
47+
}
48+
}

0 commit comments

Comments
 (0)