Add Oracle database provider. (#32070)

Closes #31969

Signed-off-by: Miquel Simon <msimonma@redhat.com>
This commit is contained in:
Miquel Simon 2024-08-22 06:52:30 +02:00 committed by GitHub
parent 5cb90b6465
commit c539a15ee5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 93 additions and 5 deletions

View file

@ -53,6 +53,10 @@
<groupId>com.microsoft.sqlserver</groupId> <groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -86,6 +86,10 @@
<groupId>org.testcontainers</groupId> <groupId>org.testcontainers</groupId>
<artifactId>mssqlserver</artifactId> <artifactId>mssqlserver</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>oracle-free</artifactId>
</dependency>
<!-- Temporary dependency until we figure out how we want to support OAuth --> <!-- Temporary dependency until we figure out how we want to support OAuth -->
<dependency> <dependency>
<groupId>com.nimbusds</groupId> <groupId>com.nimbusds</groupId>

View file

@ -11,6 +11,10 @@ public class DatabaseConfig {
private String username; private String username;
private String password; private String password;
private String postStartCommand;
private Map<String, String> env = new HashMap<>();
public String getVendor() { public String getVendor() {
return vendor; return vendor;
} }
@ -56,6 +60,24 @@ public class DatabaseConfig {
return this; return this;
} }
public String getPostStartCommand() {
return postStartCommand;
}
public DatabaseConfig postStartCommand(String postStartCommand) {
this.postStartCommand = postStartCommand;
return this;
}
public Map<String, String> getEnv() {
return env;
}
public DatabaseConfig env(Map<String, String> env) {
this.env = env;
return this;
}
public Map<String, String> toConfig() { public Map<String, String> toConfig() {
Map<String, String> config = new HashMap<>(); Map<String, String> config = new HashMap<>();
if (vendor != null) { if (vendor != null) {

View file

@ -0,0 +1,34 @@
package org.keycloak.test.framework.database;
import java.util.HashMap;
import java.util.Map;
public class OracleDatabaseSupplier extends AbstractDatabaseSupplier {
public static final String VENDOR = "oracle";
private static final String CONTAINER_IMAGE = "docker.io/miquelsi/oracle-19c:19.3";
@Override
TestDatabase getTestDatabase() {
Map<String, String> env = new HashMap<>();
env.put("ORACLE_SID", "keycloak");
env.put("ORACLE_PWD", "sa");
DatabaseConfig databaseConfig = new DatabaseConfig()
.vendor(VENDOR)
.username(DEFAULT_DB_USERNAME)
.password(DEFAULT_DB_PASSWORD)
.postStartCommand("(echo 'alter session set \"_ORACLE_SCRIPT\"=true;' && echo 'CREATE USER " +
DEFAULT_DB_USERNAME + " IDENTIFIED BY \"" +
DEFAULT_DB_PASSWORD + "\";' && echo 'GRANT CONNECT,RESOURCE,DBA,GRANT ANY PRIVILEGE,UNLIMITED TABLESPACE TO " +
DEFAULT_DB_USERNAME + ";') | sqlplus -L SYS/" + env.get("ORACLE_PWD") + "@localhost/" + env.get("ORACLE_SID") + " AS SYSDBA")
.containerImage(CONTAINER_IMAGE)
.env(env);
return new TestDatabase(databaseConfig);
}
@Override
public String getAlias() {
return VENDOR;
}
}

View file

@ -1,18 +1,25 @@
package org.keycloak.test.framework.database; package org.keycloak.test.framework.database;
import org.jboss.logging.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.JdbcDatabaseContainer; import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.oracle.OracleContainer;
import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.DockerImageName;
import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.Map; import java.util.Map;
public class TestDatabase { public class TestDatabase {
private static final Logger LOGGER = Logger.getLogger(TestDatabase.class);
private final DatabaseConfig databaseConfig; private final DatabaseConfig databaseConfig;
private GenericContainer<?> container; private GenericContainer<?> container;
@ -24,7 +31,19 @@ public class TestDatabase {
public void start() { public void start() {
if (databaseConfig.getContainerImage() != null) { if (databaseConfig.getContainerImage() != null) {
container = createContainer(); container = createContainer();
container.withStartupTimeout(Duration.ofMinutes(5)).start(); container.withStartupTimeout(Duration.ofMinutes(30))
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger(TestDatabase.class)))
.withEnv(databaseConfig.getEnv())
.start();
try {
if (databaseConfig.getPostStartCommand() != null) {
LOGGER.tracev("Running post start command: " + databaseConfig.getPostStartCommand());
String result = container.execInContainer("bash", "-c", databaseConfig.getPostStartCommand()).getStdout();
LOGGER.tracev(result);
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
databaseConfig.url(getJdbcUrl()); databaseConfig.url(getJdbcUrl());
if (container instanceof MSSQLServerContainer) { if (container instanceof MSSQLServerContainer) {
databaseConfig.username(((JdbcDatabaseContainer<?>) container).getUsername()); databaseConfig.username(((JdbcDatabaseContainer<?>) container).getUsername());
@ -64,21 +83,25 @@ public class TestDatabase {
private GenericContainer<?> createContainer() { private GenericContainer<?> createContainer() {
return switch (databaseConfig.getVendor()) { return switch (databaseConfig.getVendor()) {
case PostgresDatabaseSupplier.VENDOR -> { case PostgresDatabaseSupplier.VENDOR -> {
DockerImageName POSTGRES = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("postgres"); DockerImageName POSTGRES = DockerImageName.parse(databaseConfig.getContainerImage());
yield configureJdbcContainer(new PostgreSQLContainer<>(POSTGRES)); yield configureJdbcContainer(new PostgreSQLContainer<>(POSTGRES));
} }
case MariaDBDatabaseSupplier.VENDOR -> { case MariaDBDatabaseSupplier.VENDOR -> {
DockerImageName MARIADB = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("mariadb"); DockerImageName MARIADB = DockerImageName.parse(databaseConfig.getContainerImage());
yield configureJdbcContainer(new MariaDBContainer<>(MARIADB)); yield configureJdbcContainer(new MariaDBContainer<>(MARIADB));
} }
case MySQLDatabaseSupplier.VENDOR -> { case MySQLDatabaseSupplier.VENDOR -> {
DockerImageName MYSQL = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("mysql"); DockerImageName MYSQL = DockerImageName.parse(databaseConfig.getContainerImage());
yield configureJdbcContainer(new MySQLContainer<>(MYSQL)); yield configureJdbcContainer(new MySQLContainer<>(MYSQL));
} }
case MSSQLServerDatabaseSupplier.VENDOR -> { case MSSQLServerDatabaseSupplier.VENDOR -> {
DockerImageName MSSQL = DockerImageName.parse(databaseConfig.getContainerImage()).asCompatibleSubstituteFor("sqlserver"); DockerImageName MSSQL = DockerImageName.parse(databaseConfig.getContainerImage());
yield configureJdbcContainer(new MSSQLServerContainer<>(MSSQL)); yield configureJdbcContainer(new MSSQLServerContainer<>(MSSQL));
} }
case OracleDatabaseSupplier.VENDOR -> {
DockerImageName ORACLE = DockerImageName.parse(databaseConfig.getContainerImage());
yield configureJdbcContainer(new OracleContainer(ORACLE));
}
default -> throw new RuntimeException("Unsupported database: " + databaseConfig.getVendor()); default -> throw new RuntimeException("Unsupported database: " + databaseConfig.getVendor());
}; };
} }

View file

@ -15,5 +15,6 @@ 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.MariaDBDatabaseSupplier
org.keycloak.test.framework.database.MSSQLServerDatabaseSupplier org.keycloak.test.framework.database.MSSQLServerDatabaseSupplier
org.keycloak.test.framework.database.OracleDatabaseSupplier
org.keycloak.test.framework.page.PageSupplier org.keycloak.test.framework.page.PageSupplier
org.keycloak.test.framework.oauth.OAuthClientSupplier org.keycloak.test.framework.oauth.OAuthClientSupplier