Skip to content

Commit d902dc9

Browse files
authoredFeb 27, 2024··
Enhancements to the MySQL support (#532)
* Use the MySQL official image * Resolve the X Protocol URL * Add docs and bump version * Fix Checkstyle
1 parent d13c99b commit d902dc9

File tree

9 files changed

+93
-42
lines changed

9 files changed

+93
-42
lines changed
 

‎gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
projectVersion=2.4.0-SNAPSHOT
1+
projectVersion=2.5.0-SNAPSHOT
22
projectGroup=io.micronaut.testresources
33

44
title=Micronaut Test Resources

‎settings.gradle

-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ micronautBuild {
111111
importMicronautCatalog("micronaut-elasticsearch")
112112
importMicronautCatalog("micronaut-email")
113113
importMicronautCatalog("micronaut-kafka")
114-
importMicronautCatalog("micronaut-logging")
115114
importMicronautCatalog("micronaut-mongodb")
116115
importMicronautCatalog("micronaut-mqtt")
117116
importMicronautCatalog("micronaut-neo4j")

‎src/main/docs/guide/modules-databases-jdbc.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The following properties will automatically be set when using a JDBC database:
55
- `datasources.*.password`
66
- `datasources.*.dialect`
77
8+
Additionally, the MySQL resolver will automatically set the property `datasources.*.x-protocol-url` to be used with the
9+
https://dev.mysql.com/doc/connector-j/en/connector-j-using-xdevapi.html[MySQL X DevAPI].
10+
811
In order for the database to be properly detected, _one of_ the following properties has to be set:
912

1013
- `datasources.*.db-type`: the kind of database (preferred, one of `mariadb`, `mysql`, `oracle`, `postgres`)

‎src/main/docs/guide/modules-databases.adoc

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ Micronaut Test Resources provides support for the following databases:
66
|===
77
|Database | JDBC | R2DBC | Database identifier | Default image
88

9-
| https://mariadb.org/[MariaDB] | Yes | Yes | mariadb | mariadb
10-
| https://www.mysql.com/[MySQL] | Yes | Yes | mysql | mysql
11-
| https://www.oracle.com/database/[Oracle Database] | Yes | Yes | oracle | gvenzl/oracle-xe:slim-faststart
12-
| https://www.postgresql.org/[PostgreSQL] | Yes | Yes | postgres | postgres
13-
| https://www.microsoft.com/sql-server[Microsoft SQL Server] | Yes | Yes | mssql | mcr.microsoft.com/mssql/server:2019-CU16-GDR1-ubuntu-20.04
9+
| https://mariadb.org/[MariaDB] | Yes | Yes | `mariadb` | `mariadb`
10+
| https://www.mysql.com/[MySQL] | Yes | Yes | `mysql` | `container-registry.oracle.com/mysql/community-server`
11+
| https://www.oracle.com/database/[Oracle Database] | Yes | Yes | `oracle` | `gvenzl/oracle-xe:slim-faststart`
12+
| https://www.postgresql.org/[PostgreSQL] | Yes | Yes | `postgres` | `postgres`
13+
| https://www.microsoft.com/sql-server[Microsoft SQL Server] | Yes | Yes | `mssql` | `mcr.microsoft.com/mssql/server:2019-CU16-GDR1-ubuntu-20.04`
1414

1515
|===
1616

‎test-resources-elasticsearch/src/main/java/io/micronaut/testresources/elasticsearch/ElasticsearchTestResourceProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class ElasticsearchTestResourceProvider extends AbstractTestContainersPro
3434
public static final String SIMPLE_NAME = "elasticsearch";
3535
public static final String DEFAULT_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch";
3636
public static final String DEFAULT_TAG = "8.4.3";
37-
public static final String DISPLAY_NAME = "kafka";
37+
public static final String DISPLAY_NAME = "Elasticsearch";
3838

3939
@Override
4040
public List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {

‎test-resources-jdbc/test-resources-jdbc-core/src/main/java/io/micronaut/testresources/jdbc/AbstractJdbcTestResourceProvider.java

+12-29
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@
1818
import io.micronaut.testresources.testcontainers.AbstractTestContainersProvider;
1919
import org.testcontainers.containers.JdbcDatabaseContainer;
2020

21-
import java.util.Arrays;
2221
import java.util.Collection;
2322
import java.util.Collections;
2423
import java.util.List;
2524
import java.util.Map;
2625
import java.util.Optional;
2726
import java.util.function.Consumer;
28-
import java.util.stream.Collectors;
2927
import java.util.stream.Stream;
3028

3129
/**
@@ -34,7 +32,7 @@
3432
* @param <T> the type of the container
3533
*/
3634
public abstract class AbstractJdbcTestResourceProvider<T extends JdbcDatabaseContainer<? extends T>> extends AbstractTestContainersProvider<T> {
37-
private static final String PREFIX = "datasources";
35+
public static final String PREFIX = "datasources";
3836
private static final String URL = "url";
3937
private static final String USERNAME = "username";
4038
private static final String PASSWORD = "password";
@@ -45,9 +43,7 @@ public abstract class AbstractJdbcTestResourceProvider<T extends JdbcDatabaseCon
4543

4644
private static final String TYPE = "db-type";
4745

48-
private static final List<String> SUPPORTED_LIST = Collections.unmodifiableList(
49-
Arrays.asList(URL, USERNAME, PASSWORD, DRIVER)
50-
);
46+
private static final List<String> SUPPORTED_LIST = List.of(URL, USERNAME, PASSWORD, DRIVER);
5147

5248
/**
5349
* Returns the list of db-types supported by this provider.
@@ -62,7 +58,7 @@ public List<String> getResolvableProperties(Map<String, Collection<String>> prop
6258
Collection<String> datasources = propertyEntries.getOrDefault(PREFIX, Collections.emptyList());
6359
return datasources.stream()
6460
.flatMap(ds -> SUPPORTED_LIST.stream().map(p -> PREFIX + "." + ds + "." + p))
65-
.collect(Collectors.toList());
61+
.toList();
6662
}
6763

6864
@Override
@@ -79,7 +75,7 @@ public List<String> getRequiredProperties(String expression) {
7975
return Stream.of(
8076
datasourceExpressionOf(datasource, TYPE),
8177
datasourceExpressionOf(datasource, DIALECT)
82-
).collect(Collectors.toList());
78+
).toList();
8379
}
8480

8581
@Override
@@ -93,31 +89,18 @@ protected boolean shouldAnswer(String propertyName, Map<String, Object> requeste
9389
return getDbTypes().stream().anyMatch(type::equalsIgnoreCase);
9490
}
9591
String dialect = stringOrNull(requestedProperties.get(datasourceExpressionOf(datasource, DIALECT)));
96-
if (dialect != null && dialect.equalsIgnoreCase(getSimpleName())) {
97-
return true;
98-
}
99-
return false;
92+
return dialect != null && dialect.equalsIgnoreCase(getSimpleName());
10093
}
10194

10295
@Override
10396
protected Optional<String> resolveProperty(String expression, T container) {
104-
String value;
105-
switch (datasourcePropertyFrom(expression)) {
106-
case URL:
107-
value = container.getJdbcUrl();
108-
break;
109-
case USERNAME:
110-
value = container.getUsername();
111-
break;
112-
case PASSWORD:
113-
value = container.getPassword();
114-
break;
115-
case DRIVER:
116-
value = container.getDriverClassName();
117-
break;
118-
default:
119-
value = resolveDbSpecificProperty(expression, container);
120-
}
97+
String value = switch (datasourcePropertyFrom(expression)) {
98+
case URL -> container.getJdbcUrl();
99+
case USERNAME -> container.getUsername();
100+
case PASSWORD -> container.getPassword();
101+
case DRIVER -> container.getDriverClassName();
102+
default -> resolveDbSpecificProperty(expression, container);
103+
};
121104
return Optional.ofNullable(value);
122105
}
123106

‎test-resources-jdbc/test-resources-jdbc-mysql/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Provides support for launching a MySQL test container.
99
dependencies {
1010
implementation(libs.managed.testcontainers.mysql)
1111

12-
testRuntimeOnly(mnSql.mysql.connector.java)
12+
testImplementation(mnSql.mysql.connector.java)
1313
}

‎test-resources-jdbc/test-resources-jdbc-mysql/src/main/java/io/micronaut/testresources/mysql/MySQLTestResourceProvider.java

+46-2
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,26 @@
1616
package io.micronaut.testresources.mysql;
1717

1818
import io.micronaut.testresources.jdbc.AbstractJdbcTestResourceProvider;
19+
import org.testcontainers.containers.JdbcDatabaseContainer;
1920
import org.testcontainers.containers.MySQLContainer;
2021
import org.testcontainers.utility.DockerImageName;
2122

23+
import java.util.ArrayList;
24+
import java.util.Collection;
25+
import java.util.Collections;
26+
import java.util.List;
2227
import java.util.Map;
2328

2429
/**
2530
* A test resource provider which will spawn a MySQL test container.
2631
*/
2732
public class MySQLTestResourceProvider extends AbstractJdbcTestResourceProvider<MySQLContainer<?>> {
2833
public static final String DISPLAY_NAME = "MySQL";
34+
public static final String MYSQL_OFFICIAL_IMAGE = "container-registry.oracle.com/mysql/community-server";
35+
public static final String DOCKER_OFFICIAL_IMAGE = "mysql";
36+
public static final String SIMPLE_NAME = MySQLContainer.NAME;
37+
public static final String X_PROTOCOL_URL = "x-protocol-url";
38+
public static final int DEFAULT_X_PROTOCOL_PORT = 33060;
2939

3040
@Override
3141
public String getDisplayName() {
@@ -34,17 +44,51 @@ public String getDisplayName() {
3444

3545
@Override
3646
protected String getSimpleName() {
37-
return "mysql";
47+
return SIMPLE_NAME;
3848
}
3949

4050
@Override
4151
protected String getDefaultImageName() {
42-
return "mysql";
52+
return MYSQL_OFFICIAL_IMAGE;
4353
}
4454

4555
@Override
4656
protected MySQLContainer<?> createContainer(DockerImageName imageName, Map<String, Object> requestedProperties, Map<String, Object> testResourcesConfig) {
57+
// Testcontainers uses by default the Docker Hub official image, so the MySQL official image needs to be set as compatible substitute
58+
if (imageName.asCanonicalNameString().startsWith(MYSQL_OFFICIAL_IMAGE)) {
59+
imageName = imageName.asCompatibleSubstituteFor(DOCKER_OFFICIAL_IMAGE);
60+
}
4761
return new MySQLContainer<>(imageName);
4862
}
4963

64+
@Override
65+
protected void configureContainer(MySQLContainer<?> container, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
66+
container.withExposedPorts(MySQLContainer.MYSQL_PORT, DEFAULT_X_PROTOCOL_PORT);
67+
}
68+
69+
@Override
70+
public List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
71+
List<String> resolvableProperties = new ArrayList<>(super.getResolvableProperties(propertyEntries, testResourcesConfig));
72+
Collection<String> datasources = propertyEntries.getOrDefault(PREFIX, Collections.emptyList());
73+
List<String> properties = datasources.stream()
74+
.map(ds -> PREFIX + "." + ds + "." + X_PROTOCOL_URL)
75+
.toList();
76+
resolvableProperties.addAll(properties);
77+
return resolvableProperties;
78+
}
79+
80+
@Override
81+
protected String resolveDbSpecificProperty(String propertyName, JdbcDatabaseContainer<?> container) {
82+
if (X_PROTOCOL_URL.equals(propertyName.substring(propertyName.lastIndexOf(".") + 1))) {
83+
String username = container.getUsername();
84+
String password = container.getPassword();
85+
String host = container.getHost();
86+
String port = String.valueOf(container.getMappedPort(DEFAULT_X_PROTOCOL_PORT));
87+
String schema = container.getDatabaseName();
88+
89+
return "mysqlx://%s:%s@%s:%s/%s".formatted(username, password, host, port, schema);
90+
} else {
91+
return super.resolveDbSpecificProperty(propertyName, container);
92+
}
93+
}
5094
}

‎test-resources-jdbc/test-resources-jdbc-mysql/src/test/groovy/io/micronaut/testresources/jdbc/mysql/StartMySQLTest.groovy

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package io.micronaut.testresources.jdbc.mysql
22

3+
import com.mysql.cj.xdevapi.SessionFactory
4+
import io.micronaut.context.env.Environment
35
import io.micronaut.test.extensions.spock.annotation.MicronautTest
46
import io.micronaut.testresources.jdbc.AbstractJDBCSpec
57
import io.micronaut.testresources.jdbc.Book
8+
import io.micronaut.testresources.mysql.MySQLTestResourceProvider
69
import jakarta.inject.Inject
710

811
@MicronautTest
912
class StartMySQLTest extends AbstractJDBCSpec {
13+
1014
@Inject
1115
MySQLBookRepository repository
1216

13-
def "starts a MySQL container"() {
17+
@Inject
18+
Environment environment
19+
20+
void "starts a MySQL container"() {
21+
given:
1422
def book = new Book(title: "Micronaut for Spring developers")
1523
repository.save(book)
1624

@@ -21,8 +29,22 @@ class StartMySQLTest extends AbstractJDBCSpec {
2129
books.size() == 1
2230
}
2331

32+
void "resolves the X Protocol URL"() {
33+
given:
34+
def xProtocolUrl = environment.getRequiredProperty("datasources.default.x-protocol-url", String)
35+
36+
when:
37+
def session = new SessionFactory().getSession(xProtocolUrl)
38+
39+
then:
40+
session.isOpen()
41+
42+
cleanup:
43+
session.close()
44+
}
45+
2446
@Override
2547
String getImageName() {
26-
"mysql"
48+
MySQLTestResourceProvider.MYSQL_OFFICIAL_IMAGE
2749
}
2850
}

0 commit comments

Comments
 (0)
Please sign in to comment.