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 #withSystemPassword(String)}.
*/
private String oraclePassword = APP_USER_PASSWORD;
Copy link
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 #withSystemPassword(String)} was called to avoid overriding
* the system password when {@link #withPassword(String)} is used for the application user only.
*/
private boolean systemPasswordExplicitlySet = false;
Comment on lines +61 to +71
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.

In this class the system-user password is stored in a field named oraclePassword, while related state is systemPasswordExplicitlySet and the other Oracle module uses systemPassword. This inconsistency makes it harder to reason about which password is which (system vs app) and increases the chance of future mapping bugs. Consider standardizing the field name (e.g., systemPassword) and updating references accordingly.

Copilot uses AI. Check for mistakes.

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 system password wasn't set explicitly,
// align it with the application user's password.
if (!systemPasswordExplicitlySet) {
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 withSystemPassword(String oraclePassword) {
if (StringUtils.isEmpty(oraclePassword)) {
throw new IllegalArgumentException("Oracle password cannot be null or empty");
}
this.oraclePassword = oraclePassword;
this.systemPasswordExplicitlySet = 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);
Comment on lines +41 to +45
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
void testDefaultSettings() throws SQLException {
try ( // container {
Expand Down Expand Up @@ -78,7 +92,7 @@ void testCustomUser() throws SQLException {
@Test
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 @@ -93,7 +107,30 @@ void testSIDAndCustomPassword() throws SQLException {
.usingSid()
.withPassword("testPassword")
) {
runTest(oracle, "freepdb1", "system", "testPassword");
runTestSystemUser(oracle, "freepdb1", "system", "testPassword");
}
}

@Test
public void testWithSystemPassword() throws SQLException {
try (
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.usingSid()
.withSystemPassword("SysP@ss1!")
.withPassword("AppP@ss1!")
) {
runTestSystemUser(oracle, "freepdb1", "system", "SysP@ss1!");
}
}

@Test
public void testWithPassword() throws SQLException {
try (
OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)
.withSystemPassword("SysP@ss2!")
.withPassword("AppP@ss2!")
) {
runTest(oracle, "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 #withSystemPassword(String)}.
*/
private String systemPassword = APP_USER_PASSWORD;

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

private boolean usingSid = false;

/**
Expand Down Expand Up @@ -133,7 +145,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() ? systemPassword : password;
}

@Override
Expand Down Expand Up @@ -163,6 +176,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 (!systemPasswordExplicitlySet) {
this.systemPassword = password;
}
Comment on lines +179 to +183
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 inline comment says "if oracle password wasn't set explicitly" but the code is tracking the system password via systemPasswordExplicitlySet. Updating the comment to refer to the system password would avoid confusion when maintaining this logic.

Copilot uses AI. Check for mistakes.
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 withSystemPassword(String oraclePassword) {
if (StringUtils.isEmpty(oraclePassword)) {
throw new IllegalArgumentException("Oracle password cannot be null or empty");
}
this.systemPassword = oraclePassword;
this.systemPasswordExplicitlySet = 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 @@ -211,7 +245,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", systemPassword);

// 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 {
assertThat(container.getDatabaseName()).isEqualTo(databaseName);
assertThat(container.getUsername()).isEqualTo(username);
assertThat(container.getPassword()).isEqualTo(password);

container.start();
ResultSet resultSet = performQuery(container, "SELECT USER FROM DUAL");
String currentUser = resultSet.getString(1);
assertThat(currentUser)
.as("Connected session should run as the system user")
.isEqualToIgnoringCase(username);
}

@Test
void testDefaultSettings() throws SQLException {
try ( // container {
Expand Down Expand Up @@ -78,7 +92,7 @@ void testCustomUser() throws SQLException {
@Test
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 @@ -93,7 +107,28 @@ 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
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?

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

// Non-SID mode should use application user's password
Copy link
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)
.withSystemPassword("SysP@ss2!")
.withPassword("AppP@ss2!")
) {
runTest(oraclePdb, "xepdb1", "test", "AppP@ss2!");
}
}

Expand Down
Loading