TSK-1685: added testcontainers extension

This commit is contained in:
Mustapha Zorgati 2021-09-15 10:13:31 +02:00
parent af47d1ad14
commit c742407288
9 changed files with 198 additions and 12 deletions

View File

@ -250,11 +250,11 @@ jobs:
- H2 - H2
include: include:
- module: taskana-core - module: taskana-core
database: POSTGRES_10 database: POSTGRES
- module: taskana-core - module: taskana-core
database: DB2_11_1 database: DB2
- module: taskana-rest-spring-example-boot - module: taskana-rest-spring-example-boot
database: DB2_11_1 database: DB2
steps: steps:
- name: Git checkout - name: Git checkout
uses: actions/checkout@v2.3.4 uses: actions/checkout@v2.3.4
@ -281,6 +281,8 @@ jobs:
run: ./mvnw -B validate -pl :taskana-rest-spring run: ./mvnw -B validate -pl :taskana-rest-spring
- name: Test - name: Test
run: ./mvnw -B verify -pl :${{matrix.module}} -Dcheckstyle.skip run: ./mvnw -B verify -pl :${{matrix.module}} -Dcheckstyle.skip
env:
db.type: ${{ matrix.database }}
- name: Upload JaCoCo Report - name: Upload JaCoCo Report
if: matrix.database == 'H2' if: matrix.database == 'H2'
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2

View File

@ -106,6 +106,28 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId> <artifactId>spring-webmvc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<version>${version.testcontainers}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${version.testcontainers}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- TEST DEPENDENCIES --> <!-- TEST DEPENDENCIES -->
<dependency> <dependency>

View File

@ -0,0 +1,8 @@
package org.junit.rules;
// Testcontainers currently requires junit4 as a runtime dependency.
// Because we use junit5 we have to use this workaround to "simulate" the classes testcontainers
// requires in the classpath. They are not used unless a junit4 runtime is used.
// See: https://github.com/testcontainers/testcontainers-java/issues/970#issuecomment-625044008
@SuppressWarnings("unused")
public interface TestRule {}

View File

@ -0,0 +1,8 @@
package org.junit.runners.model;
// Testcontainers currently requires junit4 as a runtime dependency.
// Because we use junit5 we have to use this workaround to "simulate" the classes testcontainers
// requires in the classpath. They are not used unless a junit4 runtime is used.
// See: https://github.com/testcontainers/testcontainers-java/issues/970#issuecomment-625044008
@SuppressWarnings("unused")
public interface Statement {}

View File

@ -0,0 +1,136 @@
package pro.taskana.common.test.config;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.time.Duration;
import java.util.Optional;
import java.util.UUID;
import javax.sql.DataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.testcontainers.containers.Db2Container;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.utility.DockerImageName;
import pro.taskana.common.internal.configuration.DB;
public class TestContainerExtension implements AfterAllCallback {
private final DataSource dataSource;
private final String schemaName;
private final JdbcDatabaseContainer<?> container;
public TestContainerExtension() {
DB db = getTestDatabase();
Optional<JdbcDatabaseContainer<?>> container = createDockerContainer(db);
if (container.isPresent()) {
this.container = container.get();
this.container.start();
dataSource = createDataSource(this.container);
} else {
dataSource = createDataSourceForH2();
this.container = null;
}
schemaName = determineSchemaName(db);
}
@Override
public void afterAll(ExtensionContext context) {
if (container != null) {
container.stop();
}
}
public DataSource getDataSource() {
return dataSource;
}
public String getSchemaName() {
return schemaName;
}
private DB getTestDatabase() {
String property = System.getenv("db.type");
DB db;
try {
db = DB.valueOf(property);
} catch (Exception ex) {
db = DB.H2;
}
return db;
}
private static String determineSchemaName(DB db) {
return db == DB.POSTGRES ? "taskana" : "TASKANA";
}
private static DataSource createDataSource(JdbcDatabaseContainer<?> container) {
PooledDataSource ds =
new PooledDataSource(
Thread.currentThread().getContextClassLoader(),
container.getDriverClassName(),
container.getJdbcUrl(),
container.getUsername(),
container.getPassword());
ds.setPoolTimeToWait(50);
ds.forceCloseAll(); // otherwise, the MyBatis pool is not initialized correctly
return ds;
}
private static Optional<JdbcDatabaseContainer<?>> createDockerContainer(DB db) {
switch (db) {
case DB2:
return Optional.of(
new Db2Container(
DockerImageName.parse("taskana/db2:11.1")
.asCompatibleSubstituteFor("ibmcom/db2"))
.waitingFor(
new LogMessageWaitStrategy()
.withRegEx(".*DB2START processing was successful.*")
.withStartupTimeout(Duration.of(60, SECONDS)))
.withUsername("db2inst1")
.withPassword("db2inst1-pwd")
.withDatabaseName("TSKDB"));
case POSTGRES:
return Optional.of(
new PostgreSQLContainer<>(DockerImageName.parse("postgres:10"))
.withUsername("postgres")
.withPassword("postgres")
.withDatabaseName("postgres")
.withCommand(
"/bin/sh",
"-c",
"localedef -i de_DE -c -f UTF-8 -A /usr/share/locale/locale.alias de_DE.UTF-8 "
+ "&& export LANG=de_DE.UTF-8 "
+ "&& ./docker-entrypoint.sh postgres -c fsync=off")
.waitingFor(
new LogMessageWaitStrategy()
.withRegEx(".*Datenbanksystem ist bereit, um Verbindungen anzunehmen.*\\s")
.withTimes(2)
.withStartupTimeout(Duration.of(60, SECONDS))));
default:
return Optional.empty();
}
}
private static DataSource createDataSourceForH2() {
PooledDataSource ds =
new PooledDataSource(
Thread.currentThread().getContextClassLoader(),
"org.h2.Driver",
"jdbc:h2:mem:"
+ UUID.randomUUID()
+ ";LOCK_MODE=0;"
+ "INIT=CREATE SCHEMA IF NOT EXISTS TASKANA\\;"
+ "SET COLLATION DEFAULT_de_DE ",
"sa",
"sa");
ds.setPoolTimeToWait(50);
ds.forceCloseAll(); // otherwise, the MyBatis pool is not initialized correctly
return ds;
}
}

