Skip to content

Commit

Permalink
Add DB2 module (#1611)
Browse files Browse the repository at this point in the history
* Add db2 jdbc module

* Update Db2Container to use ibmcom/db2 image

* Add doc page on DB2 module

* Resolve review comments
  • Loading branch information
aguibert authored and bsideup committed Jul 16, 2019
1 parent fb1e91c commit 3dc9d9d
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 2 deletions.
47 changes: 47 additions & 0 deletions docs/modules/databases/db2.md
@@ -0,0 +1,47 @@
# DB2 Module

See [Database containers](./index.md) for documentation and usage that is common to all relational database container types.

## Usage example

Running DB2 as a stand-in for in a test:

```java
public class SomeTest {

@ClassRule
public Db2Container db2 = new Db2Container()
.acceptLicense();

@Test
public void someTestMethod() {
String url = db2.getJdbcUrl();

... create a connection and run test as normal
}
```

!!! warning "EULA Acceptance"
Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the DB2 image EULA, call the `acceptLicense()` method, or place a file at the root of the classpath named `container-license-acceptance.txt`, e.g. at `src/test/resources/container-license-acceptance.txt`. This file should contain the line: `ibmcom/db2:11.5.0.0a` (or, if you are overriding the docker image name/tag, update accordingly).

Please see the [`ibmcom/db2` image documentation](https://hub.docker.com/r/ibmcom/db2) for a link to the EULA document.

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

```groovy tab='Gradle'
testCompile "org.testcontainers:db2:{{latest_version}}"
```
```xml tab='Maven'
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```
!!! hint
Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency.
5 changes: 5 additions & 0 deletions modules/db2/build.gradle
@@ -0,0 +1,5 @@
description = "Testcontainers :: JDBC :: DB2"

dependencies {
compile project(':jdbc')
}
@@ -0,0 +1,129 @@
package org.testcontainers.containers;

import com.github.dockerjava.api.command.InspectContainerResponse;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.output.WaitingConsumer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.utility.LicenseAcceptance;
import org.testcontainers.utility.LogUtils;

import java.io.IOException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;

public class Db2Container extends JdbcDatabaseContainer<Db2Container> {

public static final String NAME = "db2";
public static final String DEFAULT_DB2_IMAGE_NAME = "ibmcom/db2";
public static final String DEFAULT_TAG = "11.5.0.0a";
public static final int DB2_PORT = 50000;

private String databaseName = "test";
private String username = "db2inst1";
private String password = "foobar1234";

public Db2Container() {
this(DEFAULT_DB2_IMAGE_NAME + ":" + DEFAULT_TAG);
}

public Db2Container(String imageName) {
super(imageName);
withPrivilegedMode(true);
this.waitStrategy = new LogMessageWaitStrategy()
.withRegEx(".*Setup has completed\\..*")
.withStartupTimeout(Duration.of(3, ChronoUnit.MINUTES));
}

@Override
protected Set<Integer> getLivenessCheckPorts() {
return new HashSet<>(getMappedPort(DB2_PORT));
}

@Override
protected void configure() {
// If license was not accepted programatically, check if it was accepted via resource file
if (!getEnvMap().containsKey("LICENSE")) {
LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName());
acceptLicense();
}

addExposedPort(DB2_PORT);

addEnv("DBNAME", databaseName);
addEnv("DB2INSTANCE", username);
addEnv("DB2INST1_PASSWORD", password);

// These settings help the DB2 container start faster
if (!getEnvMap().containsKey("AUTOCONFIG"))
addEnv("AUTOCONFIG", "false");
if (!getEnvMap().containsKey("ARCHIVE_LOGS"))
addEnv("ARCHIVE_LOGS", "false");
}

/**
* Accepts the license for the DB2 container by setting the LICENSE=accept
* variable as described at <a href="https://hub.docker.com/r/ibmcom/db2">https://hub.docker.com/r/ibmcom/db2</a>
*/
public Db2Container acceptLicense() {
addEnv("LICENSE", "accept");
return this;
}

@Override
public String getDriverClassName() {
return "com.ibm.db2.jcc.DB2Driver";
}

@Override
public String getJdbcUrl() {
return "jdbc:db2://" + getContainerIpAddress() + ":" + getMappedPort(DB2_PORT) + "/" + databaseName;
}

@Override
public String getUsername() {
return username;
}

@Override
public String getPassword() {
return password;
}

@Override
public String getDatabaseName() {
return databaseName;
}

@Override
public Db2Container withUsername(String username) {
this.username = username;
return this;
}

@Override
public Db2Container withPassword(String password) {
this.password = password;
return this;
}

@Override
public Db2Container withDatabaseName(String dbName) {
this.databaseName = dbName;
return this;
}

@Override
protected void waitUntilContainerStarted() {
getWaitStrategy().waitUntilReady(this);
}

@Override
protected String getTestQueryString() {
return "SELECT 1 FROM SYSIBM.SYSDUMMY1";
}
}
@@ -0,0 +1,18 @@
package org.testcontainers.containers;

public class Db2ContainerProvider extends JdbcDatabaseContainerProvider {
@Override
public boolean supports(String databaseType) {
return databaseType.equals(Db2Container.NAME);
}

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

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new Db2Container(Db2Container.DEFAULT_DB2_IMAGE_NAME + ":" + tag);
}
}
@@ -0,0 +1 @@
org.testcontainers.containers.Db2ContainerProvider
2 changes: 2 additions & 0 deletions modules/jdbc-test/build.gradle
Expand Up @@ -11,6 +11,7 @@ dependencies {
compile project(':oracle-xe')
compile project(':mssqlserver')
compile project(':clickhouse')
compile project(':db2')

testCompile 'com.google.guava:guava:18.0'
testCompile 'org.postgresql:postgresql:42.0.0'
Expand All @@ -19,6 +20,7 @@ dependencies {
testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted'
testCompile 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8'
testCompile 'ru.yandex.clickhouse:clickhouse-jdbc:0.1.41'
testCompile 'com.ibm.db2:jcc:11.1.4.4'

testCompile 'com.zaxxer:HikariCP-java6:2.3.8'
testCompile 'org.apache.tomcat:tomcat-jdbc:8.5.4'
Expand Down
Expand Up @@ -65,6 +65,7 @@ public static Iterable<Object[]> data() {
{"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:db2://hostname/databasename", EnumSet.noneOf(Options.class)},
});
}

