0
# Provider Pattern
1
2
Factory pattern implementation for creating MySQL containers from connection URLs and configuration objects, supporting integration with Testcontainers JDBC URL pattern and programmatic container creation.
3
4
## Capabilities
5
6
### MySQLContainerProvider
7
8
Factory class for creating MySQL containers through the provider pattern, enabling integration with Testcontainers JDBC URL functionality.
9
10
```java { .api }
11
/**
12
* Factory for MySQL containers implementing JdbcDatabaseContainerProvider
13
*/
14
public class MySQLContainerProvider extends JdbcDatabaseContainerProvider {
15
16
/**
17
* Checks if this provider supports the given database type
18
* @param databaseType Database type identifier (e.g., "mysql")
19
* @return true if databaseType equals "mysql", false otherwise
20
*/
21
public boolean supports(String databaseType);
22
23
/**
24
* Creates a new MySQL container instance with default configuration
25
* Uses default MySQL image tag and standard settings
26
* @return New MySQLContainer instance with default settings
27
*/
28
public JdbcDatabaseContainer newInstance();
29
30
/**
31
* Creates a new MySQL container instance with specified image tag
32
* @param tag MySQL Docker image tag (e.g., "8.0", "5.7")
33
* @return New MySQLContainer instance with specified tag
34
*/
35
public JdbcDatabaseContainer newInstance(String tag);
36
37
/**
38
* Creates a new MySQL container instance from a Testcontainers connection URL
39
* Parses the connection URL to extract configuration parameters
40
* @param connectionUrl Testcontainers connection URL with parameters
41
* @return New MySQLContainer instance configured from the URL
42
*/
43
public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl);
44
}
45
```
46
47
### Provider Registration and Discovery
48
49
The MySQLContainerProvider is automatically registered with the Testcontainers framework through Java's ServiceLoader mechanism, enabling automatic discovery and usage.
50
51
**Usage Examples:**
52
53
```java
54
// Direct provider usage
55
MySQLContainerProvider provider = new MySQLContainerProvider();
56
57
// Check if provider supports MySQL
58
boolean supportsMySQL = provider.supports("mysql"); // true
59
boolean supportsPostgres = provider.supports("postgresql"); // false
60
61
// Create container with default settings
62
JdbcDatabaseContainer container = provider.newInstance();
63
64
// Create container with specific tag
65
JdbcDatabaseContainer mysql8 = provider.newInstance("8.0");
66
JdbcDatabaseContainer mysql57 = provider.newInstance("5.7");
67
68
// Start and use the container
69
mysql8.start();
70
String jdbcUrl = mysql8.getJdbcUrl();
71
```
72
73
### JDBC URL Integration
74
75
Integration with Testcontainers JDBC URL pattern for automatic container creation and management.
76
77
**JDBC URL Pattern:**
78
79
```
80
jdbc:tc:mysql:[tag]://[host]/[database][?parameters]
81
```
82
83
**URL Parameters:**
84
85
- `TC_DAEMON=true` - Keep container running after test completion
86
- `TC_REUSABLE=true` - Reuse existing container if available
87
- `user=username` - Database username
88
- `password=password` - Database password
89
90
**Usage Examples:**
91
92
```java
93
// Using Testcontainers JDBC URL directly
94
String jdbcUrl = "jdbc:tc:mysql:8.0://localhost/testdb?user=testuser&password=testpass";
95
96
Connection connection = DriverManager.getConnection(jdbcUrl);
97
// Container is automatically created, started, and configured
98
```
99
100
**Advanced JDBC URL Usage:**
101
102
```java
103
// With container reuse and daemon mode
104
String jdbcUrl = "jdbc:tc:mysql:8.0://localhost/myapp_test" +
105
"?user=appuser&password=secret" +
106
"&TC_REUSABLE=true&TC_DAEMON=true";
107
108
// Use with connection pool
109
HikariConfig config = new HikariConfig();
110
config.setJdbcUrl(jdbcUrl);
111
config.setUsername("appuser");
112
config.setPassword("secret");
113
HikariDataSource dataSource = new HikariDataSource(config);
114
```
115
116
### ConnectionUrl Parameter Extraction
117
118
The provider extracts configuration from Testcontainers ConnectionUrl objects to configure MySQL containers.
119
120
```java { .api }
121
/**
122
* Creates container from ConnectionUrl with automatic parameter extraction
123
* Supported parameters:
124
* - user: Database username
125
* - password: Database password
126
* - Database name from URL path
127
* - Image tag from URL host specification
128
*/
129
public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl);
130
```
131
132
**Parameter Extraction Logic:**
133
134
```java
135
// Example ConnectionUrl parsing
136
// URL: jdbc:tc:mysql:8.0://localhost/ecommerce?user=shop_user&password=shop_pass
137
138
// Extracted configuration:
139
// - Image: mysql:8.0
140
// - Database: ecommerce
141
// - Username: shop_user
142
// - Password: shop_pass
143
```
144
145
### Integration Examples
146
147
**Spring Boot Integration:**
148
149
```java
150
// application-test.properties
151
spring.datasource.url=jdbc:tc:mysql:8.0://localhost/testdb?user=test&password=test
152
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
153
154
// Spring will automatically create and manage the MySQL container
155
@SpringBootTest
156
class SpringIntegrationTest {
157
158
@Autowired
159
private DataSource dataSource;
160
161
@Test
162
void testDatabaseConnection() throws SQLException {
163
try (Connection conn = dataSource.getConnection()) {
164
assertTrue(conn.isValid(5));
165
}
166
}
167
}
168
```
169
170
**JUnit 5 with Provider Pattern:**
171
172
```java
173
class ProviderBasedTest {
174
175
private static MySQLContainerProvider provider;
176
private static JdbcDatabaseContainer mysql;
177
178
@BeforeAll
179
static void setup() {
180
provider = new MySQLContainerProvider();
181
mysql = provider.newInstance("8.0");
182
mysql.start();
183
}
184
185
@AfterAll
186
static void cleanup() {
187
if (mysql != null) {
188
mysql.stop();
189
}
190
}
191
192
@Test
193
void testProviderCreatedContainer() throws SQLException {
194
String jdbcUrl = mysql.getJdbcUrl();
195
assertNotNull(jdbcUrl);
196
assertTrue(jdbcUrl.contains("mysql"));
197
198
try (Connection conn = mysql.createConnection("")) {
199
assertTrue(conn.isValid(5));
200
}
201
}
202
}
203
```
204
205
**Multiple Database Versions:**
206
207
```java
208
class MultiVersionTest {
209
210
@ParameterizedTest
211
@ValueSource(strings = {"5.7", "8.0", "8.1"})
212
void testWithDifferentMySQLVersions(String version) {
213
MySQLContainerProvider provider = new MySQLContainerProvider();
214
215
try (JdbcDatabaseContainer mysql = provider.newInstance(version)) {
216
mysql.start();
217
218
// Test MySQL version-specific features
219
try (Connection conn = mysql.createConnection("")) {
220
DatabaseMetaData metaData = conn.getMetaData();
221
String dbVersion = metaData.getDatabaseProductVersion();
222
assertTrue(dbVersion.startsWith(version));
223
}
224
}
225
}
226
}
227
```
228
229
### Provider Constants and Configuration
230
231
```java { .api }
232
// Internal provider constants
233
private static final String USER_PARAM = "user";
234
private static final String PASSWORD_PARAM = "password";
235
236
// Default behavior
237
// - Uses MySQLContainer.DEFAULT_TAG for default instances
238
// - Uses MySQLContainer.IMAGE for base image name
239
// - Supports MySQLContainer.NAME ("mysql") as database type identifier
240
```
241
242
**Provider Behavior:**
243
244
1. **Database Type Support**: Only responds to "mysql" database type
245
2. **Default Configuration**: Uses deprecated DEFAULT_TAG for backward compatibility
246
3. **Parameter Extraction**: Automatically extracts user/password from connection URLs
247
4. **Container Creation**: Always returns MySQLContainer instances cast to JdbcDatabaseContainer
248
249
### Error Handling
250
251
**Provider Validation:**
252
253
```java
254
MySQLContainerProvider provider = new MySQLContainerProvider();
255
256
// Unsupported database type
257
boolean supported = provider.supports("postgresql"); // false
258
259
// Null tag handling
260
JdbcDatabaseContainer container = provider.newInstance(null); // Falls back to default
261
262
// Invalid connection URL handling
263
try {
264
ConnectionUrl invalidUrl = /* malformed URL */;
265
JdbcDatabaseContainer container = provider.newInstance(invalidUrl);
266
} catch (Exception e) {
267
// Handle URL parsing errors
268
}
269
```
270
271
**JDBC URL Error Handling:**
272
273
```java
274
try {
275
String invalidUrl = "jdbc:tc:mysql:invalid-tag://localhost/db";
276
Connection conn = DriverManager.getConnection(invalidUrl);
277
} catch (SQLException e) {
278
// Handle container creation or connection failures
279
System.err.println("Failed to create MySQL container: " + e.getMessage());
280
}
281
```
282
283
### Best Practices
284
285
**Provider Usage Patterns:**
286
287
```java
288
// Prefer direct MySQLContainer creation for complex configurations
289
MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0")
290
.withDatabaseName("complex_app")
291
.withConfigurationOverride("custom-mysql.cnf")
292
.withInitScript("complex-schema.sql");
293
294
// Use provider pattern for simple, URL-driven configurations
295
String simpleUrl = "jdbc:tc:mysql:8.0://localhost/simple_db?user=test&password=test";
296
Connection conn = DriverManager.getConnection(simpleUrl);
297
298
// Use provider for multiple similar containers
299
MySQLContainerProvider provider = new MySQLContainerProvider();
300
List<JdbcDatabaseContainer> containers = Arrays.asList("5.7", "8.0", "8.1")
301
.stream()
302
.map(provider::newInstance)
303
.collect(Collectors.toList());
304
```
305
306
**Integration Considerations:**
307
308
- Provider pattern is ideal for framework integration (Spring, etc.)
309
- Direct container creation offers more configuration flexibility
310
- JDBC URL pattern provides the simplest setup for basic use cases
311
- Container reuse and daemon modes are valuable for development environments