View File

@ -19,8 +19,8 @@ export TOP_PID=$$
#H #H
#H database: #H database:
#H - H2 #H - H2
#H - DB2_11_1 #H - DB2 | DB2_11_1
#H - POSTGRES_10 #H - POSTGRES | POSTGRES_10
# Arguments: # Arguments:
# $1: exit code # $1: exit code
function helpAndExit() { function helpAndExit() {
@ -34,10 +34,10 @@ function helpAndExit() {
function mapDBToDockerComposeServiceName() { function mapDBToDockerComposeServiceName() {
[[ -z "$1" || "$1" == "H2" ]] && return [[ -z "$1" || "$1" == "H2" ]] && return
case "$1" in case "$1" in
DB2_11_1) DB2|DB2_11_1)
echo "taskana-db2_11-1" echo "taskana-db2_11-1"
;; ;;
POSTGRES_10) POSTGRES|POSTGRES_10)
echo "taskana-postgres_10" echo "taskana-postgres_10"
;; ;;
*) *)
@ -54,7 +54,7 @@ function main() {
H2) H2)
[[ -f "$propFile" ]] && rm "$propFile" [[ -f "$propFile" ]] && rm "$propFile"
;; ;;
DB2_11_1) DB2|DB2_11_1)
docker-compose -f $scriptDir/docker-compose.yml up -d "$(mapDBToDockerComposeServiceName "$1")" docker-compose -f $scriptDir/docker-compose.yml up -d "$(mapDBToDockerComposeServiceName "$1")"
echo 'jdbcDriver=com.ibm.db2.jcc.DB2Driver' > $propFile echo 'jdbcDriver=com.ibm.db2.jcc.DB2Driver' > $propFile
@ -63,7 +63,7 @@ function main() {
echo 'dbPassword=db2inst1-pwd' >> $propFile echo 'dbPassword=db2inst1-pwd' >> $propFile
echo 'schemaName=TASKANA' >> $propFile echo 'schemaName=TASKANA' >> $propFile
;; ;;
POSTGRES_10) POSTGRES|POSTGRES_10)
docker-compose -f $scriptDir/docker-compose.yml up -d "$(mapDBToDockerComposeServiceName "$1")" docker-compose -f $scriptDir/docker-compose.yml up -d "$(mapDBToDockerComposeServiceName "$1")"
echo 'jdbcDriver=org.postgresql.Driver' > $propFile echo 'jdbcDriver=org.postgresql.Driver' > $propFile

View File

@ -1,19 +1,22 @@
package acceptance; package acceptance;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.api.extension.ParameterResolver;
import pro.taskana.common.test.config.DataSourceGenerator; import pro.taskana.common.test.config.TestContainerExtension;
public class TaskanaIntegrationTestExtension implements ParameterResolver { public class TaskanaIntegrationTestExtension implements ParameterResolver, AfterAllCallback {
private final TaskanaDependencyInjectionExtension dependencyInjectionExtension; private final TaskanaDependencyInjectionExtension dependencyInjectionExtension;
private final TestContainerExtension testContainerExtension;
public TaskanaIntegrationTestExtension() throws Exception { public TaskanaIntegrationTestExtension() throws Exception {
testContainerExtension = new TestContainerExtension();
dependencyInjectionExtension = dependencyInjectionExtension =
new TaskanaDependencyInjectionExtension(DataSourceGenerator.getDataSource()); new TaskanaDependencyInjectionExtension(testContainerExtension.getDataSource());
} }
@Override @Override
@ -29,4 +32,9 @@ public class TaskanaIntegrationTestExtension implements ParameterResolver {
throws ParameterResolutionException { throws ParameterResolutionException {
return dependencyInjectionExtension.resolveParameter(parameterContext, extensionContext); return dependencyInjectionExtension.resolveParameter(parameterContext, extensionContext);
} }
@Override
public void afterAll(ExtensionContext context) {
testContainerExtension.afterAll(context);
}
} }

View File

@ -0,0 +1 @@
taskana/db2:11.1

View File

@ -88,6 +88,7 @@
<version.jacoco>0.8.7</version.jacoco> <version.jacoco>0.8.7</version.jacoco>
<version.slf4j-test>1.2.0</version.slf4j-test> <version.slf4j-test>1.2.0</version.slf4j-test>
<version.auto-restdocs>2.0.11</version.auto-restdocs> <version.auto-restdocs>2.0.11</version.auto-restdocs>
<version.testcontainers>1.16.0</version.testcontainers>
<!-- AspectJ dependencies --> <!-- AspectJ dependencies -->
<version.aspectj-maven-plugin>1.14.0</version.aspectj-maven-plugin> <version.aspectj-maven-plugin>1.14.0</version.aspectj-maven-plugin>