-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: Using org.testcontainers:mysql
will report an error as mysqld failed while attempting to check config
in GraalVM Native Image
#7954
Comments
org.testcontainers:mysql
will report an error as mysqld failed while attempting to check config
org.testcontainers:mysql
will report an error as mysqld failed while attempting to check config
in GraalVM Native Image
This is related to file-copy by testcontainers in native-image ; it's not MySQL specific. It's in the logs of the container:
That's be cause the This seems to be due to this known issue, the file is not found in native image: oracle/graal#7682 Testcontainers swallows the error in a try-catch ; so it starts the container but without the file. Consider the following tests; when doing @Test
void testNginx() throws IOException, InterruptedException {
try (GenericContainer<?> nginx = new GenericContainer<>("nginx:1-alpine-slim")) {
nginx
.withCopyToContainer(
Transferable.of("Hello world!"),
"/usr/share/nginx/html/hello.html"
)
.withExposedPorts(80)
.start();
HttpClient httpClient = HttpClient.newBuilder().build();
String url = String.format("http://%s:%d/hello.html", nginx.getHost(), nginx.getFirstMappedPort());
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder().GET().uri(URI.create(url)).build(), HttpResponse.BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals("Bonjour monde!", response.body());
}
} Consider the following tests; when doing @Test
@Disabled
void testNginxWithResource() throws IOException, InterruptedException {
try (GenericContainer<?> nginx = new GenericContainer<>("nginx:1-alpine-slim")) {
nginx
.withCopyFileToContainer(
MountableFile.forClasspathResource("bonjour.html"),
"/usr/share/nginx/html/bonjour.html"
)
.withExposedPorts(80)
.start();
HttpClient httpClient = HttpClient.newBuilder().build();
String url = String.format("http://%s:%d/bonjour.html", nginx.getHost(), nginx.getFirstMappedPort());
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder().GET().uri(URI.create(url)).build(), HttpResponse.BodyHandlers.ofString());
assertEquals(response.statusCode(), 200);
assertEquals("Bonjour monde!", response.body());
}
} Fails with:
For now, the only workaround seems to use java-config, and copy the conf through I'm working on getting to the bottom of this, trying to get better recommendations. |
I have further investigated. The Testcontainers project would have to change their code to support resource-loading in native-image. They would need to change it a lot because they'd need to change the Java APIs they use (File vs Path) or make a special case for Resources vs file ; they would also have to work around So using mountable resources won't work. Unfortunately, the There is one way around all these issues, which is explicit configuration of MySQL containers, with mounted files from the host, not from resources (you could also use @Test
void testMySQLExplicit() {
try (var container = new MySQLContainer<>("mysql:8.2.0-oracle")) {
// Explicit container configuration, with MountableFile.forHostPath, not .forClasspathResource
container.withCopyFileToContainer(
MountableFile.forHostPath("/Users/dgarnier/workspace/github/linghengqian/testcontainers-java-mysql-graalvm-native-test/src/test/resources/mysql-default-conf/"),
"/etc/mysql/conf.d/"
);
// Remove TC_MY_CNF config, which overrides the explicit configuration above
var params = new HashMap<String, String>();
params.put("TC_MY_CNF", null);
container.setParameters(params);
container.start();
// Manually build the JDBC url
var dbUrl = "jdbc:mysql://localhost:%s/test?user=root&password=test".formatted(container.getFirstMappedPort());
// The rest of the test is the same :)
System.out.println("Starting MySQL ...");
Awaitility.await().atMost(Duration.ofSeconds(10)).ignoreExceptionsMatching(e -> e instanceof CommunicationsException)
.until(() -> {
DriverManager.getConnection(dbUrl).close();
return true;
});
System.out.println("MySQL started");
try {
try (Connection connection = DriverManager.getConnection(dbUrl)) {
connection.createStatement().executeUpdate("CREATE DATABASE demo_ds_1;");
}
} catch (SQLException e) {
Assertions.fail();
}
}
} |
@Container
public static final GenericContainer<?> CONTAINER = new GenericContainer<>(DockerImageName.parse("mysql:9.0.1-oraclelinux9"))
.withEnv("MYSQL_DATABASE", DATABASE)
.withEnv("MYSQL_ROOT_PASSWORD", PASSWORD)
.withExposedPorts(3306);
|
tl;dr is: Testcontainers does not support native image it's only community-driven and very superficial. TC touches native-image limitations beyond what metadata can fix, and it's unlikely that your use-case will be supported. I think the only "supported" approach is to build your target "app" (a real app, not a JUnit app) into a native image, and run tests against that, in black box mode. You can possibly package the app into a container, and use TC to orchestrate dependencies. You could even build your native app under test using buildpacks, e.g. what DaShaun Carter did a while back (article) or a sample Eddú shared (github). Now the issue with TC is: From my understand, using the If you want to learn more about the limitations, I recorded my learnings in this repo: https://github.com/Kehrlann/native-image-resource-fs |
Not sure if I should keep the issue open waiting for a potential PR to open, as the testcontainers-java java api seems to have very few breaking changes. |
I don't think tc-java will make changes to accomodate these use-cases. I'll let the team confirm, cc @kiview @eddumelendez |
Module
MySQL
Testcontainers version
1.19.3
Using the latest Testcontainers version?
Yes
Host OS
Linux
Host Arch
x86
Docker version
Client: Docker Engine - Community Cloud integration: v1.0.35+desktop.5 Version: 24.0.6 API version: 1.43 Go version: go1.20.7 Git commit: ed223bc Built: Mon Sep 4 12:32:16 2023 OS/Arch: linux/amd64 Context: default Server: Docker Desktop Engine: Version: 24.0.6 API version: 1.43 (minimum version 1.12) Go version: go1.20.7 Git commit: 1a79695 Built: Mon Sep 4 12:32:16 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.22 GitCommit: 8165feabfdfe38c65b599c4993d227328c231fca runc: Version: 1.1.8 GitCommit: v1.1.8-0-g82f18fe docker-init: Version: 0.19.0 GitCommit: de40ad0
What happened?
org.testcontainers:mysql
will report an error asmysqld failed while attempting to check config
in GraalVM Native Image.SDKMAN!
.Relevant log output
Additional Information
The text was updated successfully, but these errors were encountered: