Skip to content

Commit 29a438d

Browse files
authored
Modernize Oracle Container Logic (#4402)
1 parent 8f312b4 commit 29a438d

File tree

4 files changed

+203
-23
lines changed

4 files changed

+203
-23
lines changed

modules/oracle-xe/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ dependencies {
55

66
testImplementation project(':jdbc-test')
77
testImplementation 'com.oracle.ojdbc:ojdbc8:19.3.0.0'
8+
9+
compileOnly 'org.jetbrains:annotations:21.0.1'
810
}

modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22

33
import com.google.common.collect.Sets;
44
import org.apache.commons.lang.StringUtils;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
57
import org.testcontainers.utility.DockerImageName;
68

9+
import java.time.Duration;
710
import java.util.Arrays;
811
import java.util.List;
912
import java.util.Set;
1013
import java.util.concurrent.Future;
1114

15+
import static java.time.temporal.ChronoUnit.SECONDS;
16+
import static java.util.Collections.singleton;
17+
1218
public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {
1319

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

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

@@ -23,10 +28,24 @@ public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {
2328

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

28-
private String username = "test";
29-
private String password = "test";
32+
// Container defaults
33+
static final String DEFAULT_DATABASE_NAME = "xepdb1";
34+
static final String DEFAULT_SID = "xe";
35+
static final String DEFAULT_SYSTEM_USER = "system";
36+
static final String DEFAULT_SYS_USER = "sys";
37+
38+
// Test container defaults
39+
static final String APP_USER = "test";
40+
static final String APP_USER_PASSWORD = "test";
41+
42+
// Restricted user and database names
43+
private static final List<String> ORACLE_SYSTEM_USERS = Arrays.asList(DEFAULT_SYSTEM_USER, DEFAULT_SYS_USER);
44+
45+
private String databaseName = DEFAULT_DATABASE_NAME;
46+
private String username = APP_USER;
47+
private String password = APP_USER_PASSWORD;
48+
private boolean usingSid = false;
3049

3150
/**
3251
* @deprecated use {@link OracleContainer(DockerImageName)} instead
@@ -42,6 +61,7 @@ public OracleContainer(String dockerImageName) {
4261

4362
public OracleContainer(final DockerImageName dockerImageName) {
4463
super(dockerImageName);
64+
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
4565
preconfigure();
4666
}
4767

@@ -51,14 +71,24 @@ public OracleContainer(Future<String> dockerImageName) {
5171
}
5272

5373
private void preconfigure() {
54-
withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS);
74+
this.waitStrategy = new LogMessageWaitStrategy()
75+
.withRegEx(".*DATABASE IS READY TO USE!.*\\s")
76+
.withTimes(1)
77+
.withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, SECONDS));
78+
5579
withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS);
5680
addExposedPorts(ORACLE_PORT, APEX_HTTP_PORT);
5781
}
5882

83+
@Override
84+
protected void waitUntilContainerStarted() {
85+
getWaitStrategy().waitUntilReady(this);
86+
}
87+
88+
@NotNull
5989
@Override
6090
public Set<Integer> getLivenessCheckPortNumbers() {
61-
return Sets.newHashSet(ORACLE_PORT);
91+
return singleton(getMappedPort(ORACLE_PORT));
6292
}
6393

6494
@Override
@@ -68,19 +98,31 @@ public String getDriverClassName() {
6898

6999
@Override
70100
public String getJdbcUrl() {
71-
return "jdbc:oracle:thin:" + getUsername() + "/" + getPassword() + "@" + getHost() + ":" + getOraclePort() + "/xepdb1";
101+
return isUsingSid() ?
102+
"jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + ":" + getSid() :
103+
"jdbc:oracle:thin:" + "@" + getHost() + ":" + getOraclePort() + "/" + getDatabaseName();
72104
}
73105

74106
@Override
75107
public String getUsername() {
76-
return username;
108+
// An application user is tied to the database, and therefore not authenticated to connect to SID.
109+
return isUsingSid() ? DEFAULT_SYSTEM_USER : username;
77110
}
78111

79112
@Override
80113
public String getPassword() {
81114
return password;
82115
}
83116

117+
@Override
118+
public String getDatabaseName() {
119+
return databaseName;
120+
}
121+
122+
protected boolean isUsingSid() {
123+
return usingSid;
124+
}
125+
84126
@Override
85127
public OracleContainer withUsername(String username) {
86128
if (StringUtils.isEmpty(username)) {
@@ -102,14 +144,33 @@ public OracleContainer withPassword(String password) {
102144
return self();
103145
}
104146

147+
@Override
148+
public OracleContainer withDatabaseName(String databaseName) {
149+
if (StringUtils.isEmpty(databaseName)) {
150+
throw new IllegalArgumentException("Database name cannot be null or empty");
151+
}
152+
153+
if (DEFAULT_DATABASE_NAME.equals(databaseName.toLowerCase())) {
154+
throw new IllegalArgumentException("Database name cannot be set to " + DEFAULT_DATABASE_NAME);
155+
}
156+
157+
this.databaseName = databaseName;
158+
return self();
159+
}
160+
161+
public OracleContainer usingSid() {
162+
this.usingSid = true;
163+
return self();
164+
}
165+
105166
@Override
106167
public OracleContainer withUrlParam(String paramName, String paramValue) {
107-
throw new UnsupportedOperationException("The OracleDb does not support this");
168+
throw new UnsupportedOperationException("The Oracle Database driver does not support this");
108169
}
109170

110171
@SuppressWarnings("SameReturnValue")
111172
public String getSid() {
112-
return "xe";
173+
return DEFAULT_SID;
113174
}
114175

115176
public Integer getOraclePort() {
@@ -129,6 +190,12 @@ public String getTestQueryString() {
129190
@Override
130191
protected void configure() {
131192
withEnv("ORACLE_PASSWORD", password);
193+
194+
// Only set ORACLE_DATABASE if different than the default.
195+
if(databaseName != DEFAULT_DATABASE_NAME) {
196+
withEnv("ORACLE_DATABASE", databaseName);
197+
}
198+
132199
withEnv("APP_USER", username);
133200
withEnv("APP_USER_PASSWORD", password);
134201
}

modules/oracle-xe/src/test/java/org/testcontainers/containers/jdbc/OracleJDBCDriverTest.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@
1212

1313
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;
1414

15-
/**
16-
* @author gusohal
17-
*/
18-
@Ignore
1915
public class OracleJDBCDriverTest {
2016

2117
@Test
Lines changed: 124 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package org.testcontainers.junit.oracle;
22

3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.fail;
5+
36
import org.junit.Test;
47
import org.testcontainers.containers.OracleContainer;
58
import org.testcontainers.db.AbstractContainerDatabaseTest;
@@ -8,26 +11,138 @@
811
import java.sql.ResultSet;
912
import java.sql.SQLException;
1013

11-
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;
12-
1314
public class SimpleOracleTest extends AbstractContainerDatabaseTest {
1415

1516
public static final DockerImageName ORACLE_DOCKER_IMAGE_NAME = DockerImageName.parse("gvenzl/oracle-xe:18.4.0-slim");
1617

18+
private void runTest(OracleContainer container, String databaseName, String username, String password) throws SQLException {
19+
//Test config was honored
20+
assertEquals(databaseName, container.getDatabaseName());
21+
assertEquals(username, container.getUsername());
22+
assertEquals(password, container.getPassword());
23+
24+
//Test we can get a connection
25+
container.start();
26+
ResultSet resultSet = performQuery(container, "SELECT 1 FROM dual");
27+
int resultSetInt = resultSet.getInt(1);
28+
assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
29+
}
30+
31+
@Test
32+
public void testDefaultSettings() throws SQLException {
33+
try (
34+
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME);
35+
) {
36+
runTest(oracle, "xepdb1", "test", "test");
37+
38+
// Match against the last '/'
39+
String urlSuffix = oracle.getJdbcUrl().split("(\\/)(?!.*\\/)", 2)[1];
40+
assertEquals("xepdb1", urlSuffix);
41+
}
42+
}
43+
44+
@Test
45+
public void testPluggableDatabase() throws SQLException {
46+
try (
47+
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
48+
.withDatabaseName("testDB")
49+
) {
50+
runTest(oracle, "testDB", "test", "test");
51+
}
52+
}
53+
54+
@Test
55+
public void testPluggableDatabaseAndCustomUser() throws SQLException {
56+
try (
57+
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
58+
.withDatabaseName("testDB")
59+
.withUsername("testUser")
60+
.withPassword("testPassword")
61+
) {
62+
runTest(oracle, "testDB", "testUser", "testPassword");
63+
}
64+
}
65+
1766
@Test
18-
public void testSimple() throws SQLException {
67+
public void testCustomUser() throws SQLException {
68+
try (
69+
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
70+
.withUsername("testUser")
71+
.withPassword("testPassword")
72+
) {
73+
runTest(oracle, "xepdb1", "testUser", "testPassword");
74+
}
75+
}
1976

77+
@Test
78+
public void testSID() throws SQLException {
2079
try (
2180
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
22-
.withUsername("baz")
23-
.withPassword("bar")
81+
.usingSid();
2482
) {
25-
oracle.start();
26-
ResultSet resultSet = performQuery(oracle, "SELECT 1 FROM dual");
83+
runTest(oracle, "xepdb1", "system", "test");
84+
85+
// Match against the last ':'
86+
String urlSuffix = oracle.getJdbcUrl().split("(\\:)(?!.*\\:)", 2)[1];
87+
assertEquals("xe", urlSuffix);
88+
}
89+
}
90+
91+
@Test
92+
public void testSIDAndCustomPassword() throws SQLException {
93+
try (
94+
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
95+
.usingSid()
96+
.withPassword("testPassword");
97+
) {
98+
runTest(oracle, "xepdb1", "system", "testPassword");
99+
}
100+
}
101+
102+
@Test
103+
public void testErrorPaths() throws SQLException {
104+
try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)) {
105+
try {
106+
oracle.withDatabaseName("XEPDB1");
107+
fail("Should not have been able to set database name to xepdb1.");
108+
} catch (IllegalArgumentException e) {
109+
//expected
110+
}
111+
112+
try {
113+
oracle.withDatabaseName("");
114+
fail("Should not have been able to set database name to nothing.");
115+
} catch (IllegalArgumentException e) {
116+
//expected
117+
}
118+
119+
try {
120+
oracle.withUsername("SYSTEM");
121+
fail("Should not have been able to set username to system.");
122+
} catch (IllegalArgumentException e) {
123+
//expected
124+
}
125+
126+
try {
127+
oracle.withUsername("SYS");
128+
fail("Should not have been able to set username to sys.");
129+
} catch (IllegalArgumentException e) {
130+
//expected
131+
}
27132

28-
int resultSetInt = resultSet.getInt(1);
133+
try {
134+
oracle.withUsername("");
135+
fail("Should not have been able to set username to nothing.");
136+
} catch (IllegalArgumentException e) {
137+
//expected
138+
}
29139

30-
assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
140+
try {
141+
oracle.withPassword("");
142+
fail("Should not have been able to set password to nothing.");
143+
} catch (IllegalArgumentException e) {
144+
//expected
145+
}
31146
}
32147
}
33148
}

0 commit comments

Comments
 (0)