Skip to content

Commit

Permalink
Pin tags (#671)
Browse files Browse the repository at this point in the history
* Pin tags where it makes sense to do so
* Update changelog and docs
* Use fixed tag names for JDBC URLs when none specified
(equivalent to current 'latest')
  • Loading branch information
rnorth authored and bsideup committed Apr 29, 2018
1 parent 3c90b18 commit 07ff2a3
Show file tree
Hide file tree
Showing 19 changed files with 85 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- Retry any exceptions (not just `DockerClientException`) on image pull ([\#662](https://github.com/testcontainers/testcontainers-java/issues/662))

### Changed
- Database container images are now pinned to a specific version rather than using `latest`. The tags selected are the most recent as of the time of this change. If a JDBC URL is used with no tag specified, a WARN level log message is output, pending a future change to make tags mandatory in the JDBC URL. ([\#671](https://github.com/testcontainers/testcontainers-java/issues/671))

## [1.7.1] - 2018-04-20

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/
public abstract class AbstractWaitStrategyTest<W extends WaitStrategy> {
static final long WAIT_TIMEOUT_MILLIS = 3000;
static final String IMAGE_NAME = "alpine:latest";
static final String IMAGE_NAME = "alpine:3.7";

/**
* Indicates that the WaitStrategy has completed waiting successfully.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
public class HostPortWaitStrategyTest {

private static final String IMAGE_NAME = "alpine:latest";
private static final String IMAGE_NAME = "alpine:3.7";

@ClassRule
public static GenericContainer container = new GenericContainer(IMAGE_NAME).withExposedPorts()
Expand Down
23 changes: 7 additions & 16 deletions docs/usage/database_containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,40 +53,40 @@ _N.B:_
* _TC needs to be on your application's classpath at runtime for this to work_
* _For Spring Boot you need to specify the driver manually `spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver`_

**Original URL**: `jdbc:mysql://somehostname:someport/databasename`
**Original URL**: `jdbc:mysql:5.7.22://somehostname:someport/databasename`

Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value.

### JDBC URL examples

#### Simple Testcontainers JDBC driver usage
#### DEPRECATED: Simple Testcontainers JDBC driver usage

`jdbc:tc:mysql://somehostname:someport/databasename`

*(Note: this will use the latest version of MySQL)*
*(Note: this will use a fixed version of the database. You should typically specify the version you desire via a tag parameter, as below).*

#### Using Testcontainers with a fixed version

`jdbc:tc:mysql:5.6.23://somehostname:someport/databasename`

#### Using PostgreSQL

`jdbc:tc:postgresql://hostname/databasename`
`jdbc:tc:postgresql:9.6.8://hostname/databasename`


## Using an init script

Testcontainers can run an initscript after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows:

`jdbc:tc:mysql://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql`
`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql`

This is useful if you have a fixed script for setting up database schema, etc.

#### Using an init function

Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method:

`jdbc:tc:mysql://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction`
`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction`

The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g.
```java
Expand All @@ -101,7 +101,7 @@ public class JDBCDriverTest {

By default database container is being stopped as soon as last connection is closed. There are cases when you might need to start container and keep it running till you stop it explicitly or JVM is shutdown. To do this, add `TC_DAEMON` parameter to the URL as follows:

`jdbc:tc:mysql://hostname/databasename?TC_DAEMON=true`
`jdbc:tc:mysql:5.7.22://hostname/databasename?TC_DAEMON=true`

With this parameter database container will keep running even when there're no open connections.
Expand All @@ -114,12 +114,3 @@ is a directory on the classpath containing .cnf files, the following URL can be
Any .cnf files in this classpath directory will be mapped into the database container's /etc/mysql/conf.d directory,
and will be able to override server settings when the container starts.

### Additional Non-standard Methods

#### Virtuoso SPARQL Service URL

VirtuosoContainer provides access to the SPARQL service URL
```java
String sparqlServiceUrl = ((VirtuosoContainer)container).getSparqlUrl();
```
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static void testCleanup() {

@Test
public void shouldStopContainerWhenAllConnectionsClosed() throws SQLException {
final String jdbcUrl = "jdbc:tc:postgresql://hostname/databasename";
final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename";

getConnectionAndClose(jdbcUrl);

Expand All @@ -33,7 +33,7 @@ public void shouldStopContainerWhenAllConnectionsClosed() throws SQLException {

@Test
public void shouldNotStopDaemonContainerWhenAllConnectionsClosed() throws SQLException {
final String jdbcUrl = "jdbc:tc:postgresql://hostname/databasename?TC_DAEMON=true";
final String jdbcUrl = "jdbc:tc:postgresql:9.6.8://hostname/databasename?TC_DAEMON=true";

getConnectionAndClose(jdbcUrl);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ public class JDBCDriverTest {
public static Iterable<Object[]> data() {
return asList(
new Object[][]{
{"jdbc:tc:mysql:5.5.43://hostname/databasename", false, false, false},
{"jdbc:tc:mysql://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql", true, false, false},
{"jdbc:tc:mysql://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
{"jdbc:tc:mysql://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
{"jdbc:tc:mysql://hostname/databasename", false, false, false},
{"jdbc:tc:mysql://hostname/databasename?useSSL=false", false, false, false},
{"jdbc:tc:postgresql://hostname/databasename", false, false, false},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql", true, false, false},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
{"jdbc:tc:mysql:5.5.43://hostname/databasename", false, false, false},
{"jdbc:tc:mysql:5.5.43://hostname/databasename?useSSL=false", false, false, false},
{"jdbc:tc:postgresql:9.6.8://hostname/databasename", false, false, false},
{"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", false, false, true},
{"jdbc:tc:mariadb:10.1.16://hostname/databasename", false, false, false},
{"jdbc:tc:mariadb://hostname/databasename", false, false, false},
{"jdbc:tc:mariadb://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
{"jdbc:tc:mariadb://hostname/databasename?TC_INITSCRIPT=somepath/init_mariadb.sql", true, false, false},
{"jdbc:tc:mariadb://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
{"jdbc:tc:mariadb:10.1.16://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", false, false, true}
{"jdbc:tc:mariadb:10.2.14://hostname/databasename", false, false, false},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?useUnicode=yes&characterEncoding=utf8", false, true, false},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITSCRIPT=somepath/init_mariadb.sql", true, false, false},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction", true, false, false},
{"jdbc:tc:mariadb:10.2.14://hostname/databasename?TC_MY_CNF=somepath/mariadb_conf_override", false, false, true}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CustomizablePostgreSQLTest {
private static final String PWD = "baz";

@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:latest")
public PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName(DB_NAME)
.withUsername(USER)
.withPassword(PWD);
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
microsoft/mssql-server-linux:latest
microsoft/mssql-server-linux:2017-CU6
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package org.testcontainers.containers;

import lombok.extern.slf4j.Slf4j;

/**
* Base class for classes that can provide a JDBC container.
*/
@Slf4j
public abstract class JdbcDatabaseContainerProvider {

public abstract boolean supports(String databaseType);

public JdbcDatabaseContainer newInstance() {
log.warn("No explicit version tag was provided in JDBC URL and this class ({}) does not " +
"override newInstance() to set a default tag. `latest` will be used but results may " +
"be unreliable!", this.getClass().getCanonicalName());
return this.newInstance("latest");
}

public abstract JdbcDatabaseContainer newInstance(String tag);
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,6 @@ public synchronized Connection connect(String url, final Properties info) throws
}
String databaseType = urlMatcher.group(1);
String tag = urlMatcher.group(3);
if (tag == null) {
tag = "latest";
}

queryString = urlMatcher.group(4);
if (queryString == null) {
Expand All @@ -119,7 +116,12 @@ public synchronized Connection connect(String url, final Properties info) throws
ServiceLoader<JdbcDatabaseContainerProvider> databaseContainers = ServiceLoader.load(JdbcDatabaseContainerProvider.class);
for (JdbcDatabaseContainerProvider candidateContainerType : databaseContainers) {
if (candidateContainerType.supports(databaseType)) {
container = candidateContainerType.newInstance(tag);

if (tag != null) {
container = candidateContainerType.newInstance(tag);
} else {
container = candidateContainerType.newInstance();
}
delegate = container.getJdbcDriverInstance();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@

/**
* Container implementation for the MariaDB project.
*
*
* @author Miguel Gonzalez Sanchez
*/
public class MariaDBContainer<SELF extends MariaDBContainer<SELF>> extends JdbcDatabaseContainer<SELF> {

public static final String NAME = "mariadb";
public static final String IMAGE = "mariadb";
public static final String DEFAULT_TAG = "10.3.6";

private static final Integer MARIADB_PORT = 3306;
private static final String MARIADB_USER = "test";
private static final String MARIADB_PASSWORD = "test";
private static final String MARIADB_DATABASE = "test";
private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF";

public MariaDBContainer() {
super(IMAGE + ":latest");
super(IMAGE + ":" + DEFAULT_TAG);
}

public MariaDBContainer(String dockerImageName) {
Expand All @@ -31,7 +33,7 @@ protected Integer getLivenessCheckPort() {
@Override
protected void configure() {
optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", "mariadb-default-conf");

addExposedPort(MARIADB_PORT);
addEnv("MYSQL_DATABASE", MARIADB_DATABASE);
addEnv("MYSQL_USER", MARIADB_USER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public boolean supports(String databaseType) {
return databaseType.equals(MariaDBContainer.NAME);
}

@Override
public JdbcDatabaseContainer newInstance() {
return newInstance(MariaDBContainer.DEFAULT_TAG);
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new MariaDBContainer(MariaDBContainer.IMAGE + ":" + tag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
* @author Stefan Hufschmidt
*/
public class MSSQLServerContainer<SELF extends MSSQLServerContainer<SELF>> extends JdbcDatabaseContainer<SELF> {
static final String NAME = "mssqlserver";
static final String IMAGE = "microsoft/mssql-server-linux";
public static final String NAME = "mssqlserver";
public static final String IMAGE = "microsoft/mssql-server-linux";
public static final String DEFAULT_TAG = "2017-CU6";

public static final Integer MS_SQL_SERVER_PORT = 1433;
private String username = "SA";
private String password = "A_Str0ng_Required_Password";

public MSSQLServerContainer() {
this(IMAGE + ":latest");
this(IMAGE + ":" + DEFAULT_TAG);
}

public MSSQLServerContainer(final String dockerImageName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public boolean supports(String databaseType) {
return databaseType.equals(MSSQLServerContainer.NAME);
}

@Override
public JdbcDatabaseContainer newInstance() {
return newInstance(MSSQLServerContainer.DEFAULT_TAG);
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new MSSQLServerContainer(MSSQLServerContainer.IMAGE + ":" + tag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ public class MySQLContainer<SELF extends MySQLContainer<SELF>> extends JdbcDatab

public static final String NAME = "mysql";
public static final String IMAGE = "mysql";
public static final String DEFAULT_TAG = "5.7.22";

private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF";
public static final Integer MYSQL_PORT = 3306;
private String databaseName = "test";
private String username = "test";
private String password = "test";

public MySQLContainer() {
super(IMAGE + ":latest");
super(IMAGE + ":" + DEFAULT_TAG);
}

public MySQLContainer(String dockerImageName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public boolean supports(String databaseType) {
return databaseType.equals(MySQLContainer.NAME);
}

@Override
public JdbcDatabaseContainer newInstance() {
return newInstance(MySQLContainer.DEFAULT_TAG);
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new MySQLContainer(MySQLContainer.IMAGE + ":" + tag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ public boolean supports(String databaseType) {
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
public JdbcDatabaseContainer newInstance() {
return new OracleContainer();
}

if (!tag.equalsIgnoreCase("latest")) {
@Override
public JdbcDatabaseContainer newInstance(String tag) {
if (tag != null) {
throw new UnsupportedOperationException("Oracle database tag should be set in the configured image name");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
* @author richardnorth
*/
public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>> extends JdbcDatabaseContainer<SELF> {
static final String NAME = "postgresql";
static final String IMAGE = "postgres";
public static final String NAME = "postgresql";
public static final String IMAGE = "postgres";
public static final String DEFAULT_TAG = "9.6.8";

public static final Integer POSTGRESQL_PORT = 5432;
private String databaseName = "test";
private String username = "test";
private String password = "test";

public PostgreSQLContainer() {
this(IMAGE + ":latest");
this(IMAGE + ":" + DEFAULT_TAG);
}

public PostgreSQLContainer(final String dockerImageName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public boolean supports(String databaseType) {
return databaseType.equals(PostgreSQLContainer.NAME);
}

@Override
public JdbcDatabaseContainer newInstance() {
return newInstance(PostgreSQLContainer.DEFAULT_TAG);
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new PostgreSQLContainer(PostgreSQLContainer.IMAGE + ":" + tag);
Expand Down

0 comments on commit 07ff2a3

Please sign in to comment.