Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/modules/databases/jdbc.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,13 @@ Examples/Tests:

* [MySQL](https://github.com/testcontainers/testcontainers-java/blob/main/modules/mysql/src/test/java/org/testcontainers/junit/mysql/SimpleMySQLTest.java)
* [PostgreSQL](https://github.com/testcontainers/testcontainers-java/blob/main/modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java)

### Init script encoding

Init scripts configured with `withInitScript` or `withInitScripts` are read as UTF-8 by default. If your scripts use another encoding, set it on the container:

<!--codeinclude-->
[Init script charset](../../../modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLContainerTest.java) inside_block:initScriptCharset
<!--/codeinclude-->

The charset applies to all init scripts of the container. Scripts loaded via `TC_INITSCRIPT` are always read as UTF-8.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -192,12 +193,24 @@ public static boolean containsSqlScriptDelimiters(
}

/**
* Load script from classpath and apply it to the given database
* Load a UTF-8 script from the classpath and apply it to the given database.
*
* @param databaseDelegate database delegate for script execution
* @param initScriptPath the resource to load the init script from
*/
public static void runInitScript(DatabaseDelegate databaseDelegate, String initScriptPath) {
runInitScript(databaseDelegate, initScriptPath, StandardCharsets.UTF_8);
}

/**
* Load a script from the classpath using the given charset and apply it to the given database.
*
* @param databaseDelegate database delegate for script execution
* @param initScriptPath the resource to load the init script from
* @param charset the charset used to read the script; never {@code null}
*/
public static void runInitScript(DatabaseDelegate databaseDelegate, String initScriptPath, Charset charset) {
checkArgument(charset != null, "charset must not be null");
try {
URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath);
if (resource == null) {
Expand All @@ -209,7 +222,7 @@ public static void runInitScript(DatabaseDelegate databaseDelegate, String initS
);
}
}
String scripts = IOUtils.toString(resource, StandardCharsets.UTF_8);
String scripts = IOUtils.toString(resource, charset);
executeDatabaseScript(databaseDelegate, initScriptPath, scripts);
} catch (IOException e) {
LOGGER.warn("Could not load classpath init script: {}", initScriptPath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.testcontainers.ext;

import org.junit.jupiter.api.Test;
import org.testcontainers.delegate.AbstractDatabaseDelegate;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class ScriptUtilsTest {

private final RecordingDatabaseDelegate delegate = new RecordingDatabaseDelegate();

@Test
void usesUtf8ByDefault() {
ScriptUtils.runInitScript(delegate, "init-utf-8.sql");

assertThat(delegate.statements).containsExactly("SELECT 'café'");
}

@Test
void readsWindows1252Script() {
ScriptUtils.runInitScript(delegate, "init-windows-1252.sql", Charset.forName("windows-1252"));

assertThat(delegate.statements).containsExactly("SELECT 'café'");
}

@Test
void rejectsNullCharset() {
assertThatThrownBy(() -> ScriptUtils.runInitScript(delegate, "init-utf-8.sql", null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("charset must not be null");
}

private static class RecordingDatabaseDelegate extends AbstractDatabaseDelegate<Void> {

private final List<String> statements = new ArrayList<>();

@Override
public void execute(
String statement,
String scriptPath,
int lineNumber,
boolean continueOnError,
boolean ignoreFailedDrops
) {
statements.add(statement);
}

@Override
protected Void createNewConnection() {
return null;
}

@Override
protected void closeConnectionQuietly(Void connection) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 'café';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 'café';
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
Expand Down Expand Up @@ -41,6 +43,8 @@

private List<String> initScriptPaths = new ArrayList<>();

private Charset initScriptCharset = StandardCharsets.UTF_8;

protected Map<String, String> parameters = new HashMap<>();

protected Map<String, String> urlParameters = new HashMap<>();
Expand All @@ -54,7 +58,7 @@
/**
* @deprecated use {@link #JdbcDatabaseContainer(DockerImageName)} instead
*/
public JdbcDatabaseContainer(@NonNull final String dockerImageName) {

Check warning on line 61 in modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java

View workflow job for this annotation

GitHub Actions / check (:testcontainers-jdbc:check)

[dep-ann] deprecated item is not annotated with @deprecated
this(DockerImageName.parse(dockerImageName));
}

Expand Down Expand Up @@ -171,6 +175,18 @@
return self();
}

/**
* Sets the charset used to read all scripts configured with {@link #withInitScript(String)}
* or {@link #withInitScripts(String...)}. Defaults to UTF-8.
*
* @param charset the charset used to read the scripts
* @return self
*/
public SELF withInitScriptCharset(@NonNull Charset charset) {
this.initScriptCharset = charset;
return self();
}

@SneakyThrows(InterruptedException.class)
@Override
protected void waitUntilContainerStarted() {
Expand Down Expand Up @@ -365,7 +381,7 @@
initScriptPaths
.stream()
.filter(Objects::nonNull)
.forEach(path -> ScriptUtils.runInitScript(getDatabaseDelegate(), path));
.forEach(path -> ScriptUtils.runInitScript(getDatabaseDelegate(), path, initScriptCharset));
}

public void setParameters(Map<String, String> parameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.testcontainers.PostgreSQLTestImages;
import org.testcontainers.db.AbstractContainerDatabaseTest;

import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
Expand Down Expand Up @@ -87,6 +88,24 @@ void testExplicitInitScript() throws SQLException {
}
}

@Test
void testExplicitInitScriptWithCharset() throws SQLException {
try (
// initScriptCharset {
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
.withInitScript("somepath/init_postgresql_windows-1252.sql")
.withInitScriptCharset(Charset.forName("windows-1252"))
// }
) {
postgres.start();

ResultSet resultSet = performQuery(postgres, "SELECT foo FROM bar");

String firstColumnValue = resultSet.getString(1);
assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("café");
}
}

@Test
void testExplicitInitScripts() throws SQLException {
try (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE TABLE bar (
foo VARCHAR(255)
);

INSERT INTO bar (foo) VALUES ('café');
Loading