testcontainers-java icon indicating copy to clipboard operation
testcontainers-java copied to clipboard

Support hikari data-source-properties in ContainerDatabaseDriver

Open bojanv55 opened this issue 6 years ago • 8 comments

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();
    }

bojanv55 avatar Jun 09 '19 20:06 bojanv55

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?

kiview avatar Jun 24 '19 06:06 kiview

AFAIK this is JDBC feature.

bojanv55 avatar Jun 24 '19 07:06 bojanv55

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.

kiview avatar Jun 24 '19 09:06 kiview

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);

bojanv55 avatar Jun 24 '19 12:06 bojanv55

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-

kiview avatar Jun 25 '19 07:06 kiview

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 ?

glefloch avatar Aug 28 '19 06:08 glefloch

Any progress on this?

s-jepsen avatar Sep 02 '22 04:09 s-jepsen

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.

  1. 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();
}
  1. 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

  1. Method signature of JdbcDatabaseContainer.createConnection(String queryString) should get updated to JdbcDatabaseContainer.createConnection(String queryString, Properties info) in order to accept connection properties.
  2. 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.

hariohmprasath avatar Sep 19 '22 06:09 hariohmprasath

Hi, I'm willing to work on this issue.

roulpriya avatar Oct 09 '22 12:10 roulpriya

Hi, can you give me a chance to crack this?

Kamveno avatar Sep 26 '23 18:09 Kamveno