-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
JDBCDriverTest.java
231 lines (196 loc) · 11.6 KB
/
JDBCDriverTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package org.testcontainers.jdbc;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.lang.SystemUtils;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.EnumSet;
import static java.util.Arrays.asList;
import static org.junit.Assume.assumeFalse;
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;
import static org.rnorth.visibleassertions.VisibleAssertions.assertTrue;
@RunWith(Parameterized.class)
public class JDBCDriverTest {
private enum Options {
ScriptedSchema,
CharacterSet,
CustomIniFile,
JDBCParams,
PmdKnownBroken
}
@Parameter
public String jdbcUrl;
@Parameter(1)
public EnumSet<Options> options;
@Parameterized.Parameters(name = "{index} - {0}")
public static Iterable<Object[]> data() {
return asList(
new Object[][]{
{"jdbc:tc:mysql://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:mysql://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=file:sql/init_mysql.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", EnumSet.noneOf(Options.class)},
{"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:presto:329://hostname/", EnumSet.of(Options.PmdKnownBroken)},
{"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)},
{"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_unicode_mysql.sql&useUnicode=yes&characterEncoding=utf8", EnumSet.of(Options.CharacterSet)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?user=someuser&password=somepwd&TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", EnumSet.of(Options.CustomIniFile)},
{"jdbc:tc:clickhouse://hostname/databasename", EnumSet.of(Options.PmdKnownBroken)},
{"jdbc:tc:sqlserver:2017-CU12://hostname:hostport;databaseName=databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:cockroach://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:db2://hostname/databasename", EnumSet.noneOf(Options.class)}
});
}
public static void sampleInitFunction(Connection connection) throws SQLException {
connection.createStatement().execute("CREATE TABLE bar (\n" +
" foo VARCHAR(255)\n" +
");");
connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');");
connection.createStatement().execute("CREATE TABLE my_counter (\n" +
" n INT\n" +
");");
}
@AfterClass
public static void testCleanup() {
ContainerDatabaseDriver.killContainers();
}
@Test
public void test() throws SQLException {
try (HikariDataSource dataSource = getDataSource(jdbcUrl, 1)) {
performSimpleTest(dataSource);
if (options.contains(Options.ScriptedSchema)) {
performTestForScriptedSchema(dataSource);
}
if (options.contains(Options.JDBCParams)) {
performTestForJDBCParamUsage(dataSource);
}
if (options.contains(Options.CharacterSet)) {
performSimpleTestWithCharacterSet(jdbcUrl);
performTestForCharacterEncodingForInitialScriptConnection(dataSource);
}
if (options.contains(Options.CustomIniFile)) {
performTestForCustomIniFile(dataSource);
}
}
}
private void performSimpleTest(HikariDataSource dataSource) throws SQLException {
String query = "SELECT 1";
if (jdbcUrl.startsWith("jdbc:tc:db2:")) {
query = "SELECT 1 FROM SYSIBM.SYSDUMMY1";
}
boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query(query, rs -> {
rs.next();
int resultSetInt = rs.getInt(1);
assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
return true;
});
assertTrue("The database returned a record as expected", result);
}
private void performTestForScriptedSchema(HikariDataSource dataSource) throws SQLException {
boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%world'", rs -> {
rs.next();
String resultSetString = rs.getString(1);
assertEquals("A basic SELECT query succeeds where the schema has been applied from a script", "hello world", resultSetString);
return true;
});
assertTrue("The database returned a record as expected", result);
}
private void performTestForJDBCParamUsage(HikariDataSource dataSource) throws SQLException {
boolean result = new QueryRunner(dataSource).query("select CURRENT_USER", rs -> {
rs.next();
String resultUser = rs.getString(1);
// Not all databases (eg. Postgres) return @% at the end of user name. We just need to make sure the user name matches.
if (resultUser.endsWith("@%")) {
resultUser = resultUser.substring(0, resultUser.length() - 2);
}
assertEquals("User from query param is created.", "someuser", resultUser);
return true;
});
assertTrue("The database returned a record as expected", result);
String databaseQuery = "SELECT DATABASE()";
// Postgres does not have Database() as a function
String databaseType = ConnectionUrl.newInstance(jdbcUrl).getDatabaseType();
if (databaseType.equalsIgnoreCase("postgresql") || databaseType.equalsIgnoreCase("postgis")) {
databaseQuery = "SELECT CURRENT_DATABASE()";
}
result = new QueryRunner(dataSource).query(databaseQuery, rs -> {
rs.next();
String resultDB = rs.getString(1);
assertEquals("Database name from URL String is used.", "databasename", resultDB);
return true;
});
assertTrue("The database returned a record as expected", result);
}
private void performTestForCharacterEncodingForInitialScriptConnection(HikariDataSource dataSource) throws SQLException {
boolean result = new QueryRunner(dataSource).query("SELECT foo FROM bar WHERE foo LIKE '%мир'", rs -> {
rs.next();
String resultSetString = rs.getString(1);
assertEquals("A SELECT query succeed and the correct charset has been applied for the init script", "привет мир", resultSetString);
return true;
});
assertTrue("The database returned a record as expected", result);
}
/**
* This method intentionally verifies encoding twice to ensure that the query string parameters are used when
* Connections are created from cached containers.
*
* @param jdbcUrl
* @throws SQLException
*/
private void performSimpleTestWithCharacterSet(String jdbcUrl) throws SQLException {
HikariDataSource datasource1 = verifyCharacterSet(jdbcUrl);
HikariDataSource datasource2 = verifyCharacterSet(jdbcUrl);
datasource1.close();
datasource2.close();
}
private HikariDataSource verifyCharacterSet(String jdbcUrl) throws SQLException {
HikariDataSource dataSource = getDataSource(jdbcUrl, 1);
boolean result = new QueryRunner(dataSource).query("SHOW VARIABLES LIKE 'character\\_set\\_connection'", rs -> {
rs.next();
String resultSetString = rs.getString(2);
assertTrue("Passing query parameters to set DB connection encoding is successful", resultSetString.startsWith("utf8"));
return true;
});
assertTrue("The database returned a record as expected", result);
return dataSource;
}
private void performTestForCustomIniFile(HikariDataSource dataSource) throws SQLException {
assumeFalse(SystemUtils.IS_OS_WINDOWS);
Statement statement = dataSource.getConnection().createStatement();
statement.execute("SELECT @@GLOBAL.innodb_file_format");
ResultSet resultSet = statement.getResultSet();
assertTrue("The query returns a result", resultSet.next());
String result = resultSet.getString(1);
assertEquals("The InnoDB file format has been set by the ini file content", "Barracuda", result);
}
private HikariDataSource getDataSource(String jdbcUrl, int poolSize) {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(jdbcUrl);
hikariConfig.setConnectionTestQuery("SELECT 1");
hikariConfig.setMinimumIdle(1);
hikariConfig.setMaximumPoolSize(poolSize);
return new HikariDataSource(hikariConfig);
}
}