Repository navigation
COG-1141: Testcontainers MySQL harness for @SpringBootTest (Boot 1.5.4 / Java 8) #335
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
Open
patrickbradley-cog
wants to merge
4
commits into
master
Choose a base branch
from
devin/cog-1141-w0-testcontainers-mysql-harness-for-springboottest-boot-154
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
3672d0e
COG-1141: Testcontainers MySQL harness for @SpringBootTest (Boot 1.5.…
devin-ai-integration[bot] ecbe4c5
COG-1141: cap Docker API version at the daemon's maximum
devin-ai-integration[bot] c129a88
COG-1141: default harness to mysql:5.7.44 until the Connector/J upgrade
devin-ai-integration[bot] ba5a6c0
COG-1141: query the default Docker context when DOCKER_HOST is unset
devin-ai-integration[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
UserFront/src/test/java/com/userFront/AbstractIntegrationTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| package com.userFront; | ||
|
|
||
| import java.io.BufferedReader; | ||
| import java.io.IOException; | ||
| import java.io.InputStreamReader; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import org.junit.runner.RunWith; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.boot.test.util.EnvironmentTestUtils; | ||
| import org.springframework.context.ApplicationContextInitializer; | ||
| import org.springframework.context.ConfigurableApplicationContext; | ||
| import org.springframework.test.context.ContextConfiguration; | ||
| import org.springframework.test.context.junit4.SpringRunner; | ||
| import org.springframework.test.web.servlet.MockMvc; | ||
| import org.testcontainers.containers.MySQLContainer; | ||
| import org.testcontainers.utility.DockerImageName; | ||
|
|
||
| /** | ||
| * Entry point for the UserFront smoke suite: every {@code @SpringBootTest} extends this class. | ||
| * | ||
| * <p>Boots the whole application against a MySQL Testcontainer, so {@code mvn verify} needs only | ||
| * Docker, not a local MySQL. A single container is started once per JVM and its JDBC coordinates | ||
| * are pushed into the environment by {@link DataSourceInitializer} before the context refreshes | ||
| * ({@code spring-boot-testcontainers} / {@code @ServiceConnection} only exist from Boot 3.1). | ||
| * The schema is created from the JPA entities with {@code spring.jpa.hibernate.ddl-auto=update}. | ||
| * | ||
| * <p>The image defaults to {@value #DEFAULT_MYSQL_IMAGE} and can be overridden with | ||
| * {@code -Dtest.mysql.image=...}. It stays on MySQL 5.7 because the Boot 1.5 BOM ships | ||
| * Connector/J 5.1.42, which cannot connect to MySQL 8 ({@code Unknown system variable | ||
| * 'query_cache_size'}) or authenticate with {@code caching_sha2_password}; move to the production | ||
| * major version (8.0) together with the Connector/J upgrade. {@code useSSL=false} is appended to | ||
| * the JDBC URL because current JDK 8 builds disable the TLSv1/1.1 that Connector/J 5.1 negotiates. | ||
| * | ||
| * <p>Subclasses get an autoconfigured {@link MockMvc} (with the Spring Security filter chain) | ||
| * as {@link #mockMvc}. | ||
| */ | ||
| @RunWith(SpringRunner.class) | ||
| @SpringBootTest(classes = UserFrontApplication.class) | ||
| @AutoConfigureMockMvc | ||
| @ContextConfiguration(initializers = AbstractIntegrationTest.DataSourceInitializer.class) | ||
| public abstract class AbstractIntegrationTest { | ||
|
|
||
| public static final String DEFAULT_MYSQL_IMAGE = "mysql:5.7.44"; | ||
|
|
||
| /** Docker Engine 25+ rejects the API 1.32 that Testcontainers 1.19.x requests by default. */ | ||
| private static final String PREFERRED_DOCKER_API_VERSION = "1.44"; | ||
|
|
||
| static { | ||
| if (System.getProperty("api.version") == null && System.getenv("DOCKER_API_VERSION") == null) { | ||
| System.setProperty("api.version", dockerApiVersion()); | ||
| } | ||
|
devin-ai-integration[bot] marked this conversation as resolved.
Resolved
|
||
| } | ||
|
|
||
| protected static final MySQLContainer<?> MYSQL = new MySQLContainer<>( | ||
| DockerImageName.parse(System.getProperty("test.mysql.image", DEFAULT_MYSQL_IMAGE)) | ||
| .asCompatibleSubstituteFor("mysql")) | ||
| .withDatabaseName("onlinebanking") | ||
| .withUrlParam("useSSL", "false"); | ||
|
|
||
| static { | ||
| MYSQL.start(); | ||
| } | ||
|
|
||
| @Autowired | ||
| protected MockMvc mockMvc; | ||
|
|
||
| /** | ||
| * {@value #PREFERRED_DOCKER_API_VERSION}, capped at the daemon's maximum API version (as | ||
| * reported by the {@code docker} CLI) so older engines such as Docker 24 (API 1.43) still work. | ||
| * Without {@code DOCKER_HOST} the CLI is pinned to the {@code default} context, i.e. the local | ||
| * socket Testcontainers falls back to, rather than whatever context the CLI has selected. | ||
| */ | ||
| private static String dockerApiVersion() { | ||
| List<String> command = new ArrayList<>(Arrays.asList("docker", "version", "--format", "{{.Server.APIVersion}}")); | ||
| if (System.getenv("DOCKER_HOST") == null) { | ||
| command.addAll(1, Arrays.asList("--context", "default")); | ||
| } | ||
| try { | ||
| Process process = new ProcessBuilder(command) | ||
| .redirectErrorStream(true) | ||
| .start(); | ||
| if (!process.waitFor(10, TimeUnit.SECONDS)) { | ||
| process.destroyForcibly(); | ||
| return PREFERRED_DOCKER_API_VERSION; | ||
| } | ||
| try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { | ||
| String serverMax = reader.readLine(); | ||
| if (process.exitValue() == 0 && serverMax != null && serverMax.trim().matches("\\d+\\.\\d+")) { | ||
| return compareApiVersions(serverMax.trim(), PREFERRED_DOCKER_API_VERSION) < 0 | ||
| ? serverMax.trim() | ||
| : PREFERRED_DOCKER_API_VERSION; | ||
| } | ||
| } | ||
| } | ||
| catch (IOException e) { | ||
| // No docker CLI on the PATH: fall back to the preferred version. | ||
| } | ||
| catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| } | ||
| return PREFERRED_DOCKER_API_VERSION; | ||
| } | ||
|
|
||
| private static int compareApiVersions(String a, String b) { | ||
| String[] x = a.split("\\."); | ||
| String[] y = b.split("\\."); | ||
| int major = Integer.compare(Integer.parseInt(x[0]), Integer.parseInt(y[0])); | ||
| return major != 0 ? major : Integer.compare(Integer.parseInt(x[1]), Integer.parseInt(y[1])); | ||
| } | ||
|
|
||
| public static class DataSourceInitializer | ||
| implements ApplicationContextInitializer<ConfigurableApplicationContext> { | ||
|
|
||
| @Override | ||
| public void initialize(ConfigurableApplicationContext applicationContext) { | ||
| EnvironmentTestUtils.addEnvironment(applicationContext, | ||
| "spring.datasource.url=" + MYSQL.getJdbcUrl(), | ||
| "spring.datasource.username=" + MYSQL.getUsername(), | ||
| "spring.datasource.password=" + MYSQL.getPassword(), | ||
| "spring.datasource.driver-class-name=" + MYSQL.getDriverClassName(), | ||
| "spring.jpa.hibernate.ddl-auto=update"); | ||
| } | ||
| } | ||
| } | ||
7 changes: 1 addition & 6 deletions
7
UserFront/src/test/java/com/userFront/UserFrontApplicationTests.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.