22
33import com .google .common .collect .Sets ;
44import org .apache .commons .lang .StringUtils ;
5+ import org .jetbrains .annotations .NotNull ;
6+ import org .testcontainers .containers .wait .strategy .LogMessageWaitStrategy ;
57import org .testcontainers .utility .DockerImageName ;
68
9+ import java .time .Duration ;
710import java .util .Arrays ;
811import java .util .List ;
912import java .util .Set ;
1013import java .util .concurrent .Future ;
1114
15+ import static java .time .temporal .ChronoUnit .SECONDS ;
16+ import static java .util .Collections .singleton ;
17+
1218public 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 }
0 commit comments