testcontainers-java
testcontainers-java copied to clipboard
Support hikari data-source-properties in ContainerDatabaseDriver
I tried to use test containers with hikari data-source-properties in Spring Boot like this:
spring:
datasource:
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
url: jdbc:tc:mysql:5.7.22://testcontainers/hi_perf_java_pers #?rewriteBatchedStatements=true&profileSQL=true&logger=com.mysql.cj.log.Slf4JLogger
hikari:
data-source-properties:
rewriteBatchedStatements: true
profileSQL: true
logger: com.mysql.cj.log.Slf4JLogger
But datasource properties are ignored by connect method inside ContainerDatabaseDriver (info parameter in method connect).
Workaround so far is to include properties directly into connection string (commented part in url #?rewriteBatched...).
MySQL driver is doing it in this way:
/**
* Builds a connection URL cache map key based on the connection string itself plus the string representation of the given connection properties.
*
* @param connString
* the connection string
* @param info
* the connection arguments map
* @return a connection string cache map key
*/
private static String buildConnectionStringCacheKey(String connString, Properties info) {
StringBuilder sbKey = new StringBuilder(connString);
sbKey.append("\u00A7"); // Section sign.
sbKey.append(
info == null ? null : info.stringPropertyNames().stream().map(k -> k + "=" + info.getProperty(k)).collect(Collectors.joining(", ", "{", "}")));
return sbKey.toString();
}
You are right, I changed the phrasing of the title to make this more into a feature request. Would this be a Hikari specific feature?
AFAIK this is JDBC feature.
I don't think there is a way to set generic properties on a JDBC connection, could you point me to the documentation?
Also this is a Spring-Boot-Hikari specific thing IMO, so maybe we should check in the Spring-Boot code what happens with the Hikari object etc.
smth like this?
Properties props = new Properties();
props.setProperty("user", "dbuser");
props.setProperty("password", "dbpassword");
props.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CONNECT_TIMEOUT, "2000");
Connection con = DriverManager.getConnection("<JDBC connection string>", props);
Oh you are right, great. We should be able to use this somehow: https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html#getConnection-java.lang.String-java.util.Properties-
Hi,
I would like to contribute and fix this issue, but, I'm not sure on the fix.
Can we agree that the modification here is to actually use info param from this method:
https://github.com/testcontainers/testcontainers-java/blob/0044218c722c174d1968c5a5e933edb5efb5ceca/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java#L64
into that call : https://github.com/testcontainers/testcontainers-java/blob/0044218c722c174d1968c5a5e933edb5efb5ceca/modules/jdbc/src/main/java/org/testcontainers/jdbc/ContainerDatabaseDriver.java#L124
which means updating this method signature (or adding a new one) to accept Properties info and merge username and password to it:
https://github.com/testcontainers/testcontainers-java/blob/0044218c722c174d1968c5a5e933edb5efb5ceca/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java#L185-L188
Am I right?
Do you know how could I test this ?
Any progress on this?
Hi @kiview, We have a similar requirement and based on my understanding we need to fix this in two places:
Changes to cache URL
We need to make sure the cache URL is formed using the properties, which would a change to ContainerDatabaseDriver.java.
- Reuse MySQL
buildConnectionStringCacheKey()method to create the connection URL, based on URL + JDBC properties:
private static String buildConnectionStringCacheKey(String connString, Properties info) {
StringBuilder sbKey = new StringBuilder(connString);
sbKey.append("\u00A7"); // Section sign.
sbKey.append(
info == null ? null : info.stringPropertyNames().stream().map(k -> k + "=" + info.getProperty(k)).collect(Collectors.joining(", ", "{", "}")));
return sbKey.toString();
}
- Update the following line of code in
ContainerDatabaseDriver.connect(String url, final Properties info)to create the cache URL based on (URL+Properties) instead of just URL:
// New changes to build connection string based on (URL + connection properties) instead of just using the URL
final String cacheUrl = buildConnectionStringCacheKey(url, info);
ConnectionUrl connectionUrl = ConnectionUrl.newInstance(cacheUrl);
Pass in properties to JDBC connector
- Method signature of
JdbcDatabaseContainer.createConnection(String queryString)should get updated toJdbcDatabaseContainer.createConnection(String queryString, Properties info)in order to accept connection properties. - Merge the passed in connection properties with the temp properties created inside the function so user defined JDBC properties gets sent in to the new connection object
final Properties info = new Properties();
info.put("user", this.getUsername());
info.put("password", this.getPassword());
Let me know your thoughts and if you are fine with this approach I can work on the changes and send in a PR shortly. Thanks.
Hi, I'm willing to work on this issue.
Hi, can you give me a chance to crack this?