Skip to content

Commit

Permalink
Modernize Oracle Container Logic
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleAure committed Sep 1, 2021
1 parent b1cdaf9 commit 6bb651d
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 37 deletions.
2 changes: 2 additions & 0 deletions modules/oracle-xe/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ dependencies {

testImplementation project(':jdbc-test')
testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0'

compileOnly 'org.jetbrains:annotations:21.0.1'
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@

import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.utility.DockerImageName;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;

public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.util.Collections.singleton;

public class OracleContainer<SELF extends OracleContainer<SELF>> extends JdbcDatabaseContainer<SELF> {

public static final String NAME = "oracle";
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe");


static final String DEFAULT_TAG = "18.4.0-slim";
static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart();

Expand All @@ -23,10 +28,21 @@ public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {

private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240;
private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 120;
private static final List<String> ORACLE_SYSTEM_USERS = Arrays.asList("system", "sys");

private String username = "test";
private String password = "test";
static final String DEFAULT_DATABASE_NAME = "xepdb1"; //Container always starts with this database
static final String DEFAULT_APP_USER = "test";
static final String DEFAULT_SYSTEM_USER = "system";
static final String DEFAULT_SYS_USER = "sys";
static final String DEFUALT_SHARED_PASSWORD = "test"; //System and App users will share a password

private static final List<String> ORACLE_SYSTEM_USERS = Arrays.asList(DEFAULT_SYSTEM_USER, DEFAULT_SYS_USER);
private static final List<String> ORACLE_DEFAULT_DBS = Arrays.asList(DEFAULT_DATABASE_NAME);

private String databaseName = DEFAULT_DATABASE_NAME;
private String username = DEFAULT_APP_USER;
private String password = DEFUALT_SHARED_PASSWORD;

private boolean usingSid = false;

/**
* @deprecated use {@link OracleContainer(DockerImageName)} instead
Expand All @@ -51,14 +67,33 @@ public OracleContainer(Future<String> dockerImageName) {
}

private void preconfigure() {
withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS);
this.waitStrategy = new LogMessageWaitStrategy()
.withRegEx(".*DATABASE IS READY TO USE!.*\\s")
.withTimes(1)
.withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, SECONDS));

withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS);

addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT);
}

@NotNull
@Override
public Set<Integer> getLivenessCheckPortNumbers() {
return Sets.newHashSet(ORACLE_PORT);
return singleton(getMappedPort(ORACLE_PORT));
}

@Override
protected void configure() {
withEnv("ORACLE_PASSWORD", password);

//Only set ORACLE_DATABASE if different than the default
if(databaseName != DEFAULT_DATABASE_NAME) {
withEnv("ORACLE_DATABASE", databaseName);
}

withEnv("APP_USER", username);
withEnv("APP_USER_PASSWORD", password);
}

@Override
Expand All @@ -68,12 +103,29 @@ public String getDriverClassName() {

@Override
public String getJdbcUrl() {
return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + "/xepdb1";
return usingSid ?
"jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() :
"jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName();
}

@Override
public String getDatabaseName() {
return databaseName;
}

@SuppressWarnings("SameReturnValue")
public String getSid() {
return "xe";
}

public boolean isUsingSid() {
return usingSid;
}

@Override
public String getUsername() {
return username;
//An application user is tied to the database, and therefore not authenticated to connect to SID.
return isUsingSid() ? DEFAULT_SYSTEM_USER : username;
}

@Override
Expand All @@ -82,7 +134,40 @@ public String getPassword() {
}

@Override
public OracleContainer withUsername(String username) {
public String getTestQueryString() {
return "SELECT 1 FROM DUAL";
}

public Integer getOraclePort() {
return getMappedPort(ORACLE_PORT);
}

@SuppressWarnings("unused")
public Integer getWebPort() {
return getMappedPort(APEX_HTTP_PORT);
}

@Override
public SELF withDatabaseName(String databaseName) {
if (StringUtils.isEmpty(databaseName)) {
throw new IllegalArgumentException("Database name cannot be null or empty");
}

if (ORACLE_DEFAULT_DBS.contains(databaseName.toLowerCase())) {
throw new IllegalArgumentException("Database name cannot be one of " + ORACLE_DEFAULT_DBS);
}

this.databaseName = databaseName;
return self();
}

public SELF usingSid() {
this.usingSid = true;
return self();
}

@Override
public SELF withUsername(String username) {
if (StringUtils.isEmpty(username)) {
throw new IllegalArgumentException("Username cannot be null or empty");
}
Expand All @@ -94,7 +179,7 @@ public OracleContainer withUsername(String username) {
}

@Override
public OracleContainer withPassword(String password) {
public SELF withPassword(String password) {
if (StringUtils.isEmpty(password)) {
throw new IllegalArgumentException("Password cannot be null or empty");
}
Expand All @@ -103,33 +188,12 @@ public OracleContainer withPassword(String password) {
}

@Override
public OracleContainer withUrlParam(String paramName, String paramValue) {
throw new UnsupportedOperationException("The OracleDb does not support this");
}

@SuppressWarnings("SameReturnValue")
public String getSid() {
return "xe";
}

public Integer getOraclePort() {
return getMappedPort(ORACLE_PORT);
}

@SuppressWarnings("unused")
public Integer getWebPort() {
return getMappedPort(APEX_HTTP_PORT);
}

@Override
public String getTestQueryString() {
return "SELECT 1 FROM DUAL";
public SELF withUrlParam(String paramName, String paramValue) {
throw new UnsupportedOperationException("The Oracle Database driver does not support this");
}

@Override
protected void configure() {
withEnv("ORACLE_PASSWORD", password);
withEnv("APP_USER", username);
withEnv("APP_USER_PASSWORD", password);
protected void waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,31 @@ public class SimpleOracleTest extends AbstractContainerDatabaseTest {
public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe:18.4.0-slim");

@Test
public void testSimple() throws SQLException {
public void testPluggableDatabase() throws SQLException {

try (
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.withUsername("baz")
.withPassword("bar")
.withDatabaseName("testDB")
) {
oracle.start();
ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual");

int resultSetInt = resultSet.getInt(1);

assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
}
}

@Test
public void testSID() throws SQLException {

try (
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.withUsername("baz")
.withPassword("bar")
.usingSid();
) {
oracle.start();
ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual");
Expand Down

0 comments on commit 6bb651d

Please sign in to comment.