Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {

private String password = APP_USER_PASSWORD;

/**
* Password for Oracle system user (e.g. SYSTEM/SYS). Defaults to {@link #APP_USER_PASSWORD}
* for backwards compatibility, but can be customized independently via {@link #withOraclePassword(String)}.
*/
private String oraclePassword = APP_USER_PASSWORD;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private String oraclePassword = APP_USER_PASSWORD;
private String systemPassword = APP_USER_PASSWORD;


/**
* Tracks whether {@link #withOraclePassword(String)} was called to avoid overriding
* the system password when {@link #withPassword(String)} is used for the application user only.
*/
private boolean oraclePasswordExplicitlySet = false;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private boolean oraclePasswordExplicitlySet = false;
private boolean systemPasswordExplicitlySet = false;


private boolean usingSid = false;

public OracleContainer(String dockerImageName) {
Expand Down Expand Up @@ -112,7 +124,8 @@ public String getUsername() {

@Override
public String getPassword() {
return password;
// When connecting via SID we authenticate as SYSTEM. Use the dedicated system password.
return isUsingSid() ? oraclePassword : password;
}

@Override
Expand Down Expand Up @@ -142,6 +155,27 @@ public OracleContainer withPassword(String password) {
throw new IllegalArgumentException("Password cannot be null or empty");
}
this.password = password;
// Maintain backwards compatibility: if oracle password wasn't set explicitly,
// align it with the application user's password.
if (!oraclePasswordExplicitlySet) {
this.oraclePassword = password;
}
return self();
}

/**
* Sets the password for the Oracle system user (SYSTEM/SYS). This is independent from the
* application user password set via {@link #withPassword(String)}.
*
* @param oraclePassword password for SYSTEM/SYS users inside the container
* @return this container instance
*/
public OracleContainer withOraclePassword(String oraclePassword) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public OracleContainer withOraclePassword(String oraclePassword) {
public OracleContainer withSystemPassword(String oraclePassword) {

if (StringUtils.isEmpty(oraclePassword)) {
throw new IllegalArgumentException("Oracle password cannot be null or empty");
}
this.oraclePassword = oraclePassword;
this.oraclePasswordExplicitlySet = true;
return self();
Comment on lines +166 to 179
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description/docs mention withOraclePassword(String) as the new API, but this module adds withSystemPassword(String) instead. Because this is part of the public container API, please align the method name with the documented API (or update the docs/PR description to match), and consider an alias/deprecation plan to avoid confusing users.

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -185,7 +219,8 @@ public String getTestQueryString() {

@Override
protected void configure() {
withEnv("ORACLE_PASSWORD", password);
// Configure system user password independently from application user's password
withEnv("ORACLE_PASSWORD", oraclePassword);

// Only set ORACLE_DATABASE if different than the default.
if (databaseName != DEFAULT_DATABASE_NAME) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ private void runTest(OracleContainer container, String databaseName, String user
assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1);
}

private void runTestSystemUser(OracleContainer container, String databaseName, String username, String password)
throws SQLException {
//Test config was honored
assertThat(container.getDatabaseName()).isEqualTo(databaseName);
assertThat(container.getUsername()).isEqualTo(username);
assertThat(container.getPassword()).isEqualTo(password);

//Test we can get a connection and execute a system-level command
container.start();
ResultSet resultSet = performQuery(container, "GRANT DBA TO " + username);
int resultSetInt = resultSet.getInt(1);
assertThat(resultSetInt).as("A basic system user query succeeds").isEqualTo(1);
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performQuery(...) expects the SQL to produce a ResultSet (it calls Statement#getResultSet() and then resultSet.next()). GRANT DBA TO ... does not return a result set, so statement.getResultSet() will be null and this test will fail with a NullPointerException. Use a SELECT-based assertion (e.g., SELECT USER FROM DUAL) or change the helper to use executeUpdate/check update count for DDL/DCL statements.

Copilot uses AI. Check for mistakes.
}

@Test
public void testDefaultSettings() throws SQLException {
try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)) {
Expand Down Expand Up @@ -77,7 +91,7 @@ public void testCustomUser() throws SQLException {
@Test
public void testSID() throws SQLException {
try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).usingSid()) {
runTest(oracle, "freepdb1", "system", "test");
runTestSystemUser(oracle, "freepdb1", "system", "test");

// Match against the last ':'
String urlSuffix = oracle.getJdbcUrl().split("(\\:)(?!.*\\:)", 2)[1];
Expand All @@ -92,7 +106,29 @@ public void testSIDAndCustomPassword() throws SQLException {
.usingSid()
.withPassword("testPassword")
) {
runTest(oracle, "freepdb1", "system", "testPassword");
runTestSystemUser(oracle, "freepdb1", "system", "testPassword");
}
}

@Test
public void testSeparateSystemAndAppPasswords() throws SQLException {
// SID mode should use system password
try (
OracleContainer oracleSid = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.usingSid()
.withOraclePassword("SysP@ss1!")
.withPassword("AppP@ss1!")
) {
runTestSystemUser(oracleSid, "freepdb1", "system", "SysP@ss1!");
}

// Non-SID mode should use application user's password
try (
OracleContainer oraclePdb = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.withOraclePassword("SysP@ss2!")
.withPassword("AppP@ss2!")
) {
runTest(oraclePdb, "freepdb1", "test", "AppP@ss2!");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ public class OracleContainer extends JdbcDatabaseContainer<OracleContainer> {

private String password = APP_USER_PASSWORD;

/**
* Password for Oracle system user (e.g. SYSTEM/SYS). Defaults to {@link #APP_USER_PASSWORD}
* for backwards compatibility, but can be customized independently via {@link #withOraclePassword(String)}.
*/
private String oraclePassword = APP_USER_PASSWORD;

/**
* Tracks whether {@link #withOraclePassword(String)} was called to avoid overriding
* the system password when {@link #withPassword(String)} is used for the application user only.
*/
private boolean oraclePasswordExplicitlySet = false;

private boolean usingSid = false;

public OracleContainer(String dockerImageName) {
Expand Down Expand Up @@ -125,7 +137,8 @@ public String getUsername() {

@Override
public String getPassword() {
return password;
// When connecting via SID we authenticate as SYSTEM. Use the dedicated system password.
return isUsingSid() ? oraclePassword : password;
}

@Override
Expand Down Expand Up @@ -155,6 +168,27 @@ public OracleContainer withPassword(String password) {
throw new IllegalArgumentException("Password cannot be null or empty");
}
this.password = password;
// Maintain backwards compatibility: if oracle password wasn't set explicitly,
// align it with the application user's password.
if (!oraclePasswordExplicitlySet) {
this.oraclePassword = password;
}
return self();
}

/**
* Sets the password for the Oracle system user (SYSTEM/SYS). This is independent from the
* application user password set via {@link #withPassword(String)}.
*
* @param oraclePassword password for SYSTEM/SYS users inside the container
* @return this container instance
*/
public OracleContainer withOraclePassword(String oraclePassword) {
if (StringUtils.isEmpty(oraclePassword)) {
throw new IllegalArgumentException("Oracle password cannot be null or empty");
}
this.oraclePassword = oraclePassword;
this.oraclePasswordExplicitlySet = true;
return self();
Comment on lines +187 to 200
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description and usage examples refer to a new public API withOraclePassword(String), but the implementation introduces withSystemPassword(String) instead. Since this is a user-facing API, please either rename the method to match the documented API (and keep withSystemPassword as a deprecated alias if needed), or update the PR description/docs accordingly so users know which method to call.

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -203,7 +237,8 @@ public String getTestQueryString() {

@Override
protected void configure() {
withEnv("ORACLE_PASSWORD", password);
// Configure system user password independently from application user's password
withEnv("ORACLE_PASSWORD", oraclePassword);

// Only set ORACLE_DATABASE if different than the default.
if (databaseName != DEFAULT_DATABASE_NAME) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ private void runTest(OracleContainer container, String databaseName, String user
assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1);
}

private void runTestSystemUser(OracleContainer container, String databaseName, String username, String password)
throws SQLException {
//Test config was honored
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comment

assertThat(container.getDatabaseName()).isEqualTo(databaseName);
assertThat(container.getUsername()).isEqualTo(username);
assertThat(container.getPassword()).isEqualTo(password);

//Test we can get a connection and execute a system-level command
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comment

container.start();
ResultSet resultSet = performQuery(container, "GRANT DBA TO " + username);
int resultSetInt = resultSet.getInt(1);
assertThat(resultSetInt).as("A basic system user query succeeds").isEqualTo(1);
}

@Test
public void testDefaultSettings() throws SQLException {
try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME);) {
Expand Down Expand Up @@ -77,7 +91,7 @@ public void testCustomUser() throws SQLException {
@Test
public void testSID() throws SQLException {
try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).usingSid();) {
runTest(oracle, "xepdb1", "system", "test");
runTestSystemUser(oracle, "xepdb1", "system", "test");

// Match against the last ':'
String urlSuffix = oracle.getJdbcUrl().split("(\\:)(?!.*\\:)", 2)[1];
Expand All @@ -92,7 +106,29 @@ public void testSIDAndCustomPassword() throws SQLException {
.usingSid()
.withPassword("testPassword");
) {
runTest(oracle, "xepdb1", "system", "testPassword");
runTestSystemUser(oracle, "xepdb1", "system", "testPassword");
}
}

@Test
public void testSeparateSystemAndAppPasswords() throws SQLException {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have two tests instead?

// SID mode should use system password
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comment

try (
OracleContainer oracleSid = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.usingSid()
.withOraclePassword("SysP@ss1!")
.withPassword("AppP@ss1!")
) {
runTestSystemUser(oracleSid, "xepdb1", "system", "SysP@ss1!");
}

// Non-SID mode should use application user's password
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comment

try (
OracleContainer oraclePdb = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.withOraclePassword("SysP@ss2!")
.withPassword("AppP@ss2!")
) {
runTest(oraclePdb, "xepdb1", "test", "AppP@ss2!");
}
}

Expand Down