Skip to content

Commit

Permalink
Add DB2 support for Docker Compose
Browse files Browse the repository at this point in the history
  • Loading branch information
quaff authored and wilkinsona committed Oct 10, 2024
1 parent d815cad commit da05e9e
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies {
dockerTestImplementation("org.junit.jupiter:junit-jupiter")
dockerTestImplementation("org.testcontainers:testcontainers")

dockerTestRuntimeOnly("com.ibm.db2:jcc")
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc")
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.docker.compose.service.connection.db2;

import java.sql.Driver;

import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.util.ClassUtils;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Integration tests for {@link Db2JdbcDockerComposeConnectionDetailsFactory}.
*
* @author Yanming Zhou
*/
class Db2JdbcDockerComposeConnectionDetailsFactoryIntegrationTests {

@DockerComposeTest(composeFile = "db2-compose.yaml", image = TestImage.DB2)
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws Exception {
assertConnectionDetails(connectionDetails);
checkDatabaseAccess(connectionDetails);
}

private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("db2inst1");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:db2://").endsWith("/testdb");
}

@SuppressWarnings("unchecked")
private void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setUrl(connectionDetails.getJdbcUrl());
dataSource.setUsername(connectionDetails.getUsername());
dataSource.setPassword(connectionDetails.getPassword());
dataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),
getClass().getClassLoader()));
JdbcTemplate template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject(DatabaseDriver.DB2.getValidationQuery(), Integer.class)).isEqualTo(1);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
services:
database:
image: '{imageName}'
ports:
- '50000'
privileged: true
environment:
- 'LICENSE=accept'
- 'DB2INSTANCE=db2inst1'
- 'DB2INST1_PASSWORD=secret'
- 'DBNAME=testdb'
- 'AUTOCONFIG=false'
- 'ARCHIVE_LOGS=false'
healthcheck:
test: 'su - db2inst1 -c "db2 connect to testdb user db2inst1 using secret"'
start_period: 90s
labels:
org.springframework.boot.readiness-check.tcp.disable: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.docker.compose.service.connection.db2;

import java.util.Map;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
* DB2 environment details.
*
* @author Yanming Zhou
*/
class Db2Environment {

private final String username;

private final String password;

private final String database;

Db2Environment(Map<String, String> env) {
this.username = env.getOrDefault("DB2INSTANCE", "db2inst1");
this.password = env.get("DB2INST1_PASSWORD");
Assert.state(StringUtils.hasLength(this.password), "DB2 password must be provided");
this.database = env.get("DBNAME");
Assert.state(StringUtils.hasLength(this.database), "DB2 database must be provided");
}

String getUsername() {
return this.username;
}

String getPassword() {
return this.password;
}

String getDatabase() {
return this.database;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.docker.compose.service.connection.db2;

import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
import org.springframework.boot.docker.compose.service.connection.jdbc.JdbcUrlBuilder;

/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code db2} service.
*
* @author Yanming Zhou
*/
class Db2JdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {

private static final String[] DB2_CONTAINER_NAMES = { "ibmcom/db2", "db2_community/db2" };

protected Db2JdbcDockerComposeConnectionDetailsFactory() {
super(DB2_CONTAINER_NAMES);
}

@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new Db2JdbcDockerComposeConnectionDetails(source.getRunningService());
}

/**
* {@link JdbcConnectionDetails} backed by a {@code db2} {@link RunningService}.
*/
static class Db2JdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {

private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("db2", 50000);

private final Db2Environment environment;

private final String jdbcUrl;

Db2JdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new Db2Environment(service.env());
this.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());
}

@Override
public String getUsername() {
return this.environment.getUsername();
}

@Override
public String getPassword() {
return this.environment.getPassword();
}

@Override
public String getJdbcUrl() {
return this.jdbcUrl;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Auto-configuration for Docker Compose DB2 service connections.
*/
package org.springframework.boot.docker.compose.service.connection.db2;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ org.springframework.boot.docker.compose.service.connection.activemq.ActiveMQClas
org.springframework.boot.docker.compose.service.connection.activemq.ActiveMQDockerComposeConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.activemq.ArtemisDockerComposeConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.cassandra.CassandraDockerComposeConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.db2.Db2JdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.elasticsearch.ElasticsearchDockerComposeConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.flyway.JdbcAdaptingFlywayConnectionDetailsFactory,\
org.springframework.boot.docker.compose.service.connection.hazelcast.HazelcastDockerComposeConnectionDetailsFactory,\
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.docker.compose.service.connection.db2;

import java.util.Collections;
import java.util.Map;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link Db2Environment}.
*
* @author Yanming Zhou
*/
class Db2EnvironmentTests {

@Test
void createWhenNoDb2InstancePasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new Db2Environment(Collections.emptyMap()))
.withMessage("DB2 password must be provided");
}

@Test
void createWhenNoDb2InstanceDatabaseThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret")))
.withMessage("DB2 database must be provided");
}

@Test
void getUsernameWhenNoDb2Instance() {
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
assertThat(environment.getUsername()).isEqualTo("db2inst1");
}

@Test
void getUsernameWhenHasDb2Instance() {
Db2Environment environment = new Db2Environment(
Map.of("DB2INSTANCE", "db2inst2", "DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
assertThat(environment.getUsername()).isEqualTo("db2inst2");
}

@Test
void getPasswordWhenHasDb2InstancePassword() {
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
assertThat(environment.getPassword()).isEqualTo("secret");
}

@Test
void getDatabaseWhenHasDbName() {
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
assertThat(environment.getDatabase()).isEqualTo("testdb");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ The following service connections are currently supported:
| Containers named "hazelcast/hazelcast".

| `JdbcConnectionDetails`
| Containers named "gvenzl/oracle-free", "gvenzl/oracle-xe", "mariadb", "bitnami/mariadb", "mssql/server", "mysql", "bitnami/mysql", "postgres", or "bitnami/postgresql"
| Containers named "gvenzl/oracle-free", "gvenzl/oracle-xe", "db2_community/db2", "ibmcom/db2", "mariadb", "bitnami/mariadb", "mssql/server", "mysql", "bitnami/mysql", "postgres", or "bitnami/postgresql"

| `LdapConnectionDetails`
| Containers named "osixia/openldap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
optional("org.testcontainers:activemq")
optional("org.testcontainers:cassandra")
optional("org.testcontainers:couchbase")
optional("org.testcontainers:db2")
optional("org.testcontainers:elasticsearch")
optional("org.testcontainers:grafana")
optional("org.testcontainers:junit-jupiter")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.testcontainers.activemq.ArtemisContainer;
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.Db2Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.containers.MongoDBContainer;
Expand All @@ -54,6 +55,7 @@
* @author Moritz Halbritter
* @author Chris Bono
* @author Phillip Webb
* @author Yanming Zhou
*/
public enum TestImage {

Expand Down Expand Up @@ -90,6 +92,12 @@ public enum TestImage {
(container) -> ((CouchbaseContainer) container).withStartupAttempts(5)
.withStartupTimeout(Duration.ofMinutes(10))),

/**
* A container image suitable for testing DB2.
*/
DB2("icr.io/db2_community/db2", "11.5.8.0", () -> Db2Container.class,
(container) -> ((Db2Container) container).withStartupTimeout(Duration.ofMinutes(10))),

/**
* A container image suitable for testing Elasticsearch 7.
*/
Expand Down

0 comments on commit da05e9e

Please sign in to comment.