Skip to content

Commit 758db80

Browse files
committed
Enhancements and Fixes around JDBC URL Based Containers
(Rebased and Squashed)
1 parent 3b974e9 commit 758db80

File tree

10 files changed

+525
-106
lines changed

10 files changed

+525
-106
lines changed

.gitignore

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ node_modules/
4747
.gradle/
4848
build/
4949

50-
# Eclipse IDE
51-
.settings/
52-
.classpath
53-
.project
54-
bin/
50+
# Eclipse IDE files
51+
**/.project
52+
**/.classpath
53+
**/.settings
54+
**/bin/
55+
**/out/

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ All notable changes to this project will be documented in this file.
44
## UNRELEASED
55

66
### Fixed
7+
- Fixed JDBC URL Regex Pattern to ensure all supported Database URL's are accepted ([\#596](https://github.com/testcontainers/testcontainers-java/issues/596))
8+
- Filtered out TestContainer parameters (TC_*) from query string before passing to database ([\#345](https://github.com/testcontainers/testcontainers-java/issues/345))
79

810
### Changed
911
- Allow `HttpWaitStrategy` to wait for a specific port ([\#703](https://github.com/testcontainers/testcontainers-java/pull/703))
1012
- New module: Apache Pulsar ([\#713](https://github.com/testcontainers/testcontainers-java/pull/713))
1113
- Add support for defining container labels ([\#725](https://github.com/testcontainers/testcontainers-java/pull/725))
1214
- Use `quay.io/testcontainers/ryuk` instead of `bsideup/ryuk` ([\#721](https://github.com/testcontainers/testcontainers-java/pull/721))
1315
- Added Couchbase module ([\#688](https://github.com/testcontainers/testcontainers-java/pull/688))
16+
- Enhancements and Fixes for JDBC URL usage to create Containers ([\#594](https://github.com/testcontainers/testcontainers-java/pull/594))
17+
- Extracted JDBC URL manipulations to a separate class - `ConnectionUrl`.
18+
- Added an overloaded method `JdbcDatabaseContainerProvider.newInstance(ConnectionUrl)`, with default implementation delegating to the existing `newInstance(tag)` method. (Relates to [\#566](https://github.com/testcontainers/testcontainers-java/issues/566))
19+
- Added an implementation of `MySQLContainerProvider.newInstance(ConnectionUrl)` that uses Database Name, User, and Password from JDBC URL while creating new MySQL Container. ([\#566](https://github.com/testcontainers/testcontainers-java/issues/566) for MySQL Container)
1420

1521
## [1.7.3] - 2018-05-16
1622

circle.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ jobs:
1919
- checkout
2020
- run:
2121
command: ./gradlew check -x testcontainers:check -x selenium:check -x jdbc-test:check
22-
environment:
23-
# Oracle JDBC drivers require a timezone to be set
24-
TZ: "/usr/share/zoneinfo/ETC/UTC"
2522
- run:
2623
name: Save test results
2724
command: |

modules/jdbc-test/src/test/java/org/testcontainers/jdbc/JDBCDriverTest.java

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,29 @@ public class JDBCDriverTest {
3232
public boolean performTestForCharacterSet;
3333
@Parameter(3)
3434
public boolean performTestForCustomIniFile;
35+
@Parameter(4)
36+
public boolean performTestForJDBCParams;
3537

3638
@Parameterized.Parameters(name = "{index} - {0}")
3739
public static Iterable<Object[]> data() {
3840
return asList(
3941
new Object[][]{
40-
{"jdbc:tc:mysql://hostname/databasename", false, false, false},
41-
{"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql", true, false, false},
42-
{"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
43-
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
44-
{"jdbc:tc:mysql:5.5.43://hostname/databasename", false, false, false},
45-
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", false, false, false},
46-
{"jdbc:tc:postgresql:9.6.8://hostname/databasename", false, false, false},
47-
{"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", false, false, true},
48-
{"jdbc:tc:mariadb://hostname/databasename", false, false, false},
49-
{"jdbc:tc:mariadb:10.2.14://hostname/databasename", false, false, false},
50-
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
51-
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_mariadb.sql", true, false, false},
52-
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
53-
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", false, false, true}
54-
});
42+
{"jdbc:tc:mysql://hostname/databasename", false, false, false, false},
43+
{"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", true, false, false, true},
44+
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false, true},
45+
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", true, false, false, true},
46+
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false, true},
47+
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false, false},
48+
{"jdbc:tc:mysql:5.5.43://hostname/databasename", false, false, false, false},
49+
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", false, false, false, false},
50+
{"jdbc:tc:postgresql:9.6.8://hostname/databasename", false, false, false, false},
51+
{"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", false, false, true, false},
52+
{"jdbc:tc:mariadb://hostname/databasename", false, false, false, false},
53+
{"jdbc:tc:mariadb:10.2.14://hostname/databasename", false, false, false, false},
54+
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false, false},
55+
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_mariadb.sql", true, false, false, false},
56+
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false, false},
57+
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", false, false, true, false}});
5558
}
5659

5760
public static void sampleInitFunction(Connection connection) throws SQLException {
@@ -77,7 +80,14 @@ public void test() throws SQLException {
7780
performTestForScriptedSchema(jdbcUrl);
7881
}
7982

83+
if (performTestForJDBCParams) {
84+
performTestForJDBCParamUsage(jdbcUrl);
85+
}
86+
8087
if (performTestForCharacterSet) {
88+
//Called twice to ensure that the query string parameters are used when
89+
//connections are created from cached containers.
90+
performSimpleTestWithCharacterSet(jdbcUrl);
8191
performSimpleTestWithCharacterSet(jdbcUrl);
8292
}
8393

@@ -107,25 +117,57 @@ private void performTestForScriptedSchema(String jdbcUrl) throws SQLException {
107117
assertEquals("A basic SELECT query succeeds where the schema has been applied from a script", "hello world", resultSetString);
108118
return true;
109119
});
110-
111-
assertTrue("The database returned a record as expected", result);
112-
113120
}
114121
}
115122

116-
private void performSimpleTestWithCharacterSet(String jdbcUrl) throws SQLException {
123+
private void performTestForJDBCParamUsage(String jdbcUrl) throws SQLException {
117124
try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) {
118-
boolean result = new QueryRunner(dataSource).query("SHOW VARIABLES LIKE 'character\\_set\\_connection'", rs -> {
125+
boolean result = new QueryRunner(dataSource).query("select CURRENT_USER()", rs -> {
126+
rs.next();
127+
String resultUser = rs.getString(1);
128+
assertEquals("User from query param is created.", "someuser@%", resultUser);
129+
return true;
130+
});
131+
132+
result = new QueryRunner(dataSource).query("SELECT DATABASE()", rs -> {
119133
rs.next();
120-
String resultSetInt = rs.getString(2);
121-
assertEquals("Passing query parameters to set DB connection encoding is successful", "utf8", resultSetInt);
134+
String resultDB = rs.getString(1);
135+
assertEquals("Database name from URL String is used.", "databasename", resultDB);
122136
return true;
123137
});
124138

125139
assertTrue("The database returned a record as expected", result);
140+
126141
}
127142
}
128143

144+
/**
145+
* This method intentionally verifies encoding twice to ensure that the query string parameters are used when
146+
* Connections are created from cached containers.
147+
*
148+
* @param jdbcUrl
149+
* @throws SQLException
150+
*/
151+
private void performSimpleTestWithCharacterSet(String jdbcUrl) throws SQLException {
152+
HikariDataSource datasource1 = verifyCharacterSet(jdbcUrl);
153+
HikariDataSource datasource2 = verifyCharacterSet(jdbcUrl);
154+
datasource1.close();
155+
datasource2.close();
156+
}
157+
158+
private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException {
159+
HikariDataSource dataSource = getDataSource(jdbcUrl, 1);
160+
boolean result = new QueryRunner(dataSource).query("SHOW VARIABLES LIKE 'character\\_set\\_connection'", rs -> {
161+
rs.next();
162+
String resultSetInt = rs.getString(2);
163+
assertEquals("Passing query parameters to set DB connection encoding is successful", "utf8", resultSetInt);
164+
return true;
165+
});
166+
167+
assertTrue("The database returned a record as expected", result);
168+
return dataSource;
169+
}
170+
129171
private void performTestForCustomIniFile(final String jdbcUrl) throws SQLException {
130172
assumeFalse(SystemUtils.IS_OS_WINDOWS);
131173
try (HikariDataSource ds = getDataSource(jdbcUrl, 1)) {
Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.testcontainers.containers;
22

3+
import org.testcontainers.jdbc.ConnectionUrl;
4+
35
import lombok.extern.slf4j.Slf4j;
46

57
/**
@@ -8,14 +10,43 @@
810
@Slf4j
911
public abstract class JdbcDatabaseContainerProvider {
1012

13+
/**
14+
* Tests if the specified database type is supported by this Container Provider. It should match to the base image name.
15+
* @param databaseType {@link String}
16+
* @return <code>true</code> when provider can handle this database type, else <code>false</code>.
17+
*/
1118
public abstract boolean supports(String databaseType);
1219

20+
/**
21+
* Instantiate a new {@link JdbcDatabaseContainer} with specified image tag.
22+
* @param tag
23+
* @return Instance of {@link JdbcDatabaseContainer}
24+
*/
25+
public abstract JdbcDatabaseContainer newInstance(String tag);
26+
27+
/**
28+
* Instantiate a new {@link JdbcDatabaseContainer} without any specified image tag. Subclasses <i>should</i>
29+
* override this method if possible, to provide a default tag that is more stable than <code>latest</code>`.
30+
*
31+
* @return Instance of {@link JdbcDatabaseContainer}
32+
*/
1333
public JdbcDatabaseContainer newInstance() {
1434
log.warn("No explicit version tag was provided in JDBC URL and this class ({}) does not " +
1535
"override newInstance() to set a default tag. `latest` will be used but results may " +
1636
"be unreliable!", this.getClass().getCanonicalName());
1737
return this.newInstance("latest");
1838
}
1939

20-
public abstract JdbcDatabaseContainer newInstance(String tag);
40+
/**
41+
* Instantiate a new {@link JdbcDatabaseContainer} using information provided with {@link ConnectionUrl}.
42+
* @param url {@link ConnectionUrl}
43+
* @return Instance of {@link JdbcDatabaseContainer}
44+
*/
45+
public JdbcDatabaseContainer newInstance(ConnectionUrl url) {
46+
if (url.getImageTag().isPresent()) {
47+
return newInstance(url.getImageTag().get());
48+
} else {
49+
return newInstance();
50+
}
51+
}
2152
}

0 commit comments

Comments
 (0)