Expand Down Expand Up @@ -109,7 +110,12 @@ public void test() throws SQLException {
}

private void performSimpleTest(HikariDataSource dataSource) throws SQLException {
boolean result = new QueryRunner(dataSource, options.contains(Options.PmdKnownBroken)).query("SELECT 1", rs -> {
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);
Expand Down
@@ -0,0 +1,39 @@
package org.testcontainers.junit;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Rule;
import org.junit.Test;
import org.testcontainers.containers.Db2Container;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;


public class SimpleDb2Test {

@Rule
public Db2Container db2 = new Db2Container()
.acceptLicense();

@Test
public void testSimple() throws SQLException {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(db2.getJdbcUrl());
hikariConfig.setUsername(db2.getUsername());
hikariConfig.setPassword(db2.getPassword());

HikariDataSource ds = new HikariDataSource(hikariConfig);
Statement statement = ds.getConnection().createStatement();
statement.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1");
ResultSet resultSet = statement.getResultSet();

resultSet.next();
int resultSetInt = resultSet.getInt(1);
assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
}

}
@@ -1 +1,2 @@
mcr.microsoft.com/mssql/server:2017-CU12
ibmcom/db2:11.5.0.0a
Expand Up @@ -203,7 +203,7 @@ public Map<String, String> getTmpfsOptions() {
* @author manikmagar
*/
public interface Patterns {
Pattern URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z]+)(:([^:]+))?://([^\\?]+)(\\?.*)?");
Pattern URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z0-9]+)(:([^:]+))?://([^\\?]+)(\\?.*)?");

Pattern ORACLE_URL_MATCHING_PATTERN = Pattern.compile("jdbc:tc:([a-z]+)(:([^(thin:)]+))?:thin:@([^\\?]+)(\\?.*)?");

Expand Down

0 comments on commit 3dc9d9d

Please sign in to comment.