Supply databases with Testcontainers. (#31321)

Signed-off-by: Miquel Simon <msimonma@redhat.com>
This commit is contained in:
Miquel Simon 2024-07-17 14:58:04 +02:00 committed by GitHub
parent e5848bdcf9
commit def6ea3620
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 170 additions and 15 deletions

View file

@ -48,6 +48,11 @@
<groupId>org.jboss.logmanager</groupId> <groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager</artifactId> <artifactId>jboss-logmanager</artifactId>
</dependency> </dependency>
<!-- JDBC Drivers -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -0,0 +1 @@
mcr.microsoft.com/mssql/server:latest

View file

@ -66,6 +66,25 @@
<version>${selenium.version}</version> <version>${selenium.version}</version>
<type>pom</type> <type>pom</type>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mariadb</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mssqlserver</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -0,0 +1,5 @@
package org.junit.rules;
@SuppressWarnings("unused")
public interface TestRule {
}

View file

@ -0,0 +1,5 @@
package org.junit.runners.model;
@SuppressWarnings("unused")
public class Statement {
}

View file

@ -9,6 +9,9 @@ import org.keycloak.test.framework.injection.Supplier;
public abstract class AbstractDatabaseSupplier implements Supplier<TestDatabase, KeycloakTestDatabase> { public abstract class AbstractDatabaseSupplier implements Supplier<TestDatabase, KeycloakTestDatabase> {
protected static final String DEFAULT_DB_USERNAME = "keycloak";
protected static final String DEFAULT_DB_PASSWORD = "Password1!";
@Override @Override
public Class<KeycloakTestDatabase> getAnnotationClass() { public Class<KeycloakTestDatabase> getAnnotationClass() {
return KeycloakTestDatabase.class; return KeycloakTestDatabase.class;

View file

@ -7,7 +7,7 @@ public class DatabaseConfig {
private String vendor; private String vendor;
private String containerImage; private String containerImage;
private String urlHost; private String url;
private String username; private String username;
private String password; private String password;
@ -29,12 +29,12 @@ public class DatabaseConfig {
return this; return this;
} }
public String getUrlHost() { public String getUrl() {
return urlHost; return url;
} }
public DatabaseConfig urlHost(String urlHost) { public DatabaseConfig url(String url) {
this.urlHost = urlHost; this.url = url;
return this; return this;
} }
@ -61,8 +61,8 @@ public class DatabaseConfig {
if (vendor != null) { if (vendor != null) {
config.put("db", vendor); config.put("db", vendor);
} }
if (urlHost != null) { if (url != null) {
config.put("db-url-host", urlHost); config.put("db-url", url);
} }
if (username != null) { if (username != null) {
config.put("db-username", username); config.put("db-username", username);

View file

@ -0,0 +1,18 @@
package org.keycloak.test.framework.database;
public class MSSQLServerDatabaseSupplier extends AbstractDatabaseSupplier {
public static final String VENDOR = "mssql";
@Override
TestDatabase getTestDatabase() {
DatabaseConfig databaseConfig = new DatabaseConfig()
.vendor(VENDOR)
.containerImage("mcr.microsoft.com/mssql/server:latest");
return new TestDatabase(databaseConfig);
}
@Override
public String getAlias() {
return VENDOR;
}
}

View file

@ -0,0 +1,20 @@
package org.keycloak.test.framework.database;
public class MariaDBDatabaseSupplier extends AbstractDatabaseSupplier {
public static final String VENDOR = "mariadb";
@Override
TestDatabase getTestDatabase() {
DatabaseConfig databaseConfig = new DatabaseConfig()
.vendor(VENDOR)
.username(DEFAULT_DB_USERNAME)
.password(DEFAULT_DB_PASSWORD)
.containerImage("mariadb:latest");
return new TestDatabase(databaseConfig);
}
@Override
public String getAlias() {
return VENDOR;
}
}

View file

@ -0,0 +1,21 @@
package org.keycloak.test.framework.database;
public class MySQLDatabaseSupplier extends AbstractDatabaseSupplier {
public static final String VENDOR = "mysql";
@Override
TestDatabase getTestDatabase() {
DatabaseConfig databaseConfig = new DatabaseConfig()
.vendor(VENDOR)
.username(DEFAULT_DB_USERNAME)
.password(DEFAULT_DB_PASSWORD)
.containerImage("mysql:latest");
return new TestDatabase(databaseConfig);
}
@Override
public String getAlias() {
return VENDOR;
}
}

View file

@ -8,9 +8,9 @@ public class PostgresDatabaseSupplier extends AbstractDatabaseSupplier {
TestDatabase getTestDatabase() { TestDatabase getTestDatabase() {
DatabaseConfig databaseConfig = new DatabaseConfig() DatabaseConfig databaseConfig = new DatabaseConfig()
.vendor(VENDOR) .vendor(VENDOR)
.username("keycloak") .username(DEFAULT_DB_USERNAME)
.password("keycloak") .password(DEFAULT_DB_PASSWORD)
.containerImage("the-postgres-container:the-version"); .containerImage("postgres:latest");
return new TestDatabase(databaseConfig); return new TestDatabase(databaseConfig);
} }

View file

@ -1,10 +1,21 @@
package org.keycloak.test.framework.database; package org.keycloak.test.framework.database;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
import java.util.Map; import java.util.Map;
public class TestDatabase { public class TestDatabase {
private DatabaseConfig databaseConfig; private final DatabaseConfig databaseConfig;
private GenericContainer<?> container;
public TestDatabase(DatabaseConfig databaseConfig) { public TestDatabase(DatabaseConfig databaseConfig) {
this.databaseConfig = databaseConfig; this.databaseConfig = databaseConfig;
@ -12,14 +23,21 @@ public class TestDatabase {
public void start() { public void start() {
if (databaseConfig.getContainerImage() != null) { if (databaseConfig.getContainerImage() != null) {
// TODO Start container container = createContainer();
container.withStartupTimeout(Duration.ofMinutes(5)).start();
databaseConfig.url(getJdbcUrl());
if (container instanceof MSSQLServerContainer) {
databaseConfig.username(((JdbcDatabaseContainer<?>) container).getUsername());
databaseConfig.password(((JdbcDatabaseContainer<?>) container).getPassword());
}
} }
} }
public void stop() { public void stop() {
if (databaseConfig.getContainerImage() != null) { if (databaseConfig.getContainerImage() != null) {
// TODO Stop container container.stop();
} else if (databaseConfig.getVendor().equals("dev-mem")) { container = null;
} else if ("dev-mem".equals(databaseConfig.getVendor())) {
// TODO Stop in-mem H2 database // TODO Stop in-mem H2 database
} }
} }
@ -28,4 +46,41 @@ public class TestDatabase {
return databaseConfig.toConfig(); return databaseConfig.toConfig();
} }
public String getJdbcUrl() {
return ((JdbcDatabaseContainer<?>)container).getJdbcUrl();
}
private JdbcDatabaseContainer<?> configureJdbcContainer(JdbcDatabaseContainer<?> jdbcDatabaseContainer) {
if (jdbcDatabaseContainer instanceof MSSQLServerContainer) {
return jdbcDatabaseContainer;
}
return jdbcDatabaseContainer
.withDatabaseName("keycloak")
.withUsername(databaseConfig.getUsername())
.withPassword(databaseConfig.getPassword());
}
private GenericContainer<?> createContainer() {
return switch (databaseConfig.getVendor()) {
case PostgresDatabaseSupplier.VENDOR -> {
DockerImageName POSTGRES = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("postgres");
yield configureJdbcContainer(new PostgreSQLContainer<>(POSTGRES));
}
case MariaDBDatabaseSupplier.VENDOR -> {
DockerImageName MARIADB = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("mariadb");
yield configureJdbcContainer(new MariaDBContainer<>(MARIADB));
}
case MySQLDatabaseSupplier.VENDOR -> {
DockerImageName MYSQL = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("mysql");
yield configureJdbcContainer(new MySQLContainer<>(MYSQL));
}
case MSSQLServerDatabaseSupplier.VENDOR -> {
DockerImageName MSSQL = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("sqlserver");
yield configureJdbcContainer(new MSSQLServerContainer<>(MSSQL));
}
default -> throw new RuntimeException("Unsupported database: " + databaseConfig.getVendor());
};
}
} }

View file

@ -9,5 +9,8 @@ org.keycloak.test.framework.webdriver.ChromeWebDriverSupplier
org.keycloak.test.framework.webdriver.FirefoxWebDriverSupplier org.keycloak.test.framework.webdriver.FirefoxWebDriverSupplier
org.keycloak.test.framework.database.DevMemDatabaseSupplier org.keycloak.test.framework.database.DevMemDatabaseSupplier
org.keycloak.test.framework.database.DevFileDatabaseSupplier org.keycloak.test.framework.database.DevFileDatabaseSupplier
org.keycloak.test.framework.database.MySQLDatabaseSupplier
org.keycloak.test.framework.database.PostgresDatabaseSupplier org.keycloak.test.framework.database.PostgresDatabaseSupplier
org.keycloak.test.framework.database.MariaDBDatabaseSupplier
org.keycloak.test.framework.database.MSSQLServerDatabaseSupplier
org.keycloak.test.framework.page.PageSupplier org.keycloak.test.framework.page.PageSupplier